// SPDX-FileCopyrightText: 2024 Aravinth Manivannan // // SPDX-License-Identifier: AGPL-3.0-or-later use std::sync::Arc; use derive_builder::Builder; use mockall::predicate::*; use mockall::*; use time::OffsetDateTime; use super::errors::*; use crate::ordering::{ application::port::output::db::line_item_id_exists::*, domain::{add_line_item_command::*, line_item_added_event::*, line_item_aggregate::*}, }; use crate::utils::uuid::*; #[automock] #[async_trait::async_trait] pub trait AddLineItemUseCase: Send + Sync { async fn add_line_item(&self, cmd: AddLineItemCommand) -> OrderingResult; } pub type AddLineItemServiceObj = Arc; #[derive(Clone, Builder)] pub struct AddLineItemService { db_line_item_id_exists: LineItemIDExistsDBPortObj, get_uuid: GetUUIDInterfaceObj, } #[async_trait::async_trait] impl AddLineItemUseCase for AddLineItemService { async fn add_line_item(&self, cmd: AddLineItemCommand) -> OrderingResult { let mut line_item_id = self.get_uuid.get_uuid(); loop { if self .db_line_item_id_exists .line_item_id_exists(&line_item_id) .await? { line_item_id = self.get_uuid.get_uuid(); continue; } else { break; } } let line_item = LineItemBuilder::default() .sale_time(OffsetDateTime::now_utc()) .product_name(cmd.product_name().into()) .product_id(*cmd.product_id()) .line_item_id(line_item_id) .quantity(cmd.quantity().clone()) .deleted(false) .build() .unwrap(); Ok(LineItemAddedEventBuilder::default() .added_by_user(*cmd.adding_by()) .line_item(line_item) .build() .unwrap()) } } #[cfg(test)] pub mod tests { use super::*; use crate::ordering::domain::line_item_added_event::tests::get_added_line_item_event_from_command; use crate::utils::uuid::tests::UUID; use crate::{tests::bdd::*, utils::uuid::tests::mock_get_uuid}; pub fn mock_add_line_item_service( times: Option, cmd: AddLineItemCommand, ) -> AddLineItemServiceObj { let mut m = MockAddLineItemUseCase::new(); let res = get_added_line_item_event_from_command(&cmd); if let Some(times) = times { m.expect_add_line_item() .times(times) .returning(move |_| Ok(res.clone())); } else { m.expect_add_line_item().returning(move |_| Ok(res.clone())); } Arc::new(m) } #[actix_rt::test] async fn test_service() { let cmd = AddLineItemCommand::get_cmd(); let s = AddLineItemServiceBuilder::default() .db_line_item_id_exists(mock_line_item_id_exists_db_port_false(IS_CALLED_ONLY_ONCE)) .get_uuid(mock_get_uuid(IS_CALLED_ONLY_ONCE)) .build() .unwrap(); let res = s.add_line_item(cmd.clone()).await.unwrap(); assert_eq!(res.line_item().product_name(), cmd.product_name()); assert_eq!(res.line_item().product_id(), cmd.product_id()); assert_eq!(res.line_item().quantity(), cmd.quantity()); assert_eq!(res.line_item().quantity(), cmd.quantity()); assert!(!res.line_item().deleted()); assert_eq!(res.added_by_user(), cmd.adding_by()); } }