feat: compute total price for bill

This commit is contained in:
Aravinth Manivannan 2024-09-18 16:03:43 +05:30
parent 384dae69f5
commit f0da898e62
Signed by: realaravinth
GPG key ID: F8F50389936984FF
12 changed files with 455 additions and 8 deletions

View file

@ -0,0 +1,61 @@
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
use mockall::predicate::*;
use mockall::*;
use uuid::Uuid;
use crate::billing::domain::line_item_aggregate::LineItem;
use super::errors::*;
#[cfg(test)]
#[allow(unused_imports)]
pub use tests::*;
#[automock]
#[async_trait::async_trait]
pub trait GetLineItemsForBillIDDBPort: Send + Sync {
async fn get_line_items_for_bill_id(&self, bill_id: Uuid) -> BillingDBResult<Vec<LineItem>>;
}
pub type GetLineItemsForBillIDDBPortObj = std::sync::Arc<dyn GetLineItemsForBillIDDBPort>;
#[cfg(test)]
pub mod tests {
use super::*;
use std::sync::Arc;
pub fn mock_get_line_items_for_bill_id_db_port_no_line_items(
times: Option<usize>,
) -> GetLineItemsForBillIDDBPortObj {
let mut m = MockGetLineItemsForBillIDDBPort::new();
if let Some(times) = times {
m.expect_get_line_items_for_bill_id()
.times(times)
.returning(|_| Ok(Vec::default()));
} else {
m.expect_get_line_items_for_bill_id()
.returning(|_| Ok(Vec::default()));
}
Arc::new(m)
}
pub fn mock_get_line_items_for_bill_id_db_port_true(
times: Option<usize>,
) -> GetLineItemsForBillIDDBPortObj {
let mut m = MockGetLineItemsForBillIDDBPort::new();
if let Some(times) = times {
m.expect_get_line_items_for_bill_id()
.times(times)
.returning(|_| Ok(vec![LineItem::default()]));
} else {
m.expect_get_line_items_for_bill_id()
.returning(|_| Ok(vec![LineItem::default()]));
}
Arc::new(m)
}
}

View file

@ -3,6 +3,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later // SPDX-License-Identifier: AGPL-3.0-or-later
pub mod bill_id_exists; pub mod bill_id_exists;
pub mod errors; pub mod errors;
pub mod get_line_items_for_bill_id;
pub mod line_item_id_exists; pub mod line_item_id_exists;
pub mod next_token_id; pub mod next_token_id;
pub mod store_id_exists; pub mod store_id_exists;

View file

