feat: include minor and major quantity description in Product and amend DB for same #55
14 changed files with 249 additions and 153 deletions
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"db_name": "PostgreSQL",
|
"db_name": "PostgreSQL",
|
||||||
"query": "INSERT INTO cqrs_inventory_product_query (\n version,\n name,\n description,\n image,\n product_id,\n category_id,\n price_major,\n price_minor,\n price_currency,\n sku_able,\n quantity_unit,\n quantity_number,\n deleted\n ) VALUES (\n $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13\n );",
|
"query": "INSERT INTO cqrs_inventory_product_query (\n version,\n name,\n description,\n image,\n product_id,\n category_id,\n price_major,\n price_minor,\n price_currency,\n sku_able,\n quantity_minor_unit,\n quantity_minor_number,\n quantity_major_unit,\n quantity_major_number,\n\n deleted\n ) VALUES (\n $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15\n );",
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
"parameters": {
|
"parameters": {
|
||||||
|
@ -17,10 +17,12 @@
|
||||||
"Bool",
|
"Bool",
|
||||||
"Text",
|
"Text",
|
||||||
"Int4",
|
"Int4",
|
||||||
|
"Text",
|
||||||
|
"Int4",
|
||||||
"Bool"
|
"Bool"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"nullable": []
|
"nullable": []
|
||||||
},
|
},
|
||||||
"hash": "9390910c71001ef77313e594dea0e4f0682f740778e483a2db91d6c73ac6bc6d"
|
"hash": "c091fbfdc77afd15d73933c5092be72fda7a14b38462b52a8a4d6e8eee00f7c6"
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"db_name": "PostgreSQL",
|
"db_name": "PostgreSQL",
|
||||||
"query": "UPDATE\n cqrs_inventory_product_query\n SET\n version = $1,\n name = $2,\n description = $3,\n image = $4,\n product_id = $5,\n category_id = $6,\n price_major = $7,\n price_minor = $8,\n price_currency = $9,\n sku_able = $10,\n quantity_unit = $11,\n quantity_number = $12,\n deleted = $13;",
|
"query": "UPDATE\n cqrs_inventory_product_query\n SET\n version = $1,\n name = $2,\n description = $3,\n image = $4,\n product_id = $5,\n category_id = $6,\n price_major = $7,\n price_minor = $8,\n price_currency = $9,\n sku_able = $10,\n quantity_minor_unit = $11,\n quantity_minor_number = $12,\n quantity_major_unit = $13,\n quantity_major_number = $14,\n deleted = $15;",
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
"parameters": {
|
"parameters": {
|
||||||
|
@ -17,10 +17,12 @@
|
||||||
"Bool",
|
"Bool",
|
||||||
"Text",
|
"Text",
|
||||||
"Int4",
|
"Int4",
|
||||||
|
"Text",
|
||||||
|
"Int4",
|
||||||
"Bool"
|
"Bool"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"nullable": []
|
"nullable": []
|
||||||
},
|
},
|
||||||
"hash": "f55fe530202bb369fdea3baaf91f86bbc866218e4146b6d608255c1b929073b4"
|
"hash": "e2f9f291a20aac77851774ba8cd37325143a4d98e0980632f097c5885cc71094"
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"db_name": "PostgreSQL",
|
"db_name": "PostgreSQL",
|
||||||
"query": "SELECT \n name,\n description,\n image,\n product_id,\n category_id,\n price_major,\n price_minor,\n price_currency,\n sku_able,\n quantity_unit,\n quantity_number,\n deleted\n FROM\n cqrs_inventory_product_query\n WHERE\n product_id = $1;",
|
"query": "SELECT \n name,\n description,\n image,\n product_id,\n category_id,\n price_major,\n price_minor,\n price_currency,\n sku_able,\n quantity_minor_unit,\n quantity_minor_number,\n quantity_major_unit,\n quantity_major_number,\n deleted\n FROM\n cqrs_inventory_product_query\n WHERE\n product_id = $1;",
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
|
@ -50,16 +50,26 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 9,
|
"ordinal": 9,
|
||||||
"name": "quantity_unit",
|
"name": "quantity_minor_unit",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 10,
|
"ordinal": 10,
|
||||||
"name": "quantity_number",
|
"name": "quantity_minor_number",
|
||||||
"type_info": "Int4"
|
"type_info": "Int4"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 11,
|
"ordinal": 11,
|
||||||
|
"name": "quantity_major_unit",
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 12,
|
||||||
|
"name": "quantity_major_number",
|
||||||
|
"type_info": "Int4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 13,
|
||||||
"name": "deleted",
|
"name": "deleted",
|
||||||
"type_info": "Bool"
|
"type_info": "Bool"
|
||||||
}
|
}
|
||||||
|
@ -81,8 +91,10 @@
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
false
|
false
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"hash": "3f83167782a2de1be7d87d35f63a3e530373595ce83cd36612ee48d3c36c81f3"
|
"hash": "f40df2534cbf3a44afdd27bb19cff0c62d56d9236356287d56e965b5e2a7b3d2"
|
||||||
}
|
}
|
|
@ -17,8 +17,10 @@ CREATE TABLE IF NOT EXISTS cqrs_inventory_product_query
|
||||||
price_major INTEGER NOT NULL,
|
price_major INTEGER NOT NULL,
|
||||||
price_currency TEXT NOT NULL,
|
price_currency TEXT NOT NULL,
|
||||||
|
|
||||||
quantity_number INTEGER NOT NULL,
|
quantity_major_number INTEGER NOT NULL,
|
||||||
quantity_unit TEXT NOT NULL,
|
quantity_minor_number INTEGER NOT NULL,
|
||||||
|
quantity_major_unit TEXT NOT NULL,
|
||||||
|
quantity_minor_unit TEXT NOT NULL,
|
||||||
|
|
||||||
category_id UUID NOT NULL,
|
category_id UUID NOT NULL,
|
||||||
|
|
||||||
|
|
|
@ -84,11 +84,13 @@ pub mod tests {
|
||||||
price_minor,
|
price_minor,
|
||||||
price_currency,
|
price_currency,
|
||||||
sku_able,
|
sku_able,
|
||||||
quantity_unit,
|
quantity_minor_unit,
|
||||||
quantity_number,
|
quantity_minor_number,
|
||||||
|
quantity_major_unit,
|
||||||
|
quantity_major_number,
|
||||||
deleted
|
deleted
|
||||||
) VALUES (
|
) VALUES (
|
||||||
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13
|
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15
|
||||||
);",
|
);",
|
||||||
1,
|
1,
|
||||||
p.name(),
|
p.name(),
|
||||||
|
@ -100,8 +102,10 @@ pub mod tests {
|
||||||
p.price().minor().clone() as i32,
|
p.price().minor().clone() as i32,
|
||||||
p.price().currency().to_string(),
|
p.price().currency().to_string(),
|
||||||
p.sku_able().clone(),
|
p.sku_able().clone(),
|
||||||
p.quantity().unit().to_string(),
|
p.quantity().major().unit().to_string(),
|
||||||
p.quantity().number().clone() as i32,
|
p.quantity().major().number().clone() as i32,
|
||||||
|
p.quantity().minor().unit().to_string(),
|
||||||
|
p.quantity().minor().number().clone() as i32,
|
||||||
p.deleted().clone(),
|
p.deleted().clone(),
|
||||||
)
|
)
|
||||||
.execute(&db.pool)
|
.execute(&db.pool)
|
||||||
|
|
|
@ -14,8 +14,9 @@ use super::errors::*;
|
||||||
use super::InventoryDBPostgresAdapter;
|
use super::InventoryDBPostgresAdapter;
|
||||||
use crate::inventory::domain::events::InventoryEvent;
|
use crate::inventory::domain::events::InventoryEvent;
|
||||||
use crate::inventory::domain::product_aggregate::{
|
use crate::inventory::domain::product_aggregate::{
|
||||||
Currency, PriceBuilder, Product, ProductBuilder, QuantityBuilder, QuantityUnit,
|
Currency, PriceBuilder, Product, ProductBuilder,
|
||||||
};
|
};
|
||||||
|
use crate::types::quantity::*;
|
||||||
use crate::utils::parse_aggregate_id::parse_aggregate_id;
|
use crate::utils::parse_aggregate_id::parse_aggregate_id;
|
||||||
|
|
||||||
pub const NEW_PRODUCT_NON_UUID: &str = "new_product_non_uuid-asdfa";
|
pub const NEW_PRODUCT_NON_UUID: &str = "new_product_non_uuid-asdfa";
|
||||||
|
@ -34,8 +35,10 @@ pub struct ProductView {
|
||||||
price_major: i32,
|
price_major: i32,
|
||||||
price_currency: String,
|
price_currency: String,
|
||||||
|
|
||||||
quantity_unit: String,
|
quantity_major_number: i32,
|
||||||
quantity_number: i32,
|
quantity_minor_number: i32,
|
||||||
|
quantity_major_unit: String,
|
||||||
|
quantity_minor_unit: String,
|
||||||
|
|
||||||
category_id: Uuid,
|
category_id: Uuid,
|
||||||
|
|
||||||
|
@ -52,8 +55,20 @@ impl From<ProductView> for Product {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let quantity = QuantityBuilder::default()
|
let quantity = QuantityBuilder::default()
|
||||||
.number(v.quantity_number as usize)
|
.minor(
|
||||||
.unit(QuantityUnit::from_str(&v.quantity_unit).unwrap())
|
QuantityPartBuilder::default()
|
||||||
|
.number(v.quantity_minor_number as usize)
|
||||||
|
.unit(QuantityUnit::from_str(&v.quantity_minor_unit).unwrap())
|
||||||
|
.build()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.major(
|
||||||
|
QuantityPartBuilder::default()
|
||||||
|
.number(v.quantity_major_number as usize)
|
||||||
|
.unit(QuantityUnit::from_str(&v.quantity_major_unit).unwrap())
|
||||||
|
.build()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -91,8 +106,10 @@ impl View<Product> for ProductView {
|
||||||
self.price_major = *val.price().major() as i32;
|
self.price_major = *val.price().major() as i32;
|
||||||
self.price_currency = val.price().currency().to_string();
|
self.price_currency = val.price().currency().to_string();
|
||||||
|
|
||||||
self.quantity_number = *val.quantity().number() as i32;
|
self.quantity_major_number = *val.quantity().major().number() as i32;
|
||||||
self.quantity_unit = val.quantity().unit().to_string();
|
self.quantity_minor_number = *val.quantity().minor().number() as i32;
|
||||||
|
self.quantity_major_unit = val.quantity().major().unit().to_string();
|
||||||
|
self.quantity_minor_unit = val.quantity().minor().unit().to_string();
|
||||||
|
|
||||||
self.deleted = false;
|
self.deleted = false;
|
||||||
}
|
}
|
||||||
|
@ -121,8 +138,10 @@ impl ViewRepository<ProductView, Product> for InventoryDBPostgresAdapter {
|
||||||
price_minor,
|
price_minor,
|
||||||
price_currency,
|
price_currency,
|
||||||
sku_able,
|
sku_able,
|
||||||
quantity_unit,
|
quantity_minor_unit,
|
||||||
quantity_number,
|
quantity_minor_number,
|
||||||
|
quantity_major_unit,
|
||||||
|
quantity_major_number,
|
||||||
deleted
|
deleted
|
||||||
FROM
|
FROM
|
||||||
cqrs_inventory_product_query
|
cqrs_inventory_product_query
|
||||||
|
@ -158,8 +177,10 @@ impl ViewRepository<ProductView, Product> for InventoryDBPostgresAdapter {
|
||||||
price_minor,
|
price_minor,
|
||||||
price_currency,
|
price_currency,
|
||||||
sku_able,
|
sku_able,
|
||||||
quantity_unit,
|
quantity_minor_unit,
|
||||||
quantity_number,
|
quantity_minor_number,
|
||||||
|
quantity_major_unit,
|
||||||
|
quantity_major_number,
|
||||||
deleted
|
deleted
|
||||||
FROM
|
FROM
|
||||||
cqrs_inventory_product_query
|
cqrs_inventory_product_query
|
||||||
|
@ -214,11 +235,14 @@ impl ViewRepository<ProductView, Product> for InventoryDBPostgresAdapter {
|
||||||
price_minor,
|
price_minor,
|
||||||
price_currency,
|
price_currency,
|
||||||
sku_able,
|
sku_able,
|
||||||
quantity_unit,
|
quantity_minor_unit,
|
||||||
quantity_number,
|
quantity_minor_number,
|
||||||
|
quantity_major_unit,
|
||||||
|
quantity_major_number,
|
||||||
|
|
||||||
deleted
|
deleted
|
||||||
) VALUES (
|
) VALUES (
|
||||||
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13
|
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15
|
||||||
);",
|
);",
|
||||||
version,
|
version,
|
||||||
view.name,
|
view.name,
|
||||||
|
@ -230,8 +254,10 @@ impl ViewRepository<ProductView, Product> for InventoryDBPostgresAdapter {
|
||||||
view.price_minor,
|
view.price_minor,
|
||||||
view.price_currency,
|
view.price_currency,
|
||||||
view.sku_able,
|
view.sku_able,
|
||||||
view.quantity_unit,
|
view.quantity_minor_unit,
|
||||||
view.quantity_number,
|
view.quantity_minor_number,
|
||||||
|
view.quantity_major_unit,
|
||||||
|
view.quantity_major_number,
|
||||||
view.deleted,
|
view.deleted,
|
||||||
)
|
)
|
||||||
.execute(&self.pool)
|
.execute(&self.pool)
|
||||||
|
@ -255,9 +281,11 @@ impl ViewRepository<ProductView, Product> for InventoryDBPostgresAdapter {
|
||||||
price_minor = $8,
|
price_minor = $8,
|
||||||
price_currency = $9,
|
price_currency = $9,
|
||||||
sku_able = $10,
|
sku_able = $10,
|
||||||
quantity_unit = $11,
|
quantity_minor_unit = $11,
|
||||||
quantity_number = $12,
|
quantity_minor_number = $12,
|
||||||
deleted = $13;",
|
quantity_major_unit = $13,
|
||||||
|
quantity_major_number = $14,
|
||||||
|
deleted = $15;",
|
||||||
version,
|
version,
|
||||||
view.name,
|
view.name,
|
||||||
view.description,
|
view.description,
|
||||||
|
@ -268,8 +296,10 @@ impl ViewRepository<ProductView, Product> for InventoryDBPostgresAdapter {
|
||||||
view.price_minor,
|
view.price_minor,
|
||||||
view.price_currency,
|
view.price_currency,
|
||||||
view.sku_able,
|
view.sku_able,
|
||||||
view.quantity_unit,
|
view.quantity_minor_unit,
|
||||||
view.quantity_number,
|
view.quantity_minor_number,
|
||||||
|
view.quantity_major_unit,
|
||||||
|
view.quantity_major_number,
|
||||||
view.deleted,
|
view.deleted,
|
||||||
)
|
)
|
||||||
.execute(&self.pool)
|
.execute(&self.pool)
|
||||||
|
|
|
@ -8,7 +8,8 @@ use derive_more::{Display, Error};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use super::product_aggregate::{Price, Quantity};
|
use super::product_aggregate::Price;
|
||||||
|
use crate::types::quantity::*;
|
||||||
|
|
||||||
#[derive(Debug, Error, Display, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Error, Display, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub enum AddProductCommandError {
|
pub enum AddProductCommandError {
|
||||||
|
@ -88,9 +89,7 @@ pub mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
inventory::domain::product_aggregate::{
|
inventory::domain::product_aggregate::{Currency, PriceBuilder},
|
||||||
Currency, PriceBuilder, QuantityBuilder, QuantityUnit,
|
|
||||||
},
|
|
||||||
utils::uuid::tests::UUID,
|
utils::uuid::tests::UUID,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -110,8 +109,20 @@ pub mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let quantity = QuantityBuilder::default()
|
let quantity = QuantityBuilder::default()
|
||||||
.number(1)
|
.minor(
|
||||||
.unit(QuantityUnit::DiscreteNumber)
|
QuantityPartBuilder::default()
|
||||||
|
.number(0)
|
||||||
|
.unit(QuantityUnit::DiscreteNumber)
|
||||||
|
.build()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.major(
|
||||||
|
QuantityPartBuilder::default()
|
||||||
|
.number(1)
|
||||||
|
.unit(QuantityUnit::DiscreteNumber)
|
||||||
|
.build()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -143,11 +154,8 @@ pub mod tests {
|
||||||
.currency(Currency::INR)
|
.currency(Currency::INR)
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let quantity = QuantityBuilder::default()
|
|
||||||
.number(1)
|
let quantity = Quantity::default();
|
||||||
.unit(QuantityUnit::DiscreteNumber)
|
|
||||||
.build()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// description = None
|
// description = None
|
||||||
let cmd = UnvalidatedAddProductCommandBuilder::default()
|
let cmd = UnvalidatedAddProductCommandBuilder::default()
|
||||||
|
@ -188,11 +196,8 @@ pub mod tests {
|
||||||
.currency(Currency::INR)
|
.currency(Currency::INR)
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let quantity = QuantityBuilder::default()
|
|
||||||
.number(1)
|
let quantity = Quantity::default();
|
||||||
.unit(QuantityUnit::DiscreteNumber)
|
|
||||||
.build()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let cmd = UnvalidatedAddProductCommandBuilder::default()
|
let cmd = UnvalidatedAddProductCommandBuilder::default()
|
||||||
.name(name.into())
|
.name(name.into())
|
||||||
|
@ -233,11 +238,8 @@ pub mod tests {
|
||||||
.currency(Currency::INR)
|
.currency(Currency::INR)
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let quantity = QuantityBuilder::default()
|
|
||||||
.number(1)
|
let quantity = Quantity::default();
|
||||||
.unit(QuantityUnit::DiscreteNumber)
|
|
||||||
.build()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let cmd = UnvalidatedAddProductCommandBuilder::default()
|
let cmd = UnvalidatedAddProductCommandBuilder::default()
|
||||||
.name("".into())
|
.name("".into())
|
||||||
|
|
|
@ -7,7 +7,8 @@ use derive_getters::Getters;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use super::product_aggregate::{Price, Quantity};
|
use super::product_aggregate::Price;
|
||||||
|
use crate::types::quantity::Quantity;
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
Clone, Debug, Builder, Serialize, Deserialize, Getters, Eq, PartialEq, Ord, PartialOrd,
|
Clone, Debug, Builder, Serialize, Deserialize, Getters, Eq, PartialEq, Ord, PartialOrd,
|
||||||
|
|
|
@ -15,54 +15,7 @@ use uuid::Uuid;
|
||||||
use super::{commands::InventoryCommand, events::InventoryEvent};
|
use super::{commands::InventoryCommand, events::InventoryEvent};
|
||||||
use crate::inventory::application::services::errors::*;
|
use crate::inventory::application::services::errors::*;
|
||||||
use crate::inventory::application::services::InventoryServicesInterface;
|
use crate::inventory::application::services::InventoryServicesInterface;
|
||||||
|
use crate::types::quantity::Quantity;
|
||||||
#[derive(Clone, Display, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd)]
|
|
||||||
pub enum QuantityUnit {
|
|
||||||
#[display(fmt = "{}", KILO_GRAM)]
|
|
||||||
Kilogram,
|
|
||||||
#[display(fmt = "{}", GRAM)]
|
|
||||||
Gram,
|
|
||||||
#[display(fmt = "{}", DISCRETE_NUMBER)]
|
|
||||||
DiscreteNumber, // example: 1 sofa, 2 bed, etc.
|
|
||||||
#[display(fmt = "{}", MILLI_LITER)]
|
|
||||||
MilliLiter,
|
|
||||||
#[display(fmt = "{}", LITER)]
|
|
||||||
Liter,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for QuantityUnit {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::DiscreteNumber
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const KILO_GRAM: &str = "kg";
|
|
||||||
const GRAM: &str = "g";
|
|
||||||
const DISCRETE_NUMBER: &str = "discrete_number";
|
|
||||||
const MILLI_LITER: &str = "ml";
|
|
||||||
const LITER: &str = "l";
|
|
||||||
|
|
||||||
impl FromStr for QuantityUnit {
|
|
||||||
type Err = String;
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
match s.trim() {
|
|
||||||
KILO_GRAM => Ok(Self::Kilogram),
|
|
||||||
GRAM => Ok(Self::Gram),
|
|
||||||
DISCRETE_NUMBER => Ok(Self::DiscreteNumber),
|
|
||||||
MILLI_LITER => Ok(Self::MilliLiter),
|
|
||||||
LITER => Ok(Self::Liter),
|
|
||||||
_ => Err("Currency unsupported".into()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(
|
|
||||||
Clone, Debug, Serialize, Default, Deserialize, Eq, PartialEq, Ord, PartialOrd, Builder, Getters,
|
|
||||||
)]
|
|
||||||
pub struct Quantity {
|
|
||||||
number: usize,
|
|
||||||
unit: QuantityUnit,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Display, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd)]
|
#[derive(Clone, Display, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
pub enum Currency {
|
pub enum Currency {
|
||||||
|
@ -250,29 +203,4 @@ mod aggregate_tests {
|
||||||
fn currency_to_string_from_str() {
|
fn currency_to_string_from_str() {
|
||||||
assert!(test_helper(Currency::INR, INR));
|
assert!(test_helper(Currency::INR, INR));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn quantity_unit_kilogram() {
|
|
||||||
assert!(test_helper(QuantityUnit::Kilogram, KILO_GRAM));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn quantity_unit_gram() {
|
|
||||||
assert!(test_helper(QuantityUnit::Gram, GRAM));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn quantity_unit_discrete_number() {
|
|
||||||
assert!(test_helper(QuantityUnit::DiscreteNumber, DISCRETE_NUMBER));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn quantity_unit_milli_liter() {
|
|
||||||
assert!(test_helper(QuantityUnit::MilliLiter, MILLI_LITER));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn quantity_unit_liter() {
|
|
||||||
assert!(test_helper(QuantityUnit::Liter, LITER));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use super::product_aggregate::Quantity;
|
use crate::types::quantity::Quantity;
|
||||||
|
|
||||||
// stock keeping unit
|
// stock keeping unit
|
||||||
// TODO: will implement later, have to figure out how to print SKU label and during billing.
|
// TODO: will implement later, have to figure out how to print SKU label and during billing.
|
||||||
|
|
|
@ -10,7 +10,8 @@ use derive_more::{Display, Error};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use super::product_aggregate::{Price, Product, Quantity};
|
use super::product_aggregate::{Price, Product};
|
||||||
|
use crate::types::quantity::Quantity;
|
||||||
|
|
||||||
#[derive(Debug, Error, Display, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Error, Display, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub enum UpdateProductCommandError {
|
pub enum UpdateProductCommandError {
|
||||||
|
@ -92,10 +93,9 @@ impl UnvalidatedUpdateProductCommand {
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
use crate::types::quantity::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
inventory::domain::product_aggregate::{
|
inventory::domain::product_aggregate::{Currency, PriceBuilder},
|
||||||
Currency, PriceBuilder, QuantityBuilder, QuantityUnit,
|
|
||||||
},
|
|
||||||
utils::uuid::tests::UUID,
|
utils::uuid::tests::UUID,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -115,8 +115,20 @@ pub mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let quantity = QuantityBuilder::default()
|
let quantity = QuantityBuilder::default()
|
||||||
.number(1)
|
.minor(
|
||||||
.unit(QuantityUnit::DiscreteNumber)
|
QuantityPartBuilder::default()
|
||||||
|
.number(0)
|
||||||
|
.unit(QuantityUnit::DiscreteNumber)
|
||||||
|
.build()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.major(
|
||||||
|
QuantityPartBuilder::default()
|
||||||
|
.number(1)
|
||||||
|
.unit(QuantityUnit::DiscreteNumber)
|
||||||
|
.build()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -149,11 +161,8 @@ pub mod tests {
|
||||||
.currency(Currency::INR)
|
.currency(Currency::INR)
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let quantity = QuantityBuilder::default()
|
|
||||||
.number(1)
|
let quantity = Quantity::default();
|
||||||
.unit(QuantityUnit::DiscreteNumber)
|
|
||||||
.build()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// description = None
|
// description = None
|
||||||
let cmd = UnvalidatedUpdateProductCommandBuilder::default()
|
let cmd = UnvalidatedUpdateProductCommandBuilder::default()
|
||||||
|
@ -196,11 +205,8 @@ pub mod tests {
|
||||||
.currency(Currency::INR)
|
.currency(Currency::INR)
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let quantity = QuantityBuilder::default()
|
|
||||||
.number(1)
|
let quantity = Quantity::default();
|
||||||
.unit(QuantityUnit::DiscreteNumber)
|
|
||||||
.build()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let cmd = UnvalidatedUpdateProductCommandBuilder::default()
|
let cmd = UnvalidatedUpdateProductCommandBuilder::default()
|
||||||
.name(name.into())
|
.name(name.into())
|
||||||
|
@ -242,11 +248,8 @@ pub mod tests {
|
||||||
.currency(Currency::INR)
|
.currency(Currency::INR)
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let quantity = QuantityBuilder::default()
|
|
||||||
.number(1)
|
let quantity = Quantity::default();
|
||||||
.unit(QuantityUnit::DiscreteNumber)
|
|
||||||
.build()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let cmd = UnvalidatedUpdateProductCommandBuilder::default()
|
let cmd = UnvalidatedUpdateProductCommandBuilder::default()
|
||||||
.name("".into())
|
.name("".into())
|
||||||
|
|
|
@ -17,6 +17,7 @@ mod ordering;
|
||||||
mod settings;
|
mod settings;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
mod types;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
#[actix_web::main]
|
#[actix_web::main]
|
||||||
|
|
1
src/types/mod.rs
Normal file
1
src/types/mod.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pub mod quantity;
|
108
src/types/quantity.rs
Normal file
108
src/types/quantity.rs
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use derive_builder::Builder;
|
||||||
|
use derive_getters::Getters;
|
||||||
|
use derive_more::Display;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(
|
||||||
|
Clone, Default, Display, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd,
|
||||||
|
)]
|
||||||
|
pub enum QuantityUnit {
|
||||||
|
#[display(fmt = "{}", KILO_GRAM)]
|
||||||
|
Kilogram,
|
||||||
|
#[display(fmt = "{}", GRAM)]
|
||||||
|
Gram,
|
||||||
|
#[default]
|
||||||
|
#[display(fmt = "{}", DISCRETE_NUMBER)]
|
||||||
|
DiscreteNumber, // example: 1 sofa, 2 bed, etc.
|
||||||
|
#[display(fmt = "{}", MILLI_LITER)]
|
||||||
|
MilliLiter,
|
||||||
|
#[display(fmt = "{}", LITER)]
|
||||||
|
Liter,
|
||||||
|
}
|
||||||
|
|
||||||
|
const KILO_GRAM: &str = "kg";
|
||||||
|
const GRAM: &str = "g";
|
||||||
|
const DISCRETE_NUMBER: &str = "discrete_number";
|
||||||
|
const MILLI_LITER: &str = "ml";
|
||||||
|
const LITER: &str = "l";
|
||||||
|
|
||||||
|
impl FromStr for QuantityUnit {
|
||||||
|
type Err = String;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s.trim() {
|
||||||
|
KILO_GRAM => Ok(Self::Kilogram),
|
||||||
|
GRAM => Ok(Self::Gram),
|
||||||
|
DISCRETE_NUMBER => Ok(Self::DiscreteNumber),
|
||||||
|
MILLI_LITER => Ok(Self::MilliLiter),
|
||||||
|
LITER => Ok(Self::Liter),
|
||||||
|
_ => Err("Currency unsupported".into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(
|
||||||
|
Clone, Debug, Default, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Builder, Getters,
|
||||||
|
)]
|
||||||
|
pub struct QuantityPart {
|
||||||
|
number: usize,
|
||||||
|
unit: QuantityUnit,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(
|
||||||
|
Clone, Default, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Builder, Getters,
|
||||||
|
)]
|
||||||
|
pub struct Quantity {
|
||||||
|
minor: QuantityPart,
|
||||||
|
major: QuantityPart,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn test_helper<T>(t: T, str_value: &str) -> bool
|
||||||
|
where
|
||||||
|
T: ToString + FromStr + std::fmt::Debug + PartialEq,
|
||||||
|
<T as FromStr>::Err: std::fmt::Debug,
|
||||||
|
{
|
||||||
|
println!("Testing type: {:?} against value {str_value}", t);
|
||||||
|
assert_eq!(t.to_string(), str_value.to_string());
|
||||||
|
|
||||||
|
assert_eq!(T::from_str(str_value).unwrap(), t);
|
||||||
|
|
||||||
|
assert_eq!(T::from_str(t.to_string().as_str()).unwrap(), t,);
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn quantity_unit_kilogram() {
|
||||||
|
assert!(test_helper(QuantityUnit::Kilogram, KILO_GRAM));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn quantity_unit_gram() {
|
||||||
|
assert!(test_helper(QuantityUnit::Gram, GRAM));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn quantity_unit_discrete_number() {
|
||||||
|
assert!(test_helper(QuantityUnit::DiscreteNumber, DISCRETE_NUMBER));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn quantity_unit_milli_liter() {
|
||||||
|
assert!(test_helper(QuantityUnit::MilliLiter, MILLI_LITER));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn quantity_unit_liter() {
|
||||||
|
assert!(test_helper(QuantityUnit::Liter, LITER));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue