feat: add order service #66

Merged
realaravinth merged 7 commits from add-order-service into master 2024-07-23 19:52:06 +05:30
3 changed files with 121 additions and 0 deletions
Showing only changes of commit 3a19d7099d - Show all commits

View file

@ -0,0 +1,108 @@
// 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::order_id_exists::*,
domain::{add_order_command::*, order_added_event::*, order_aggregate::*},
};
use crate::utils::uuid::*;
#[automock]
#[async_trait::async_trait]
pub trait AddOrderUseCase: Send + Sync {
async fn add_order(&self, cmd: AddOrderCommand) -> OrderingResult<OrderAddedEvent>;
}
pub type AddOrderServiceObj = Arc<dyn AddOrderUseCase>;
#[derive(Clone, Builder)]
pub struct AddOrderService {
db_order_id_exists: OrderIDExistsDBPortObj,
get_uuid: GetUUIDInterfaceObj,
}
#[async_trait::async_trait]
impl AddOrderUseCase for AddOrderService {
async fn add_order(&self, cmd: AddOrderCommand) -> OrderingResult<OrderAddedEvent> {
let mut order_id = self.get_uuid.get_uuid();
loop {
if self
.db_order_id_exists
.order_id_exists(&order_id)
.await?
{
order_id = self.get_uuid.get_uuid();
continue;
} else {
break;
}
}
let order = OrderBuilder::default()
.created_time(OffsetDateTime::now_utc())
.customer_name(cmd.customer_name().into())
.order_id(order_id)
.deleted(false)
.build()
.unwrap();
Ok(OrderAddedEventBuilder::default()
.added_by_user(*cmd.adding_by())
.order(order)
.build()
.unwrap())
}
}
#[cfg(test)]
pub mod tests {
use super::*;
use crate::ordering::domain::order_added_event::tests::get_added_order_event_from_command;
use crate::utils::uuid::tests::UUID;
use crate::{tests::bdd::*, utils::uuid::tests::mock_get_uuid};
pub fn mock_add_order_service(
times: Option<usize>,
cmd: AddOrderCommand,
) -> AddOrderServiceObj {
let mut m = MockAddOrderUseCase::new();
let res = get_added_order_event_from_command(&cmd);
if let Some(times) = times {
m.expect_add_order()
.times(times)
.returning(move |_| Ok(res.clone()));
} else {
m.expect_add_order().returning(move |_| Ok(res.clone()));
}
Arc::new(m)
}
#[actix_rt::test]
async fn test_service() {
let cmd = AddOrderCommand::get_cmd();
let s = AddOrderServiceBuilder::default()
.db_order_id_exists(mock_order_id_exists_db_port_false(IS_CALLED_ONLY_ONCE))
.get_uuid(mock_get_uuid(IS_CALLED_ONLY_ONCE))
.build()
.unwrap();
let res = s.add_order(cmd.clone()).await.unwrap();
assert_eq!(res.order().customer_name(), cmd.customer_name());
assert!(!res.order().deleted());
assert_eq!(res.added_by_user(), cmd.adding_by());
}
}

View file

@ -14,6 +14,7 @@ pub type OrderingResult<V> = Result<V, OrderingError>;
pub enum OrderingError { pub enum OrderingError {
LineItemIDNotFound, LineItemIDNotFound,
InternalError, InternalError,
OrderIDNotFound,
} }
// //
impl From<OrderingDBError> for OrderingError { impl From<OrderingDBError> for OrderingError {
@ -24,6 +25,11 @@ impl From<OrderingDBError> for OrderingError {
Self::InternalError Self::InternalError
} }
OrderingDBError::LineItemIDNotFound => OrderingError::LineItemIDNotFound, OrderingDBError::LineItemIDNotFound => OrderingError::LineItemIDNotFound,
OrderingDBError::DuplicateOrderID => {
error!("DuplicateOrderID");
Self::InternalError
}
OrderingDBError::OrderIDNotFound => OrderingError::OrderIDNotFound,
OrderingDBError::InternalError => Self::InternalError, OrderingDBError::InternalError => Self::InternalError,
} }
} }

View file

@ -12,12 +12,14 @@ pub mod errors;
pub mod add_line_item_service; pub mod add_line_item_service;
pub mod delete_line_item_service; pub mod delete_line_item_service;
pub mod update_line_item_service; pub mod update_line_item_service;
pub mod add_order_service;
#[automock] #[automock]
pub trait OrderingServicesInterface: Send + Sync { pub trait OrderingServicesInterface: Send + Sync {
fn add_line_item(&self) -> add_line_item_service::AddLineItemServiceObj; fn add_line_item(&self) -> add_line_item_service::AddLineItemServiceObj;
fn update_line_item(&self) -> update_line_item_service::UpdateLineItemServiceObj; fn update_line_item(&self) -> update_line_item_service::UpdateLineItemServiceObj;
fn delete_line_item(&self) -> delete_line_item_service::DeleteLineItemServiceObj; fn delete_line_item(&self) -> delete_line_item_service::DeleteLineItemServiceObj;
fn add_order(&self) -> add_order_service::AddOrderServiceObj;
} }
#[derive(Clone, Builder)] #[derive(Clone, Builder)]
@ -25,6 +27,7 @@ pub struct OrderingServices {
add_line_item: add_line_item_service::AddLineItemServiceObj, add_line_item: add_line_item_service::AddLineItemServiceObj,
update_line_item: update_line_item_service::UpdateLineItemServiceObj, update_line_item: update_line_item_service::UpdateLineItemServiceObj,
delete_line_item: delete_line_item_service::DeleteLineItemServiceObj, delete_line_item: delete_line_item_service::DeleteLineItemServiceObj,
add_order: add_order_service::AddOrderServiceObj,
} }
impl OrderingServicesInterface for OrderingServices { impl OrderingServicesInterface for OrderingServices {
@ -38,4 +41,8 @@ impl OrderingServicesInterface for OrderingServices {
fn delete_line_item(&self) -> delete_line_item_service::DeleteLineItemServiceObj { fn delete_line_item(&self) -> delete_line_item_service::DeleteLineItemServiceObj {
self.delete_line_item.clone() self.delete_line_item.clone()
} }
fn add_order(&self) -> add_order_service::AddOrderServiceObj {
self.add_order.clone()
}
} }