@ -0,0 +1,210 @@
// 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 super::errors::*;
use crate::{
billing::{
application::port::output::db::bill_id_exists::*,
application::port::output::db::get_line_items_for_bill_id::*,
domain::{
bill_aggregate::*, bill_total_price_computed_event::*,
compute_bill_total_price_command::*,
},
},
types::currency::*,
};
#[automock]
#[async_trait::async_trait]
pub trait ComputeBillTotalPriceBillUseCase: Send + Sync {
async fn compute_total_price_for_bill(
&self,
cmd: ComputeBillTotalPriceBillCommand,
) -> BillingResult<BillTotalPriceComputedEvent>;
}
pub type ComputeBillTotalPriceBillServiceObj = Arc<dyn ComputeBillTotalPriceBillUseCase>;
#[derive(Clone, Builder)]
pub struct ComputeBillTotalPriceBillService {
db_bill_id_exists: BillIDExistsDBPortObj,
db_get_line_items_for_bill_id: GetLineItemsForBillIDDBPortObj,
}
#[async_trait::async_trait]
impl ComputeBillTotalPriceBillUseCase for ComputeBillTotalPriceBillService {
async fn compute_total_price_for_bill(
&self,
cmd: ComputeBillTotalPriceBillCommand,
) -> BillingResult<BillTotalPriceComputedEvent> {
if !self.db_bill_id_exists.bill_id_exists(cmd.bill_id()).await? {
return Err(BillingError::BillIDNotFound);
}
let line_items = self
.db_get_line_items_for_bill_id
.get_line_items_for_bill_id(*cmd.bill_id())
.await?;
if line_items.is_empty() {
todo!("Can't compute bill");
}
let mut total_price = PriceBuilder::default()
.major(0)
.minor(0)
.currency(Currency::INR)
.build()
.unwrap();
for li in line_items.iter() {
total_price = total_price.clone() + li.total_price();
}
// TODO: 3. Tax?
Ok(BillTotalPriceComputedEventBuilder::default()
.added_by_user(*cmd.adding_by())
.bill_id(*cmd.bill_id())
.total_price(total_price)
.build()
.unwrap())
}
}
#[cfg(test)]
pub mod tests {
use time::macros::datetime;
use super::*;
use crate::billing::domain::bill_total_price_computed_event::tests::get_bill_total_computed_event_from_command;
use crate::billing::domain::line_item_aggregate::LineItemBuilder;
use crate::tests::bdd::*;
use crate::types::quantity::*;
use crate::utils::uuid::tests::*;
pub fn mock_compute_bill_total_price_service(
times: Option<usize>,
cmd: ComputeBillTotalPriceBillCommand,
) -> ComputeBillTotalPriceBillServiceObj {
let mut m = MockComputeBillTotalPriceBillUseCase::new();
let res = get_bill_total_computed_event_from_command(&cmd);
if let Some(times) = times {
m.expect_compute_total_price_for_bill()
.times(times)
.returning(move |_| Ok(res.clone()));
} else {
m.expect_compute_total_price_for_bill()
.returning(move |_| Ok(res.clone()));
}
Arc::new(m)
}
#[actix_rt::test]
async fn test_service() {
let cmd = ComputeBillTotalPriceBillCommand::get_cmd();
let s = ComputeBillTotalPriceBillServiceBuilder::default()
.db_bill_id_exists(mock_bill_id_exists_db_port_true(IS_CALLED_ONLY_ONCE))
.db_get_line_items_for_bill_id(mock_get_line_items_for_bill_id_db_port_true(
IS_CALLED_ONLY_ONCE,
))
.build()
.unwrap();
let res = s.compute_total_price_for_bill(cmd.clone()).await.unwrap();
assert_eq!(res.total_price().clone(), Price::default());
assert_eq!(res.bill_id(), cmd.bill_id());
assert_eq!(res.added_by_user(), cmd.adding_by());
}
#[actix_rt::test]
async fn test_service_sum() {
let cmd = ComputeBillTotalPriceBillCommand::get_cmd();
let li = LineItemBuilder::default()
.created_time(datetime!(1970-01-01 0:00 UTC))
.product_name("test_product".into())
.product_id(UUID)
.quantity(
QuantityBuilder::default()
.major(
QuantityPartBuilder::default()
.number(2)
.unit(QuantityUnit::DiscreteNumber)
.build()
.unwrap(),
)
.minor(
QuantityPartBuilder::default()
.number(1)
.unit(QuantityUnit::DiscreteNumber)
.build()
.unwrap(),
)
.build()
.unwrap(),
)
.bill_id(UUID)
.price_per_unit(
PriceBuilder::default()
.major(100)
.minor(20)
.currency(Currency::INR)
.build()
.unwrap(),
)
.line_item_id(UUID)
.build()
.unwrap();
let mut m = MockGetLineItemsForBillIDDBPort::new();
m.expect_get_line_items_for_bill_id()
.times(IS_CALLED_ONLY_ONCE.unwrap())
.returning(move |_| Ok(vec![li.clone(), li.clone()]));
let s = ComputeBillTotalPriceBillServiceBuilder::default()
.db_bill_id_exists(mock_bill_id_exists_db_port_true(IS_CALLED_ONLY_ONCE))
.db_get_line_items_for_bill_id(std::sync::Arc::new(m))
.build()
.unwrap();
let res = s.compute_total_price_for_bill(cmd.clone()).await.unwrap();
assert_eq!(
res.total_price().clone(),
PriceBuilder::default()
.major(100 * 2 * 2)
.minor(20 * 2 * 2)
.currency(Currency::INR)
.build()
.unwrap()
);
}
#[actix_rt::test]
async fn test_service_bill_id_doesnt_exist() {
let cmd = ComputeBillTotalPriceBillCommand::get_cmd();
let s = ComputeBillTotalPriceBillServiceBuilder::default()
.db_bill_id_exists(mock_bill_id_exists_db_port_false(IS_CALLED_ONLY_ONCE))
.db_get_line_items_for_bill_id(mock_get_line_items_for_bill_id_db_port_true(
IS_NEVER_CALLED,
))
.build()
.unwrap();
assert_eq!(
s.compute_total_price_for_bill(cmd.clone()).await,
Err(BillingError::BillIDNotFound)
);
}
}

