vanikam/src/ordering/application/services/add_line_item_service.rs

113 lines
3.5 KiB
Rust

// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
//
// 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<LineItemAddedEvent>;
}
pub type AddLineItemServiceObj = Arc<dyn AddLineItemUseCase>;
#[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<LineItemAddedEvent> {
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<usize>,
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());
}
}