datasynth_core/models/sales_quote.rs
1//! Sales quote models for the Quote-to-Cash process.
2//!
3//! These models represent sales quotations and their line items,
4//! supporting the full quote lifecycle from draft through win/loss.
5
6use chrono::NaiveDate;
7use rust_decimal::Decimal;
8use serde::{Deserialize, Serialize};
9
10/// Status of a sales quote through the quotation lifecycle.
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
12#[serde(rename_all = "snake_case")]
13pub enum QuoteStatus {
14 /// Initial draft, not yet sent to customer
15 #[default]
16 Draft,
17 /// Quote has been sent to the customer
18 Sent,
19 /// Quote is under active negotiation
20 Negotiating,
21 /// Customer accepted the quote
22 Won,
23 /// Customer rejected the quote
24 Lost,
25 /// Quote validity period has elapsed
26 Expired,
27 /// Quote was cancelled before resolution
28 Cancelled,
29}
30
31/// A sales quotation issued to a prospective or existing customer.
32#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct SalesQuote {
34 /// Unique quote identifier
35 pub quote_id: String,
36 /// Company code issuing the quote
37 pub company_code: String,
38 /// Customer identifier
39 pub customer_id: String,
40 /// Customer name
41 pub customer_name: String,
42 /// Date the quote was created
43 pub quote_date: NaiveDate,
44 /// Date the quote expires
45 pub valid_until: NaiveDate,
46 /// Current status of the quote
47 pub status: QuoteStatus,
48 /// Individual line items on the quote
49 pub line_items: Vec<QuoteLineItem>,
50 /// Total quoted amount before discount
51 #[serde(with = "rust_decimal::serde::str")]
52 pub total_amount: Decimal,
53 /// Currency code (e.g., USD, EUR)
54 pub currency: String,
55 /// Discount percentage applied (0.0 to 1.0)
56 pub discount_percent: f64,
57 /// Calculated discount amount
58 #[serde(with = "rust_decimal::serde::str")]
59 pub discount_amount: Decimal,
60 /// Sales representative responsible for the quote
61 pub sales_rep_id: Option<String>,
62 /// Linked sales order identifier (populated when status is Won)
63 pub sales_order_id: Option<String>,
64 /// Reason the quote was lost (populated when status is Lost)
65 pub lost_reason: Option<String>,
66 /// Free-text notes on the quote
67 pub notes: Option<String>,
68}
69
70/// An individual line item within a sales quote.
71#[derive(Debug, Clone, Serialize, Deserialize)]
72pub struct QuoteLineItem {
73 /// Sequential item number within the quote
74 pub item_number: u32,
75 /// Material or product identifier
76 pub material_id: String,
77 /// Description of the quoted item
78 pub description: String,
79 /// Quoted quantity
80 #[serde(with = "rust_decimal::serde::str")]
81 pub quantity: Decimal,
82 /// Unit price for the item
83 #[serde(with = "rust_decimal::serde::str")]
84 pub unit_price: Decimal,
85 /// Total line amount (quantity * unit_price)
86 #[serde(with = "rust_decimal::serde::str")]
87 pub line_amount: Decimal,
88}