View file

@ -12,11 +12,13 @@ pub mod errors;
pub mod add_bill_service; pub mod add_bill_service;
pub mod add_line_item_service; pub mod add_line_item_service;
pub mod add_store_service; pub mod add_store_service;
pub mod compute_bill_total_price_service;
pub mod delete_bill_service; pub mod delete_bill_service;
pub mod delete_line_item_service; pub mod delete_line_item_service;
pub mod update_bill_service; pub mod update_bill_service;
pub mod update_line_item_service; pub mod update_line_item_service;
pub mod update_store_service; pub mod update_store_service;
// TODO: 2. reset token number for store_id cronjob
#[automock] #[automock]
pub trait BillingServicesInterface: Send + Sync { pub trait BillingServicesInterface: Send + Sync {
@ -28,6 +30,9 @@ pub trait BillingServicesInterface: 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 compute_total_price_for_bill(
&self,
) -> compute_bill_total_price_service::ComputeBillTotalPriceBillServiceObj;
} }
#[derive(Clone, Builder)] #[derive(Clone, Builder)]
@ -40,6 +45,8 @@ pub struct BillingServices {
delete_line_item: delete_line_item_service::DeleteLineItemServiceObj, delete_line_item: delete_line_item_service::DeleteLineItemServiceObj,
update_bill: update_bill_service::UpdateBillServiceObj, update_bill: update_bill_service::UpdateBillServiceObj,
delete_bill: delete_bill_service::DeleteBillServiceObj, delete_bill: delete_bill_service::DeleteBillServiceObj,
compute_total_price_for_bill:
compute_bill_total_price_service::ComputeBillTotalPriceBillServiceObj,
} }
impl BillingServicesInterface for BillingServices { impl BillingServicesInterface for BillingServices {
@ -68,4 +75,9 @@ impl BillingServicesInterface for BillingServices {
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 compute_total_price_for_bill(
&self,
) -> compute_bill_total_price_service::ComputeBillTotalPriceBillServiceObj {
self.compute_total_price_for_bill.clone()
}
} }

View file

@ -100,6 +100,13 @@ impl Aggregate for Bill {
let res = services.delete_bill().delete_bill(cmd).await?; let res = services.delete_bill().delete_bill(cmd).await?;
Ok(vec![BillingEvent::BillDeleted(res)]) Ok(vec![BillingEvent::BillDeleted(res)])
} }
BillingCommand::ComputeBillTotalPriceBill(cmd) => {
let res = services
.compute_total_price_for_bill()
.compute_total_price_for_bill(cmd)
.await?;
Ok(vec![BillingEvent::BillTotalPriceComputed(res)])
}
_ => Ok(Vec::default()), _ => Ok(Vec::default()),
} }
} }
@ -108,6 +115,9 @@ impl Aggregate for Bill {
match event { match event {
BillingEvent::BillAdded(e) => *self = e.bill().clone(), BillingEvent::BillAdded(e) => *self = e.bill().clone(),
BillingEvent::BillUpdated(e) => *self = e.new_bill().clone(), BillingEvent::BillUpdated(e) => *self = e.new_bill().clone(),
BillingEvent::BillTotalPriceComputed(e) => {
self.total_price = Some(e.total_price().clone());
}
BillingEvent::BillDeleted(e) => *self = e.bill().clone(), BillingEvent::BillDeleted(e) => *self = e.bill().clone(),
_ => (), _ => (),
} }
@ -119,6 +129,8 @@ mod aggregate_tests {
use std::sync::Arc; use std::sync::Arc;
use add_bill_service::tests::mock_add_bill_service; use add_bill_service::tests::mock_add_bill_service;
use compute_bill_total_price_service::tests::mock_compute_bill_total_price_service;
use compute_bill_total_price_service::*;
use cqrs_es::test::TestFramework; use cqrs_es::test::TestFramework;
use delete_bill_service::tests::mock_delete_bill_service; use delete_bill_service::tests::mock_delete_bill_service;
use update_bill_service::tests::mock_update_bill_service; use update_bill_service::tests::mock_update_bill_service;
@ -126,6 +138,8 @@ mod aggregate_tests {
use super::*; use super::*;
use crate::billing::domain::bill_deleted_event::tests::get_deleted_bill_event_from_command; use crate::billing::domain::bill_deleted_event::tests::get_deleted_bill_event_from_command;
use crate::billing::domain::bill_total_price_computed_event::tests::get_bill_total_computed_event_from_command;
use crate::billing::domain::bill_total_price_computed_event::BillTotalPriceComputedEvent;
use crate::billing::domain::bill_updated_event::tests::get_updated_bill_event_from_command; use crate::billing::domain::bill_updated_event::tests::get_updated_bill_event_from_command;
use crate::billing::domain::delete_bill_command::DeleteBillCommand; use crate::billing::domain::delete_bill_command::DeleteBillCommand;
use crate::billing::domain::update_bill_command::UpdateBillCommand; use crate::billing::domain::update_bill_command::UpdateBillCommand;
@ -133,6 +147,7 @@ mod aggregate_tests {
use crate::billing::domain::{ use crate::billing::domain::{
add_bill_command::*, bill_added_event::tests::get_added_bill_event_from_command, add_bill_command::*, bill_added_event::tests::get_added_bill_event_from_command,
bill_total_price_computed_event::tests::*, compute_bill_total_price_command::*,
}; };
type BillTestFramework = TestFramework<Bill>; type BillTestFramework = TestFramework<Bill>;
@ -173,6 +188,27 @@ mod aggregate_tests {
.then_expect_events(vec![expected]); .then_expect_events(vec![expected]);
} }
#[test]
fn test_bill_total_price_computed() {
let cmd = ComputeBillTotalPriceBillCommand::get_cmd();
let expected = get_bill_total_computed_event_from_command(&cmd);
let expected = BillingEvent::BillTotalPriceComputed(expected);
let mut services = MockBillingServicesInterface::new();
services
.expect_compute_total_price_for_bill()
.times(IS_CALLED_ONLY_ONCE.unwrap())
.return_const(mock_compute_bill_total_price_service(
IS_CALLED_ONLY_ONCE,
cmd.clone(),
));
BillTestFramework::with(Arc::new(services))
.given_no_previous_events()
.when(BillingCommand::ComputeBillTotalPriceBill(cmd))
.then_expect_events(vec![expected]);
}
#[test] #[test]
fn test_delete_bill() { fn test_delete_bill() {
let cmd = DeleteBillCommand::get_cmd(); let cmd = DeleteBillCommand::get_cmd();

View file

@ -0,0 +1,44 @@
// 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::bill_aggregate::*;
use crate::types::currency::*;
#[derive(
Clone, Debug, Builder, Serialize, Deserialize, Getters, Eq, PartialEq, Ord, PartialOrd,
)]
pub struct BillTotalPriceComputedEvent {
added_by_user: Uuid,
bill_id: Uuid,
total_price: Price,
}
#[cfg(test)]
pub mod tests {
use crate::billing::domain::compute_bill_total_price_command::*;
use super::*;
pub fn get_bill_total_computed_event_from_command(
cmd: &ComputeBillTotalPriceBillCommand,
) -> BillTotalPriceComputedEvent {
BillTotalPriceComputedEventBuilder::default()
.added_by_user(cmd.adding_by().clone())
.bill_id(*cmd.bill_id())
.total_price(Price::default())
.build()
.unwrap()
}
#[test]
fn test_event() {
get_bill_total_computed_event_from_command(&ComputeBillTotalPriceBillCommand::get_cmd());
}
}

View file

@ -7,9 +7,11 @@ use serde::{Deserialize, Serialize};
use super::{ use super::{
add_bill_command::AddBillCommand, add_line_item_command::AddLineItemCommand, add_bill_command::AddBillCommand, add_line_item_command::AddLineItemCommand,
add_store_command::AddStoreCommand, delete_bill_command::DeleteBillCommand, add_store_command::AddStoreCommand,
delete_line_item_command::DeleteLineItemCommand, update_bill_command::UpdateBillCommand, compute_bill_total_price_command::ComputeBillTotalPriceBillCommand,
update_line_item_command::UpdateLineItemCommand, update_store_command::UpdateStoreCommand, delete_bill_command::DeleteBillCommand, delete_line_item_command::DeleteLineItemCommand,
update_bill_command::UpdateBillCommand, update_line_item_command::UpdateLineItemCommand,
update_store_command::UpdateStoreCommand,
}; };
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd)] #[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd)]
@ -20,6 +22,7 @@ pub enum BillingCommand {
AddBill(AddBillCommand), AddBill(AddBillCommand),
UpdateBill(UpdateBillCommand), UpdateBill(UpdateBillCommand),
DeleteBill(DeleteBillCommand), DeleteBill(DeleteBillCommand),
ComputeBillTotalPriceBill(ComputeBillTotalPriceBillCommand),
AddStore(AddStoreCommand), AddStore(AddStoreCommand),
UpdateStore(UpdateStoreCommand), UpdateStore(UpdateStoreCommand),
} }

