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}