feat: kot add service #69

Merged
realaravinth merged 5 commits from kot-add-service into master 2024-07-23 20:48:48 +05:30
7 changed files with 248 additions and 6 deletions
Showing only changes of commit 6115a9adde - Show all commits

View file

@ -0,0 +1,129 @@
// 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::kot_id_exists::*,
application::port::output::db::order_id_exists::*,
domain::{add_kot_command::*, kot_added_event::*, kot_aggregate::*},
};
use crate::utils::uuid::*;
#[automock]
#[async_trait::async_trait]
pub trait AddKotUseCase: Send + Sync {
async fn add_kot(&self, cmd: AddKotCommand) -> OrderingResult<KotAddedEvent>;
}
pub type AddKotServiceObj = Arc<dyn AddKotUseCase>;
#[derive(Clone, Builder)]
pub struct AddKotService {
db_kot_id_exists: KotIDExistsDBPortObj,
db_order_id_exists: OrderIDExistsDBPortObj,
get_uuid: GetUUIDInterfaceObj,
}
#[async_trait::async_trait]
impl AddKotUseCase for AddKotService {
async fn add_kot(&self, cmd: AddKotCommand) -> OrderingResult<KotAddedEvent> {
if !self
.db_order_id_exists
.order_id_exists(cmd.order_id())
.await?
{
return Err(OrderingError::OrderIDNotFound);
}
let mut kot_id = self.get_uuid.get_uuid();
loop {
if self.db_kot_id_exists.kot_id_exists(&kot_id).await? {
kot_id = self.get_uuid.get_uuid();
continue;
} else {
break;
}
}
let kot = KotBuilder::default()
.created_time(OffsetDateTime::now_utc())
.order_id(*cmd.order_id())
.kot_id(kot_id)
.deleted(false)
.build()
.unwrap();
Ok(KotAddedEventBuilder::default()
.added_by_user(*cmd.adding_by())
.kot(kot)
.build()
.unwrap())
}
}
#[cfg(test)]
pub mod tests {
use super::*;
use crate::ordering::domain::kot_added_event::tests::get_added_kot_event_from_command;
use crate::utils::uuid::tests::UUID;
use crate::{tests::bdd::*, utils::uuid::tests::mock_get_uuid};
pub fn mock_add_kot_service(times: Option<usize>, cmd: AddKotCommand) -> AddKotServiceObj {
let mut m = MockAddKotUseCase::new();
let res = get_added_kot_event_from_command(&cmd);
if let Some(times) = times {
m.expect_add_kot()
.times(times)
.returning(move |_| Ok(res.clone()));
} else {
m.expect_add_kot().returning(move |_| Ok(res.clone()));
}
Arc::new(m)
}
#[actix_rt::test]
async fn test_service() {
let cmd = AddKotCommand::get_cmd();
let s = AddKotServiceBuilder::default()
.db_kot_id_exists(mock_kot_id_exists_db_port_false(IS_CALLED_ONLY_ONCE))
.db_order_id_exists(mock_order_id_exists_db_port_true(IS_CALLED_ONLY_ONCE))
.get_uuid(mock_get_uuid(IS_CALLED_ONLY_ONCE))
.build()
.unwrap();
let res = s.add_kot(cmd.clone()).await.unwrap();
assert_eq!(res.kot().order_id(), cmd.order_id());
assert!(!res.kot().deleted());
assert_eq!(res.added_by_user(), cmd.adding_by());
}
#[actix_rt::test]
async fn test_service_order_id_doesnt_exist() {
let cmd = AddKotCommand::get_cmd();
let s = AddKotServiceBuilder::default()
.db_kot_id_exists(mock_kot_id_exists_db_port_false(IS_NEVER_CALLED))
.db_order_id_exists(mock_order_id_exists_db_port_false(IS_CALLED_ONLY_ONCE))
.get_uuid(mock_get_uuid(IS_NEVER_CALLED))
.build()
.unwrap();
assert_eq!(
s.add_kot(cmd.clone()).await,
Err(OrderingError::OrderIDNotFound)
);
}
}

View file