View file

@ -0,0 +1,66 @@
// 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;
use super::bill_aggregate::Bill;
use crate::types::currency::*;
#[derive(
Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Getters, Builder,
)]
pub struct ComputeBillTotalPriceBillCommand {
adding_by: Uuid,
#[builder(default = "OffsetDateTime::now_utc()")]
created_time: OffsetDateTime,
bill_id: Uuid,
}
#[cfg(test)]
mod tests {
use time::macros::datetime;
use crate::{
billing::{self, domain::bill_aggregate::*},
utils::uuid::tests::UUID,
};
use super::*;
impl ComputeBillTotalPriceBillCommand {
pub fn get_cmd() -> Self {
let bill_id = UUID;
let adding_by = UUID;
ComputeBillTotalPriceBillCommandBuilder::default()
.adding_by(adding_by)
.bill_id(bill_id)
.created_time(datetime!(1970-01-01 0:00 UTC))
.build()
.unwrap()
}
}
#[test]
fn test_cmd() {
let bill_id = UUID;
let adding_by = UUID;
let cmd = ComputeBillTotalPriceBillCommandBuilder::default()
.adding_by(adding_by)
.bill_id(bill_id)
.created_time(datetime!(1970-01-01 0:00 UTC))
.build()
.unwrap();
assert_eq!(*cmd.bill_id(), bill_id);
assert_eq!(*cmd.adding_by(), adding_by);
}
}

