use chrono::{DateTime, Utc};
use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
use strum::{Display, EnumString};
use uuid::Uuid;
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Display, EnumString, Serialize, Deserialize, Default,
)]
#[strum(serialize_all = "snake_case", ascii_case_insensitive)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum WarehouseType {
#[default]
Distribution,
Manufacturing,
Retail,
#[strum(serialize = "third_party", serialize = "thirdparty")]
ThirdParty,
Consignment,
Returns,
}
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Display, EnumString, Serialize, Deserialize, Default,
)]
#[strum(serialize_all = "snake_case", ascii_case_insensitive)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum LocationType {
#[default]
Bulk,
Pick,
Staging,
Receiving,
Shipping,
Quarantine,
Returns,
Production,
Packing,
#[strum(serialize = "cross_dock", serialize = "crossdock")]
CrossDock,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub struct WarehouseAddress {
pub street1: String,
pub street2: Option<String>,
pub city: String,
pub state: String,
pub postal_code: String,
pub country: String,
pub phone: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct Warehouse {
pub id: i32,
pub code: String,
pub name: String,
pub warehouse_type: WarehouseType,
pub address: WarehouseAddress,
pub timezone: Option<String>,
pub is_active: bool,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub struct CreateWarehouse {
pub code: String,
pub name: String,
pub warehouse_type: WarehouseType,
pub address: WarehouseAddress,
pub timezone: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub struct UpdateWarehouse {
pub name: Option<String>,
pub warehouse_type: Option<WarehouseType>,
pub address: Option<WarehouseAddress>,
pub timezone: Option<String>,
pub is_active: Option<bool>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct WarehouseFilter {
pub warehouse_type: Option<WarehouseType>,
pub is_active: Option<bool>,
pub limit: Option<u32>,
pub offset: Option<u32>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct Location {
pub id: i32,
pub warehouse_id: i32,
pub code: String,
pub location_type: LocationType,
pub zone: Option<String>,
pub aisle: Option<String>,
pub rack: Option<String>,
pub level: Option<String>,
pub bin: Option<String>,
pub max_weight_kg: Option<Decimal>,
pub max_volume_m3: Option<Decimal>,
pub current_weight_kg: Option<Decimal>,
pub current_volume_m3: Option<Decimal>,
pub is_pickable: bool,
pub is_receivable: bool,
pub is_active: bool,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub struct CreateLocation {
pub warehouse_id: i32,
pub code: Option<String>,
pub location_type: LocationType,
pub zone: Option<String>,
pub aisle: Option<String>,
pub rack: Option<String>,
pub level: Option<String>,
pub bin: Option<String>,
pub max_weight_kg: Option<Decimal>,
pub max_volume_m3: Option<Decimal>,
pub is_pickable: Option<bool>,
pub is_receivable: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub struct UpdateLocation {
pub location_type: Option<LocationType>,
pub zone: Option<String>,
pub aisle: Option<String>,
pub rack: Option<String>,
pub level: Option<String>,
pub bin: Option<String>,
pub max_weight_kg: Option<Decimal>,
pub max_volume_m3: Option<Decimal>,
pub is_pickable: Option<bool>,
pub is_receivable: Option<bool>,
pub is_active: Option<bool>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct LocationFilter {
pub warehouse_id: Option<i32>,
pub location_type: Option<LocationType>,
pub zone: Option<String>,
pub aisle: Option<String>,
pub is_pickable: Option<bool>,
pub is_receivable: Option<bool>,
pub is_active: Option<bool>,
pub has_capacity: Option<bool>,
pub limit: Option<u32>,
pub offset: Option<u32>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct LocationInventory {
pub location_id: i32,
pub sku: String,
pub lot_id: Option<Uuid>,
pub quantity_on_hand: Decimal,
pub quantity_reserved: Decimal,
pub quantity_available: Decimal,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct AdjustLocationInventory {
pub location_id: i32,
pub sku: String,
pub lot_id: Option<Uuid>,
pub quantity: Decimal,
pub reason: String,
pub reference_type: Option<String>,
pub reference_id: Option<Uuid>,
pub performed_by: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct MoveInventory {
pub from_location_id: i32,
pub to_location_id: i32,
pub sku: String,
pub lot_id: Option<Uuid>,
pub quantity: Decimal,
pub reason: Option<String>,
pub performed_by: Option<String>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct LocationInventoryFilter {
pub location_id: Option<i32>,
pub warehouse_id: Option<i32>,
pub sku: Option<String>,
pub lot_id: Option<Uuid>,
pub has_quantity: Option<bool>,
pub limit: Option<u32>,
pub offset: Option<u32>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct LocationMovement {
pub id: Uuid,
pub movement_type: MovementType,
pub from_location_id: Option<i32>,
pub to_location_id: Option<i32>,
pub sku: String,
pub lot_id: Option<Uuid>,
pub quantity: Decimal,
pub reference_type: Option<String>,
pub reference_id: Option<Uuid>,
pub reason: Option<String>,
pub performed_by: Option<String>,
pub created_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum MovementType {
Receipt,
Transfer,
Pick,
Adjustment,
Shipment,
Return,
}
impl std::fmt::Display for MovementType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Receipt => write!(f, "receipt"),
Self::Transfer => write!(f, "transfer"),
Self::Pick => write!(f, "pick"),
Self::Adjustment => write!(f, "adjustment"),
Self::Shipment => write!(f, "shipment"),
Self::Return => write!(f, "return"),
}
}
}
impl std::str::FromStr for MovementType {
type Err = crate::CommerceError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"receipt" => Ok(Self::Receipt),
"transfer" => Ok(Self::Transfer),
"pick" => Ok(Self::Pick),
"adjustment" => Ok(Self::Adjustment),
"shipment" => Ok(Self::Shipment),
"return" => Ok(Self::Return),
_ => {
Err(crate::CommerceError::ValidationError(format!("Invalid movement type: {}", s)))
}
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct MovementFilter {
pub warehouse_id: Option<i32>,
pub location_id: Option<i32>,
pub sku: Option<String>,
pub lot_id: Option<Uuid>,
pub movement_type: Option<MovementType>,
pub from_date: Option<DateTime<Utc>>,
pub to_date: Option<DateTime<Utc>>,
pub limit: Option<u32>,
pub offset: Option<u32>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct Zone {
pub id: i32,
pub warehouse_id: i32,
pub code: String,
pub name: String,
pub description: Option<String>,
pub is_active: bool,
pub created_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub struct CreateZone {
pub warehouse_id: i32,
pub code: String,
pub name: String,
pub description: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub struct UpdateZone {
pub name: Option<String>,
pub description: Option<String>,
pub is_active: Option<bool>,
}
pub type CreateWarehouseLocation = CreateLocation;