diff --git a/src/inventory/adapters/output/db/postgres/category_id_exists.rs b/src/inventory/adapters/output/db/postgres/category_id_exists.rs index 9438657..6b04fa1 100644 --- a/src/inventory/adapters/output/db/postgres/category_id_exists.rs +++ b/src/inventory/adapters/output/db/postgres/category_id_exists.rs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2024 Aravinth Manivannan // // SPDX-License-Identifier: AGPL-3.0-or-later +use uuid::Uuid; use super::InventoryDBPostgresAdapter; use crate::inventory::application::port::output::db::{category_id_exists::*, errors::*}; @@ -8,7 +9,7 @@ use crate::inventory::domain::category_aggregate::*; #[async_trait::async_trait] impl CategoryIDExistsDBPort for InventoryDBPostgresAdapter { - async fn category_id_exists(&self, s: &Category) -> InventoryDBResult { + async fn category_id_exists(&self, category_id: &Uuid) -> InventoryDBResult { let res = sqlx::query!( "SELECT EXISTS ( SELECT 1 @@ -16,7 +17,7 @@ impl CategoryIDExistsDBPort for InventoryDBPostgresAdapter { WHERE category_id = $1 );", - s.category_id(), + category_id, ) .fetch_one(&self.pool) .await?; @@ -57,12 +58,12 @@ mod tests { .unwrap(); // state doesn't exist - assert!(!db.category_id_exists(&category).await.unwrap()); + assert!(!db.category_id_exists(category.category_id()).await.unwrap()); create_dummy_category_record(&category, &db).await; // state exists - assert!(db.category_id_exists(&category).await.unwrap()); + assert!(db.category_id_exists(category.category_id()).await.unwrap()); settings.drop_db().await; } diff --git a/src/inventory/adapters/output/db/postgres/store_view.rs b/src/inventory/adapters/output/db/postgres/store_view.rs index 8a118b7..aae80d2 100644 --- a/src/inventory/adapters/output/db/postgres/store_view.rs +++ b/src/inventory/adapters/output/db/postgres/store_view.rs @@ -214,12 +214,14 @@ mod tests { add_category_service::tests::mock_add_category_service, add_customization_service::tests::mock_add_customization_service, add_product_service::tests::mock_add_product_service, - add_store_service::AddStoreServiceBuilder, InventoryServicesBuilder, + add_store_service::AddStoreServiceBuilder, + update_product_service::tests::mock_update_product_service, + InventoryServicesBuilder, }, domain::{ add_category_command::AddCategoryCommand, add_customization_command, add_product_command::tests::get_command, add_store_command::AddStoreCommand, - commands::InventoryCommand, + commands::InventoryCommand, update_product_command, }, }, tests::bdd::IS_NEVER_CALLED, @@ -260,6 +262,10 @@ mod tests { IS_NEVER_CALLED, add_customization_command::tests::get_command(), )) + .update_product(mock_update_product_service( + IS_NEVER_CALLED, + update_product_command::tests::get_command(), + )) .build() .unwrap(); diff --git a/src/inventory/application/port/output/db/category_id_exists.rs b/src/inventory/application/port/output/db/category_id_exists.rs index 4b0e19b..c2c93f0 100644 --- a/src/inventory/application/port/output/db/category_id_exists.rs +++ b/src/inventory/application/port/output/db/category_id_exists.rs @@ -4,8 +4,7 @@ use mockall::predicate::*; use mockall::*; - -use crate::inventory::domain::category_aggregate::Category; +use uuid::Uuid; use super::errors::*; #[cfg(test)] @@ -15,7 +14,7 @@ pub use tests::*; #[automock] #[async_trait::async_trait] pub trait CategoryIDExistsDBPort: Send + Sync { - async fn category_id_exists(&self, c: &Category) -> InventoryDBResult; + async fn category_id_exists(&self, category_id: &Uuid) -> InventoryDBResult; } pub type CategoryIDExistsDBPortObj = std::sync::Arc; diff --git a/src/inventory/application/services/add_category_service.rs b/src/inventory/application/services/add_category_service.rs index 5574614..4fe8c78 100644 --- a/src/inventory/application/services/add_category_service.rs +++ b/src/inventory/application/services/add_category_service.rs @@ -39,7 +39,22 @@ pub struct AddCategoryService { impl AddCategoryUseCase for AddCategoryService { async fn add_category(&self, cmd: AddCategoryCommand) -> InventoryResult { let mut category_id = self.get_uuid.get_uuid(); - let mut category = CategoryBuilder::default() + + loop { + if self + .db_category_id_exists + .category_id_exists(&category_id) + .await? + { + category_id = self.get_uuid.get_uuid(); + + continue; + } else { + break; + } + } + + let category = CategoryBuilder::default() .name(cmd.name().into()) .description(cmd.description().as_ref().map(|s| s.to_string())) .store_id(*cmd.store_id()) @@ -55,27 +70,6 @@ impl AddCategoryUseCase for AddCategoryService { return Err(InventoryError::DuplicateCategoryName); } - loop { - if self - .db_category_id_exists - .category_id_exists(&category) - .await? - { - category_id = self.get_uuid.get_uuid(); - category = CategoryBuilder::default() - .name(cmd.name().into()) - .description(cmd.description().as_ref().map(|s| s.to_string())) - .store_id(*cmd.store_id()) - .category_id(category_id) - .build() - .unwrap(); - - continue; - } else { - break; - } - } - Ok(CategoryAddedEventBuilder::default() .name(category.name().into()) .description(category.description().as_ref().map(|s| s.to_string())) @@ -165,7 +159,7 @@ pub mod tests { .db_category_name_exists_for_store(mock_category_name_exists_for_store_db_port_true( IS_CALLED_ONLY_ONCE, )) - .db_category_id_exists(mock_category_id_exists_db_port_false(IS_NEVER_CALLED)) + .db_category_id_exists(mock_category_id_exists_db_port_false(IS_CALLED_ONLY_ONCE)) .get_uuid(mock_get_uuid(IS_CALLED_ONLY_ONCE)) .build() .unwrap(); diff --git a/src/inventory/application/services/errors.rs b/src/inventory/application/services/errors.rs index bc5b1d0..18a49d9 100644 --- a/src/inventory/application/services/errors.rs +++ b/src/inventory/application/services/errors.rs @@ -17,6 +17,8 @@ pub enum InventoryError { DuplicateProductName, DuplicateCustomizationName, ProductIDNotFound, + CategoryIDNotFound, + StoreIDNotFound, InternalError, } diff --git a/src/inventory/application/services/mod.rs b/src/inventory/application/services/mod.rs index 704c116..321dcc9 100644 --- a/src/inventory/application/services/mod.rs +++ b/src/inventory/application/services/mod.rs @@ -13,6 +13,7 @@ pub mod add_category_service; pub mod add_customization_service; pub mod add_product_service; pub mod add_store_service; +pub mod update_product_service; #[automock] pub trait InventoryServicesInterface: Send + Sync { @@ -20,6 +21,7 @@ pub trait InventoryServicesInterface: Send + Sync { fn add_category(&self) -> add_category_service::AddCategoryServiceObj; fn add_product(&self) -> add_product_service::AddProductServiceObj; fn add_customization(&self) -> add_customization_service::AddCustomizationServiceObj; + fn update_product(&self) -> update_product_service::UpdateProductServiceObj; } #[derive(Clone, Builder)] @@ -28,6 +30,7 @@ pub struct InventoryServices { add_category: add_category_service::AddCategoryServiceObj, add_product: add_product_service::AddProductServiceObj, add_customization: add_customization_service::AddCustomizationServiceObj, + update_product: update_product_service::UpdateProductServiceObj, } impl InventoryServicesInterface for InventoryServices { @@ -44,4 +47,7 @@ impl InventoryServicesInterface for InventoryServices { fn add_customization(&self) -> add_customization_service::AddCustomizationServiceObj { self.add_customization.clone() } + fn update_product(&self) -> update_product_service::UpdateProductServiceObj { + self.update_product().clone() + } } diff --git a/src/inventory/application/services/update_product_service.rs b/src/inventory/application/services/update_product_service.rs index 56f60de..b36af6a 100644 --- a/src/inventory/application/services/update_product_service.rs +++ b/src/inventory/application/services/update_product_service.rs @@ -1,3 +1,205 @@ -// SPDX-FileCopyrightText: 2024 Aravinth Manivannan +/// SPDX-FileCopyrightText: 2024 Aravinth Manivannan // // 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::inventory::{ + application::port::output::db::{ + category_id_exists::*, product_id_exists::*, product_name_exists_for_category::*, + }, + domain::{product_aggregate::*, product_updated_event::*, update_product_command::*}, +}; +use crate::utils::uuid::*; + +#[automock] +#[async_trait::async_trait] +pub trait UpdateProductUseCase: Send + Sync { + async fn update_product( + &self, + cmd: UpdateProductCommand, + ) -> InventoryResult; +} + +pub type UpdateProductServiceObj = Arc; + +#[derive(Clone, Builder)] +pub struct UpdateProductService { + // TODO: check if category ID exists + db_product_name_exists_for_category: ProductNameExistsForCategoryDBPortObj, + db_product_id_exists: ProductIDExistsDBPortObj, + db_category_id_exists: CategoryIDExistsDBPortObj, +} + +#[async_trait::async_trait] +impl UpdateProductUseCase for UpdateProductService { + async fn update_product( + &self, + cmd: UpdateProductCommand, + ) -> InventoryResult { + if !self + .db_product_id_exists + .product_id_exists(cmd.old_product().product_id()) + .await? + { + return Err(InventoryError::ProductIDNotFound); + } + + if !self + .db_category_id_exists + .category_id_exists(cmd.category_id()) + .await? + { + return Err(InventoryError::CategoryIDNotFound); + } + + let updated_product = ProductBuilder::default() + .name(cmd.name().into()) + .description(cmd.description().as_ref().map(|s| s.to_string())) + .image(cmd.image().clone()) + .sku_able(*cmd.sku_able()) + .price(cmd.price().clone()) + .category_id(*cmd.category_id()) + .quantity(cmd.quantity().clone()) + .product_id(cmd.old_product().product_id().clone()) + .build() + .unwrap(); + + if updated_product.name() != cmd.old_product().name() { + if self + .db_product_name_exists_for_category + .product_name_exists_for_category(&updated_product) + .await? + { + return Err(InventoryError::DuplicateProductName); + } + } + + Ok(ProductUpdatedEventBuilder::default() + .added_by_user(*cmd.adding_by()) + .old_product(cmd.old_product().clone()) + .new_product(updated_product) + .build() + .unwrap()) + } +} + +#[cfg(test)] +pub mod tests { + use super::*; + + use crate::inventory::domain::product_updated_event; + use crate::inventory::domain::update_product_command::tests::get_command; + use crate::utils::uuid::tests::UUID; + use crate::{tests::bdd::*, utils::uuid::tests::mock_get_uuid}; + + pub fn mock_update_product_service( + times: Option, + cmd: UpdateProductCommand, + ) -> UpdateProductServiceObj { + let mut m = MockUpdateProductUseCase::new(); + + let res = product_updated_event::tests::get_event_from_command(&cmd); + + if let Some(times) = times { + m.expect_update_product() + .times(times) + .returning(move |_| Ok(res.clone())); + } else { + m.expect_update_product() + .returning(move |_| Ok(res.clone())); + } + + Arc::new(m) + } + + #[actix_rt::test] + async fn test_service() { + let cmd = get_command(); + + let s = UpdateProductServiceBuilder::default() + .db_category_id_exists(mock_category_id_exists_db_port_true(IS_CALLED_ONLY_ONCE)) + .db_product_name_exists_for_category( + mock_product_name_exists_for_category_db_port_false(IS_CALLED_ONLY_ONCE), + ) + .db_product_id_exists(mock_product_id_exists_db_port_true(IS_CALLED_ONLY_ONCE)) + .build() + .unwrap(); + + let res = s.update_product(cmd.clone()).await.unwrap(); + assert_eq!(res.new_product().name(), cmd.name()); + assert_eq!(res.new_product().description(), cmd.description()); + assert_eq!(res.new_product().image(), cmd.image()); + assert_eq!(res.new_product().sku_able(), cmd.sku_able()); + assert_eq!(res.new_product().price(), cmd.price()); + assert_eq!(res.new_product().category_id(), cmd.category_id()); + assert_eq!( + res.new_product().product_id(), + cmd.old_product().product_id() + ); + assert_eq!(res.new_product().quantity(), cmd.quantity()); + assert_eq!(res.old_product(), cmd.old_product()); + assert_eq!(res.added_by_user(), cmd.adding_by()); + } + + #[actix_rt::test] + async fn test_service_category_doesnt_exist() { + let cmd = get_command(); + + let s = UpdateProductServiceBuilder::default() + .db_category_id_exists(mock_category_id_exists_db_port_false(IS_CALLED_ONLY_ONCE)) + .db_product_name_exists_for_category( + mock_product_name_exists_for_category_db_port_false(IS_NEVER_CALLED), + ) + .db_product_id_exists(mock_product_id_exists_db_port_true(IS_CALLED_ONLY_ONCE)) + .build() + .unwrap(); + + assert_eq!( + s.update_product(cmd.clone()).await, + Err(InventoryError::CategoryIDNotFound) + ); + } + + #[actix_rt::test] + async fn test_product_id_not_found() { + let cmd = get_command(); + + let s = UpdateProductServiceBuilder::default() + .db_category_id_exists(mock_category_id_exists_db_port_true(IS_NEVER_CALLED)) + .db_product_name_exists_for_category( + mock_product_name_exists_for_category_db_port_false(IS_NEVER_CALLED), + ) + .db_product_id_exists(mock_product_id_exists_db_port_false(IS_CALLED_ONLY_ONCE)) + .build() + .unwrap(); + + assert_eq!( + s.update_product(cmd.clone()).await, + Err(InventoryError::ProductIDNotFound) + ); + } + + #[actix_rt::test] + async fn test_duplicate_new_name() { + let cmd = get_command(); + + let s = UpdateProductServiceBuilder::default() + .db_category_id_exists(mock_category_id_exists_db_port_true(IS_CALLED_ONLY_ONCE)) + .db_product_name_exists_for_category( + mock_product_name_exists_for_category_db_port_true(IS_CALLED_ONLY_ONCE), + ) + .db_product_id_exists(mock_product_id_exists_db_port_true(IS_CALLED_ONLY_ONCE)) + .build() + .unwrap(); + + assert_eq!( + s.update_product(cmd.clone()).await, + Err(InventoryError::DuplicateProductName) + ); + } +} diff --git a/src/inventory/domain/commands.rs b/src/inventory/domain/commands.rs index d3f36ea..33c82b4 100644 --- a/src/inventory/domain/commands.rs +++ b/src/inventory/domain/commands.rs @@ -8,6 +8,7 @@ use serde::{Deserialize, Serialize}; use super::{ add_category_command::AddCategoryCommand, add_customization_command::AddCustomizationCommand, add_product_command::AddProductCommand, add_store_command::AddStoreCommand, + update_product_command::UpdateProductCommand, }; #[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd)] @@ -16,4 +17,5 @@ pub enum InventoryCommand { AddStore(AddStoreCommand), AddProduct(AddProductCommand), AddCustomization(AddCustomizationCommand), + UpdateProduct(UpdateProductCommand), } diff --git a/src/inventory/domain/events.rs b/src/inventory/domain/events.rs index e40bde1..047c5ce 100644 --- a/src/inventory/domain/events.rs +++ b/src/inventory/domain/events.rs @@ -7,7 +7,8 @@ use serde::{Deserialize, Serialize}; use super::{ category_added_event::*, customization_added_event::CustomizationAddedEvent, - product_added_event::ProductAddedEvent, store_added_event::StoreAddedEvent, + product_added_event::ProductAddedEvent, product_updated_event::ProductUpdatedEvent, + store_added_event::StoreAddedEvent, }; #[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd)] @@ -16,6 +17,7 @@ pub enum InventoryEvent { StoreAdded(StoreAddedEvent), ProductAdded(ProductAddedEvent), CustomizationAdded(CustomizationAddedEvent), + ProductUpdated(ProductUpdatedEvent), } impl DomainEvent for InventoryEvent { @@ -29,6 +31,7 @@ impl DomainEvent for InventoryEvent { InventoryEvent::StoreAdded { .. } => "InventoryStoreAdded", InventoryEvent::ProductAdded { .. } => "InventoryProductAdded", InventoryEvent::CustomizationAdded { .. } => "InventoryCustomizationAdded", + InventoryEvent::ProductUpdated { .. } => "InventoryProductUpdated", }; e.to_string() diff --git a/src/inventory/domain/product_aggregate.rs b/src/inventory/domain/product_aggregate.rs index 5c04c73..b687109 100644 --- a/src/inventory/domain/product_aggregate.rs +++ b/src/inventory/domain/product_aggregate.rs @@ -140,6 +140,10 @@ impl Aggregate for Product { let res = services.add_product().add_product(cmd).await?; Ok(vec![InventoryEvent::ProductAdded(res)]) } + InventoryCommand::UpdateProduct(cmd) => { + let res = services.update_product().update_product(cmd).await?; + Ok(vec![InventoryEvent::ProductUpdated(res)]) + } _ => Ok(Vec::default()), } } @@ -160,6 +164,9 @@ impl Aggregate for Product { .build() .unwrap(); } + InventoryEvent::ProductUpdated(e) => { + *self = e.new_product().clone(); + } _ => (), } } @@ -170,6 +177,7 @@ mod aggregate_tests { use std::sync::Arc; use cqrs_es::test::TestFramework; + use update_product_service::tests::mock_update_product_service; use super::*; use crate::inventory::{ @@ -177,6 +185,7 @@ mod aggregate_tests { domain::{ add_product_command::tests::get_command, commands::InventoryCommand, events::InventoryEvent, product_added_event::tests::get_event_from_command, + product_updated_event, update_product_command, }, }; use crate::tests::bdd::*; @@ -201,6 +210,27 @@ mod aggregate_tests { .then_expect_events(vec![expected]); } + #[test] + fn test_update_product() { + let cmd = update_product_command::tests::get_command(); + let expected = product_updated_event::tests::get_event_from_command(&cmd); + let expected = InventoryEvent::ProductUpdated(expected); + + let mut services = MockInventoryServicesInterface::new(); + services + .expect_update_product() + .times(IS_CALLED_ONLY_ONCE.unwrap()) + .return_const(mock_update_product_service( + IS_CALLED_ONLY_ONCE, + cmd.clone(), + )); + + ProductTestFramework::with(Arc::new(services)) + .given_no_previous_events() + .when(InventoryCommand::UpdateProduct(cmd)) + .then_expect_events(vec![expected]); + } + fn test_helper(t: T, str_value: &str) -> bool where T: ToString + FromStr + std::fmt::Debug + PartialEq, diff --git a/src/inventory/domain/product_updated_event.rs b/src/inventory/domain/product_updated_event.rs index 91070cf..254a1b6 100644 --- a/src/inventory/domain/product_updated_event.rs +++ b/src/inventory/domain/product_updated_event.rs @@ -7,63 +7,47 @@ use derive_getters::Getters; use serde::{Deserialize, Serialize}; use uuid::Uuid; -use super::customization_aggregate::*; -use super::product_aggregate::{Price, Product, Quantity}; +use super::product_aggregate::Product; #[derive( Clone, Debug, Builder, Serialize, Deserialize, Getters, Eq, PartialEq, Ord, PartialOrd, )] -pub struct ProductUpdateedEvent { +pub struct ProductUpdatedEvent { added_by_user: Uuid, - name: String, - description: Option, - image: Option, // string = file_name - price: Price, - quantity: Quantity, - category_id: Uuid, - sku_able: bool, - product_id: Uuid, - customizations: Vec, - old_product: Product, + new_product: Product, } -//#[cfg(test)] -//pub mod tests { -// use crate::inventory::domain::{ -// add_product_command::UpdateProductCommand, product_aggregate::CustomizationBuilder, -// }; -// -// use super::*; -// -// use crate::utils::uuid::tests::UUID; -// -// pub fn get_event_from_command(cmd: &UpdateProductCommand) -> ProductUpdateedEvent { -// let mut customizations = Vec::with_capacity(cmd.customizations().len()); -// for c in cmd.customizations().iter() { -// customizations.push( -// CustomizationBuilder::default() -// .name(c.name().into()) -// .deleted(false) -// .customization_id(UUID) -// .build() -// .unwrap(), -// ); -// } -// -// ProductUpdateedEventBuilder::default() -// .name(cmd.name().into()) -// .description(cmd.description().as_ref().map(|s| s.to_string())) -// .image(cmd.image().as_ref().map(|s| s.to_string())) -// .sku_able(cmd.sku_able().clone()) -// .category_id(cmd.category_id().clone()) -// .product_id(UUID.clone()) -// .price(cmd.price().clone()) -// .customizations(customizations) -// .quantity(cmd.quantity().clone()) -// .added_by_user(cmd.adding_by().clone()) -// .build() -// .unwrap() -// } -//} +#[cfg(test)] +pub mod tests { + use crate::inventory::domain::{ + product_aggregate::*, update_product_command::UpdateProductCommand, + }; + + use super::*; + + #[test] + fn test_name() {} + + pub fn get_event_from_command(cmd: &UpdateProductCommand) -> ProductUpdatedEvent { + let updated_product = ProductBuilder::default() + .name(cmd.name().into()) + .description(cmd.description().as_ref().map(|s| s.to_string())) + .image(cmd.image().clone()) + .sku_able(*cmd.sku_able()) + .price(cmd.price().clone()) + .category_id(*cmd.category_id()) + .quantity(cmd.quantity().clone()) + .product_id(cmd.old_product().product_id().clone()) + .build() + .unwrap(); + + ProductUpdatedEventBuilder::default() + .added_by_user(cmd.adding_by().clone()) + .new_product(updated_product) + .old_product(cmd.old_product().clone()) + .build() + .unwrap() + } +} diff --git a/src/inventory/domain/update_product_command.rs b/src/inventory/domain/update_product_command.rs index 81db35f..d5938ec 100644 --- a/src/inventory/domain/update_product_command.rs +++ b/src/inventory/domain/update_product_command.rs @@ -15,30 +15,6 @@ use super::product_aggregate::{Price, Product, Quantity}; #[derive(Debug, Error, Display, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] pub enum UpdateProductCommandError { NameIsEmpty, - CustomizationNameIsEmpty, - DuplicateCustomizationName, -} -#[derive( - Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Getters, Builder, -)] -pub struct UnvalidatedUpdateCustomization { - name: String, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Getters)] -pub struct UpdateCustomization { - name: String, -} - -impl UnvalidatedUpdateCustomization { - pub fn validate(self) -> Result { - let name = self.name.trim().to_owned(); - if name.is_empty() { - return Err(UpdateProductCommandError::CustomizationNameIsEmpty); - } - - Ok(UpdateCustomization { name }) - } } #[derive( @@ -53,7 +29,6 @@ pub struct UnvalidatedUpdateProductCommand { quantity: Quantity, price: Price, adding_by: Uuid, - customizations: Vec, old_product: Product, } @@ -67,7 +42,6 @@ pub struct UpdateProductCommand { price: Price, quantity: Quantity, adding_by: Uuid, - customizations: Vec, old_product: Product, } @@ -100,22 +74,6 @@ impl UnvalidatedUpdateProductCommand { return Err(UpdateProductCommandError::NameIsEmpty); } - let mut unique_customization_names = HashSet::new(); - if !self - .customizations - .iter() - .all(|c| unique_customization_names.insert(c.name.clone())) - { - return Err(UpdateProductCommandError::DuplicateCustomizationName); - } - - // &name == self.old_product.name() && - // &description == self.old_product().description() && - // &image == self.old_product().image() && - // self.sku_able == *self.old_product().sku_able() && - // &self.price == self.old_product().price() && - // &self.quantity == self.old_product.quantity(); - Ok(UpdateProductCommand { name, description, @@ -125,7 +83,6 @@ impl UnvalidatedUpdateProductCommand { price: self.price, quantity: self.quantity, adding_by: self.adding_by, - customizations: self.customizations, old_product: self.old_product, }) } @@ -142,28 +99,6 @@ pub mod tests { utils::uuid::tests::UUID, }; - pub fn get_customizations() -> Vec { - vec![ - UnvalidatedUpdateCustomizationBuilder::default() - .name("foo".into()) - .build() - .unwrap() - .validate() - .unwrap(), - UnvalidatedUpdateCustomizationBuilder::default() - .name("bar".into()) - .build() - .unwrap() - .validate() - .unwrap(), - UnvalidatedUpdateCustomizationBuilder::default() - .name("baz".into()) - .build() - .unwrap() - .validate() - .unwrap(), - ] - } pub fn get_command() -> UpdateProductCommand { let name = "foo"; let adding_by = UUID; @@ -172,8 +107,6 @@ pub mod tests { let image = Some("image".to_string()); let description = Some("description".to_string()); - let customizations = get_customizations(); - let price = PriceBuilder::default() .minor(0) .major(100) @@ -196,7 +129,6 @@ pub mod tests { .quantity(quantity) .sku_able(sku_able) .price(price.clone()) - .customizations(customizations) .old_product(Product::default()) .build() .unwrap(); @@ -211,7 +143,6 @@ pub mod tests { let category_id = Uuid::new_v4(); let sku_able = false; - let customizations = get_customizations(); let price = PriceBuilder::default() .minor(0) .major(100) @@ -235,7 +166,6 @@ pub mod tests { .sku_able(sku_able) .price(price.clone()) .old_product(Product::default()) - .customizations(customizations.clone()) .build() .unwrap(); @@ -250,7 +180,6 @@ pub mod tests { assert_eq!(cmd.old_product(), &Product::default()); assert_eq!(cmd.price(), &price); assert_eq!(cmd.quantity(), &quantity); - assert_eq!(cmd.customizations(), &customizations); } #[test] fn test_description_some() { @@ -261,7 +190,6 @@ pub mod tests { let image = Some("image".to_string()); let description = Some("description".to_string()); - let customizations = get_customizations(); let price = PriceBuilder::default() .minor(0) .major(100) @@ -283,7 +211,6 @@ pub mod tests { .adding_by(adding_by.clone()) .sku_able(sku_able) .price(price.clone()) - .customizations(customizations.clone()) .old_product(Product::default()) .build() .unwrap(); @@ -298,7 +225,6 @@ pub mod tests { assert_eq!(cmd.sku_able(), &sku_able); assert_eq!(cmd.price(), &price); assert_eq!(cmd.quantity(), &quantity); - assert_eq!(cmd.customizations(), &customizations); assert_eq!(cmd.old_product(), &Product::default()); } @@ -310,7 +236,6 @@ pub mod tests { let image = Some("image".to_string()); let description = Some("description".to_string()); - let customizations = get_customizations(); let price = PriceBuilder::default() .minor(0) .major(100) @@ -332,7 +257,6 @@ pub mod tests { .quantity(quantity) .old_product(Product::default()) .sku_able(sku_able) - .customizations(customizations) .price(price.clone()) .build() .unwrap(); @@ -340,61 +264,4 @@ pub mod tests { // UpdateProductCommandError::NameIsEmpty assert_eq!(cmd.validate(), Err(UpdateProductCommandError::NameIsEmpty)) } - - #[test] - fn test_customization_name_is_empty() { - assert_eq!( - UnvalidatedUpdateCustomizationBuilder::default() - .name("".into()) - .build() - .unwrap() - .validate(), - Err(UpdateProductCommandError::CustomizationNameIsEmpty) - ) - } - - #[test] - fn test_duplicate_customization() { - let name = "foo"; - let adding_by = UUID; - let category_id = Uuid::new_v4(); - let sku_able = false; - let image = Some("image".to_string()); - let description = Some("description".to_string()); - - let mut customizations = get_customizations(); - customizations.push(customizations.first().unwrap().to_owned()); - - let price = PriceBuilder::default() - .minor(0) - .major(100) - .currency(Currency::INR) - .build() - .unwrap(); - let quantity = QuantityBuilder::default() - .number(1) - .unit(QuantityUnit::DiscreteNumber) - .build() - .unwrap(); - - let cmd = UnvalidatedUpdateProductCommandBuilder::default() - .name(name.into()) - .description(description.clone()) - .image(image.clone()) - .category_id(category_id.clone()) - .adding_by(adding_by.clone()) - .quantity(quantity) - .old_product(Product::default()) - .sku_able(sku_able) - .customizations(customizations) - .price(price.clone()) - .build() - .unwrap(); - - // UpdateProductCommandError::DuplicateCustomizationName - assert_eq!( - cmd.validate(), - Err(UpdateProductCommandError::DuplicateCustomizationName) - ) - } }