View file

@ -7,6 +7,7 @@ use serde::{Deserialize, Serialize};
use super::{ use super::{
bill_added_event::BillAddedEvent, bill_deleted_event::BillDeletedEvent, bill_added_event::BillAddedEvent, bill_deleted_event::BillDeletedEvent,
bill_total_price_computed_event::BillTotalPriceComputedEvent,
bill_updated_event::BillUpdatedEvent, line_item_added_event::LineItemAddedEvent, bill_updated_event::BillUpdatedEvent, line_item_added_event::LineItemAddedEvent,
line_item_deleted_event::LineItemDeletedEvent, line_item_updated_event::LineItemUpdatedEvent, line_item_deleted_event::LineItemDeletedEvent, line_item_updated_event::LineItemUpdatedEvent,
store_added_event::StoreAddedEvent, store_updated_event::StoreUpdatedEvent, store_added_event::StoreAddedEvent, store_updated_event::StoreUpdatedEvent,
@ -20,6 +21,7 @@ pub enum BillingEvent {
BillAdded(BillAddedEvent), BillAdded(BillAddedEvent),
BillUpdated(BillUpdatedEvent), BillUpdated(BillUpdatedEvent),
BillDeleted(BillDeletedEvent), BillDeleted(BillDeletedEvent),
BillTotalPriceComputed(BillTotalPriceComputedEvent),
StoreAdded(StoreAddedEvent), StoreAdded(StoreAddedEvent),
StoreUpdated(StoreUpdatedEvent), StoreUpdated(StoreUpdatedEvent),
} }
@ -34,9 +36,10 @@ impl DomainEvent for BillingEvent {
BillingEvent::LineItemAdded { .. } => "BillingLineItemAdded", BillingEvent::LineItemAdded { .. } => "BillingLineItemAdded",
BillingEvent::LineItemUpdated { .. } => "BillingLineItemUpdated", BillingEvent::LineItemUpdated { .. } => "BillingLineItemUpdated",
BillingEvent::LineItemDeleted { .. } => "BillingLineItemDeleted", BillingEvent::LineItemDeleted { .. } => "BillingLineItemDeleted",
BillingEvent::BillAdded { .. } => "BillingBilAdded", BillingEvent::BillAdded { .. } => "BillingBillAdded",
BillingEvent::BillUpdated { .. } => "BillingBilUpdated", BillingEvent::BillUpdated { .. } => "BillingBillUpdated",
BillingEvent::BillDeleted { .. } => "BillingBilDeleted", BillingEvent::BillDeleted { .. } => "BillingBillDeleted",
BillingEvent::BillTotalPriceComputed { .. } => "BillingBillTotalPriceComputed",
BillingEvent::StoreAdded { .. } => "BillingStoreAdded", BillingEvent::StoreAdded { .. } => "BillingStoreAdded",
BillingEvent::StoreUpdated { .. } => "BillingStoreUpdated", BillingEvent::StoreUpdated { .. } => "BillingStoreUpdated",
}; };

