feat: add line item service

This commit is contained in:
Aravinth Manivannan 2024-07-23 17:41:40 +05:30
parent 66101f0aeb
commit 36432bcd83
Signed by: realaravinth
GPG key ID: F8F50389936984FF
3 changed files with 168 additions and 0 deletions

View file

@ -0,0 +1,113 @@
// 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());
}
}

View file

@ -0,0 +1,30 @@
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
use derive_more::{Display, Error};
use log::error;
use serde::{Deserialize, Serialize};
use crate::ordering::application::port::output::db::errors::OrderingDBError;
pub type OrderingResult<V> = Result<V, OrderingError>;
#[derive(Debug, Error, Display, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
pub enum OrderingError {
LineItemIDNotFound,
InternalError,
}
//
impl From<OrderingDBError> for OrderingError {
fn from(value: OrderingDBError) -> Self {
match value {
OrderingDBError::DuplicateLineItemID => {
error!("DuplicateLineItemID");
Self::InternalError
}
OrderingDBError::LineItemIDNotFound => OrderingError::LineItemIDNotFound,
OrderingDBError::InternalError => Self::InternalError,
}
}
}

View file

@ -1,3 +1,28 @@
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
use derive_builder::Builder;
use mockall::predicate::*;
use mockall::*;
pub mod errors;
//services
pub mod add_line_item_service;
#[automock]
pub trait OrderingServicesInterface: Send + Sync {
fn add_line_item(&self) -> add_line_item_service::AddLineItemServiceObj;
}
#[derive(Clone, Builder)]
pub struct OrderingServices {
add_line_item: add_line_item_service::AddLineItemServiceObj,
}
impl OrderingServicesInterface for OrderingServices {
fn add_line_item(&self) -> add_line_item_service::AddLineItemServiceObj {
self.add_line_item.clone()
}
}