@ -9,6 +9,7 @@ use mockall::*;
pub mod errors;
//services
pub mod add_kot_service;
pub mod add_line_item_service;
pub mod add_order_service;
pub mod delete_line_item_service;
@ -24,6 +25,7 @@ pub trait OrderingServicesInterface: Send + Sync {
fn add_order(&self) -> add_order_service::AddOrderServiceObj;
fn update_order(&self) -> update_order_service::UpdateOrderServiceObj;
fn delete_order(&self) -> delete_order_service::DeleteOrderServiceObj;
fn add_kot(&self) -> add_kot_service::AddKotServiceObj;
}
#[derive(Clone, Builder)]
@ -34,6 +36,7 @@ pub struct OrderingServices {
add_order: add_order_service::AddOrderServiceObj,
update_order: update_order_service::UpdateOrderServiceObj,
delete_order: delete_order_service::DeleteOrderServiceObj,
add_kot: add_kot_service::AddKotServiceObj,
}
impl OrderingServicesInterface for OrderingServices {
@ -59,4 +62,8 @@ impl OrderingServicesInterface for OrderingServices {
fn delete_order(&self) -> delete_order_service::DeleteOrderServiceObj {
self.delete_order.clone()
}
fn add_kot(&self) -> add_kot_service::AddKotServiceObj {
self.add_kot.clone()
}
}

View file

@ -0,0 +1,58 @@
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
use derive_builder::Builder;
use derive_getters::Getters;
use serde::{Deserialize, Serialize};
use time::OffsetDateTime;
use uuid::Uuid;
#[derive(
Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Getters, Builder,
)]
pub struct AddKotCommand {
adding_by: Uuid,
#[builder(default = "OffsetDateTime::now_utc()")]
created_time: OffsetDateTime,
order_id: Uuid,
}
#[cfg(test)]
mod tests {
use time::macros::datetime;
use crate::utils::uuid::tests::UUID;
use super::*;
impl AddKotCommand {
pub fn get_cmd() -> Self {
let order_id = UUID;
let adding_by = UUID;
AddKotCommandBuilder::default()
.adding_by(adding_by)
.created_time(datetime!(1970-01-01 0:00 UTC))
.order_id(order_id)
.build()
.unwrap()
}
}
#[test]
fn test_cmd() {
let order_id = UUID;
let adding_by = UUID;
let cmd = AddKotCommandBuilder::default()
.adding_by(adding_by)
.order_id(order_id)
.build()
.unwrap();
assert_eq!(*cmd.order_id(), order_id);
assert_eq!(*cmd.adding_by(), adding_by);
}
}

View file

@ -6,9 +6,10 @@ use mockall::predicate::*;
use serde::{Deserialize, Serialize};
use super::{
add_line_item_command::AddLineItemCommand, add_order_command::AddOrderCommand,
delete_line_item_command::DeleteLineItemCommand, delete_order_command::DeleteOrderCommand,
update_line_item_command::UpdateLineItemCommand, update_order_command::UpdateOrderCommand,
add_kot_command::AddKotCommand, add_line_item_command::AddLineItemCommand,
add_order_command::AddOrderCommand, delete_line_item_command::DeleteLineItemCommand,
delete_order_command::DeleteOrderCommand, update_line_item_command::UpdateLineItemCommand,
update_order_command::UpdateOrderCommand,
};
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd)]
@ -19,4 +20,5 @@ pub enum OrderingCommand {
AddOrder(AddOrderCommand),
UpdateOrder(UpdateOrderCommand),
DeleteOrder(DeleteOrderCommand),
AddKot(AddKotCommand),
}

View file

@ -6,9 +6,10 @@ use cqrs_es::DomainEvent;
use serde::{Deserialize, Serialize};
use super::{
line_item_added_event::LineItemAddedEvent, line_item_deleted_event::LineItemDeletedEvent,
line_item_updated_event::LineItemUpdatedEvent, order_added_event::OrderAddedEvent,
order_deleted_event::OrderDeletedEvent, order_updated_event::OrderUpdatedEvent,
kot_added_event::KotAddedEvent, line_item_added_event::LineItemAddedEvent,
line_item_deleted_event::LineItemDeletedEvent, line_item_updated_event::LineItemUpdatedEvent,
order_added_event::OrderAddedEvent, order_deleted_event::OrderDeletedEvent,
order_updated_event::OrderUpdatedEvent,
};
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd)]
@ -19,6 +20,7 @@ pub enum OrderingEvent {
OrderAdded(OrderAddedEvent),
OrderUpdated(OrderUpdatedEvent),
OrderDeleted(OrderDeletedEvent),
KotAdded(KotAddedEvent),
}
impl DomainEvent for OrderingEvent {
@ -34,6 +36,7 @@ impl DomainEvent for OrderingEvent {
OrderingEvent::OrderAdded { .. } => "OrderingOrderAdded",
OrderingEvent::OrderUpdated { .. } => "OrderingOrderUpdated",
OrderingEvent::OrderDeleted { .. } => "OrderingOrderDeleted",
OrderingEvent::KotAdded { .. } => "OrderingKotAdded",
};
e.to_string()

View file

@ -0,0 +1,41 @@
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
use derive_builder::Builder;
use derive_getters::Getters;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use super::kot_aggregate::Kot;
#[derive(
Clone, Debug, Builder, Serialize, Deserialize, Getters, Eq, PartialEq, Ord, PartialOrd,
)]
pub struct KotAddedEvent {
added_by_user: Uuid,
kot: Kot,
}
#[cfg(test)]
pub mod tests {
use crate::ordering::domain::add_kot_command::AddKotCommand;
use super::*;
pub fn get_added_kot_event_from_command(cmd: &AddKotCommand) -> KotAddedEvent {
let kot = Kot::get_kot();
KotAddedEventBuilder::default()
.added_by_user(cmd.adding_by().clone())
.kot(kot)
.build()
.unwrap()
}
#[test]
fn test_event() {
get_added_kot_event_from_command(&AddKotCommand::get_cmd());
}
}

View file

@ -8,6 +8,7 @@ pub mod line_item_aggregate;
pub mod order_aggregate;
// commands
pub mod add_kot_command;
pub mod add_line_item_command;
pub mod add_order_command;
pub mod commands;
@ -18,6 +19,7 @@ pub mod update_order_command;
// events
pub mod events;
pub mod kot_added_event;
pub mod line_item_added_event;
pub mod line_item_deleted_event;
pub mod line_item_updated_event;