View file

@ -49,9 +49,15 @@ impl Default for LineItem {
impl LineItem { impl LineItem {
pub fn total_price(&self) -> Price { pub fn total_price(&self) -> Price {
let total_price_as_minor = (self.quantity().major_as_minor().unwrap() // TODO: handle err let price_per_unit_as_minor =
self.price_per_unit().major_as_minor() + self.price_per_unit().minor();
let total_price_as_minor = if self.quantity().major().is_dividable() {
(self.quantity().major_as_minor().unwrap() // TODO: handle err
+ self.quantity().minor().number()) + self.quantity().minor().number())
* (self.price_per_unit().major_as_minor() + self.price_per_unit().minor()); * price_per_unit_as_minor
} else {
self.quantity().major().number() * price_per_unit_as_minor
};
Price::from_minor( Price::from_minor(
total_price_as_minor, total_price_as_minor,

View file

@ -12,6 +12,7 @@ pub mod add_bill_command;
pub mod add_line_item_command; pub mod add_line_item_command;
pub mod add_store_command; pub mod add_store_command;
pub mod commands; pub mod commands;
pub mod compute_bill_total_price_command;
pub mod delete_bill_command; pub mod delete_bill_command;
pub mod delete_line_item_command; pub mod delete_line_item_command;
pub mod update_bill_command; pub mod update_bill_command;
@ -21,6 +22,7 @@ pub mod update_store_command;
// events; // events;
pub mod bill_added_event; pub mod bill_added_event;
pub mod bill_deleted_event; pub mod bill_deleted_event;
pub mod bill_total_price_computed_event;
pub mod bill_updated_event; pub mod bill_updated_event;
pub mod events; pub mod events;
pub mod line_item_added_event; pub mod line_item_added_event;

View file

@ -29,6 +29,8 @@ pub struct UpdateBillCommand {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use time::macros::datetime;
use crate::{billing::domain::bill_aggregate::*, utils::uuid::tests::UUID}; use crate::{billing::domain::bill_aggregate::*, utils::uuid::tests::UUID};
use super::*; use super::*;
@ -39,6 +41,7 @@ mod tests {
let adding_by = UUID; let adding_by = UUID;
UpdateBillCommandBuilder::default() UpdateBillCommandBuilder::default()
.created_time(datetime!(1970-01-01 0:00 UTC))
.adding_by(adding_by) .adding_by(adding_by)
.store_id(store_id) .store_id(store_id)
.total_price(None) .total_price(None)