Skip to main content

domain/retail/
reorder.rs

1//! Reorder models for stock-threshold decisions and manager/vendor workflow creation.
2
3use serde::{Deserialize, Serialize};
4
5use crate::entities::LocationId;
6use crate::policy;
7
8use super::inventory::Position;
9use super::product::Sku;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
12/// Reorder policy deciding whether low stock creates a manager review, staff task, or vendor notice.
13pub enum Policy {
14    /// Low-stock findings stop for manager review instead of creating automatic vendor action.
15    ManualReview,
16    /// Low-stock findings create a staff/manager task for human ordering follow-up.
17    AutoCreateManagerTask,
18    /// Low-stock findings create a vendor-managed notice but do not place an order.
19    VendorManaged,
20}
21
22impl Policy {
23    /// Evaluates an inventory position against the policy and emits only threshold-backed reorder actions.
24    pub fn evaluate(&self, position: &Position) -> Decision {
25        if !position.is_at_or_below_reorder_threshold() {
26            return Decision::NoAction;
27        }
28        match self {
29            Self::ManualReview => Decision::ManagerReviewRequired {
30                reason: Reason::AtOrBelowThreshold,
31                gate: policy::ReviewGate::ManagerApproval,
32            },
33            Self::AutoCreateManagerTask => Decision::CreateStaffTask {
34                location_id: position.location_id,
35                sku: position.sku().clone(),
36                reason: Reason::AtOrBelowThreshold,
37                gate: policy::ReviewGate::ManagerApproval,
38            },
39            Self::VendorManaged => Decision::VendorManagedNotice {
40                sku: position.sku().clone(),
41                reason: Reason::AtOrBelowThreshold,
42            },
43        }
44    }
45}
46
47#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
48/// Reorder decision produced when available units are at or below threshold.
49pub enum Decision {
50    /// Available stock remains above threshold, so no staff or vendor follow-up is needed.
51    NoAction,
52    /// Creates a human task with location, SKU, reason, and manager approval gate for reorder follow-up.
53    CreateStaffTask {
54        /// Location where staff should inspect stock or complete the reorder task.
55        location_id: LocationId,
56        /// SKU that fell to or below the reorder threshold.
57        sku: Sku,
58        /// Reorder reason shown to staff or managers before purchasing or vendor follow-up.
59        reason: Reason,
60        /// Manager approval gate required before staff treat the reorder task as authorized.
61        gate: policy::ReviewGate,
62    },
63    /// Low-stock finding requires manager approval before any purchasing or vendor action.
64    ManagerReviewRequired {
65        /// Reorder reason shown to staff or managers before purchasing or vendor follow-up.
66        reason: Reason,
67        /// Manager approval gate required before staff treat the reorder task as authorized.
68        gate: policy::ReviewGate,
69    },
70    /// Vendor-managed item produces a notice for review rather than an automatic order.
71    VendorManagedNotice {
72        /// SKU that fell to or below the reorder threshold.
73        sku: Sku,
74        /// Reorder reason shown to staff or managers before purchasing or vendor follow-up.
75        reason: Reason,
76    },
77}
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
80/// Business reason explaining why reorder action or vendor notice is needed.
81pub enum Reason {
82    /// Available stock is at or below the configured threshold for this SKU.
83    AtOrBelowThreshold,
84    /// Vendor reports the SKU is backordered, so staff can plan substitutes or waitlist notes.
85    VendorBackorder,
86    /// Upcoming boarding diet demand may deplete stock and should prompt manager review.
87    ForecastedBoardingDietDepletion,
88}