Skip to main content

stateset_embedded/
analytics.rs

1//! Analytics and forecasting operations
2
3use rust_decimal::Decimal;
4use stateset_core::{
5    AnalyticsQuery, CustomerMetrics, DemandForecast, FulfillmentMetrics, InventoryHealth,
6    InventoryMovement, LowStockItem, OrderStatusBreakdown, ProductPerformance, Result,
7    ReturnMetrics, RevenueByPeriod, RevenueForecast, SalesSummary, TimeGranularity, TopCustomer,
8    TopProduct,
9};
10use stateset_db::Database;
11use std::sync::Arc;
12
13/// Analytics operations interface.
14///
15/// Provides sales analytics, inventory forecasting, and business intelligence.
16///
17/// # Example
18///
19/// ```rust,no_run
20/// use stateset_embedded::{Commerce, AnalyticsQuery, TimePeriod};
21///
22/// let commerce = Commerce::new("./store.db")?;
23///
24/// // Get sales summary for last 30 days
25/// let summary = commerce.analytics().sales_summary(
26///     AnalyticsQuery::new().period(TimePeriod::Last30Days)
27/// )?;
28/// println!("Revenue: ${}", summary.total_revenue);
29///
30/// // Get top selling products
31/// let top_products = commerce.analytics().top_products(
32///     AnalyticsQuery::new().period(TimePeriod::ThisMonth).limit(10)
33/// )?;
34///
35/// // Get demand forecast
36/// let forecasts = commerce.analytics().demand_forecast(None, 30)?;
37/// # Ok::<(), stateset_embedded::CommerceError>(())
38/// ```
39pub struct Analytics {
40    db: Arc<dyn Database>,
41}
42
43impl std::fmt::Debug for Analytics {
44    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45        f.debug_struct("Analytics").finish_non_exhaustive()
46    }
47}
48
49impl Analytics {
50    pub(crate) fn new(db: Arc<dyn Database>) -> Self {
51        Self { db }
52    }
53
54    // ========================================================================
55    // Sales Analytics
56    // ========================================================================
57
58    /// Get sales summary for a time period.
59    ///
60    /// Returns total revenue, order count, average order value, and more.
61    ///
62    /// # Example
63    ///
64    /// ```rust,no_run
65    /// # use stateset_embedded::*;
66    /// # let commerce = Commerce::new(":memory:")?;
67    /// let summary = commerce.analytics().sales_summary(
68    ///     AnalyticsQuery::new().period(TimePeriod::Last30Days)
69    /// )?;
70    /// println!("Revenue: ${}", summary.total_revenue);
71    /// println!("Orders: {}", summary.order_count);
72    /// println!("AOV: ${}", summary.average_order_value);
73    /// # Ok::<(), CommerceError>(())
74    /// ```
75    pub fn sales_summary(&self, query: AnalyticsQuery) -> Result<SalesSummary> {
76        self.db.analytics().get_sales_summary(query)
77    }
78
79    /// Get revenue broken down by time periods.
80    ///
81    /// # Example
82    ///
83    /// ```rust,no_run
84    /// # use stateset_embedded::*;
85    /// # let commerce = Commerce::new(":memory:")?;
86    /// let revenue = commerce.analytics().revenue_by_period(
87    ///     AnalyticsQuery::new()
88    ///         .period(TimePeriod::Last30Days)
89    ///         .granularity(TimeGranularity::Day)
90    /// )?;
91    /// for day in revenue {
92    ///     println!("{}: ${}", day.period, day.revenue);
93    /// }
94    /// # Ok::<(), CommerceError>(())
95    /// ```
96    pub fn revenue_by_period(&self, query: AnalyticsQuery) -> Result<Vec<RevenueByPeriod>> {
97        self.db.analytics().get_revenue_by_period(query)
98    }
99
100    // ========================================================================
101    // Product Analytics
102    // ========================================================================
103
104    /// Get top selling products.
105    ///
106    /// # Example
107    ///
108    /// ```rust,no_run
109    /// # use stateset_embedded::*;
110    /// # let commerce = Commerce::new(":memory:")?;
111    /// let top = commerce.analytics().top_products(
112    ///     AnalyticsQuery::new()
113    ///         .period(TimePeriod::ThisMonth)
114    ///         .limit(10)
115    /// )?;
116    /// for product in top {
117    ///     println!("{}: {} units, ${}", product.name, product.units_sold, product.revenue);
118    /// }
119    /// # Ok::<(), CommerceError>(())
120    /// ```
121    pub fn top_products(&self, query: AnalyticsQuery) -> Result<Vec<TopProduct>> {
122        self.db.analytics().get_top_products(query)
123    }
124
125    /// Get product performance with period comparison.
126    pub fn product_performance(&self, query: AnalyticsQuery) -> Result<Vec<ProductPerformance>> {
127        self.db.analytics().get_product_performance(query)
128    }
129
130    // ========================================================================
131    // Customer Analytics
132    // ========================================================================
133
134    /// Get customer metrics.
135    ///
136    /// # Example
137    ///
138    /// ```rust,no_run
139    /// # use stateset_embedded::*;
140    /// # let commerce = Commerce::new(":memory:")?;
141    /// let metrics = commerce.analytics().customer_metrics(
142    ///     AnalyticsQuery::new().period(TimePeriod::ThisMonth)
143    /// )?;
144    /// println!("Total customers: {}", metrics.total_customers);
145    /// println!("New this month: {}", metrics.new_customers);
146    /// println!("Avg LTV: ${}", metrics.average_lifetime_value);
147    /// # Ok::<(), CommerceError>(())
148    /// ```
149    pub fn customer_metrics(&self, query: AnalyticsQuery) -> Result<CustomerMetrics> {
150        self.db.analytics().get_customer_metrics(query)
151    }
152
153    /// Get top customers by spend.
154    ///
155    /// # Example
156    ///
157    /// ```rust,no_run
158    /// # use stateset_embedded::*;
159    /// # let commerce = Commerce::new(":memory:")?;
160    /// let top = commerce.analytics().top_customers(
161    ///     AnalyticsQuery::new().period(TimePeriod::AllTime).limit(10)
162    /// )?;
163    /// for customer in top {
164    ///     println!("{}: {} orders, ${}", customer.name, customer.order_count, customer.total_spent);
165    /// }
166    /// # Ok::<(), CommerceError>(())
167    /// ```
168    pub fn top_customers(&self, query: AnalyticsQuery) -> Result<Vec<TopCustomer>> {
169        self.db.analytics().get_top_customers(query)
170    }
171
172    // ========================================================================
173    // Inventory Analytics
174    // ========================================================================
175
176    /// Get inventory health summary.
177    ///
178    /// # Example
179    ///
180    /// ```rust,no_run
181    /// # use stateset_embedded::*;
182    /// # let commerce = Commerce::new(":memory:")?;
183    /// let health = commerce.analytics().inventory_health()?;
184    /// println!("Total SKUs: {}", health.total_skus);
185    /// println!("Low stock: {}", health.low_stock_skus);
186    /// println!("Out of stock: {}", health.out_of_stock_skus);
187    /// # Ok::<(), CommerceError>(())
188    /// ```
189    pub fn inventory_health(&self) -> Result<InventoryHealth> {
190        self.db.analytics().get_inventory_health()
191    }
192
193    /// Get low stock items.
194    ///
195    /// # Example
196    ///
197    /// ```rust,no_run
198    /// # use stateset_embedded::*;
199    /// # use rust_decimal_macros::dec;
200    /// # let commerce = Commerce::new(":memory:")?;
201    /// let low_stock = commerce.analytics().low_stock_items(Some(dec!(20)))?;
202    /// for item in low_stock {
203    ///     println!("{}: {} available", item.sku, item.available);
204    /// }
205    /// # Ok::<(), CommerceError>(())
206    /// ```
207    pub fn low_stock_items(&self, threshold: Option<Decimal>) -> Result<Vec<LowStockItem>> {
208        self.db.analytics().get_low_stock_items(threshold)
209    }
210
211    /// Get inventory movement summary.
212    pub fn inventory_movement(&self, query: AnalyticsQuery) -> Result<Vec<InventoryMovement>> {
213        self.db.analytics().get_inventory_movement(query)
214    }
215
216    // ========================================================================
217    // Order Analytics
218    // ========================================================================
219
220    /// Get order status breakdown.
221    ///
222    /// # Example
223    ///
224    /// ```rust,no_run
225    /// # use stateset_embedded::*;
226    /// # let commerce = Commerce::new(":memory:")?;
227    /// let breakdown = commerce.analytics().order_status_breakdown(
228    ///     AnalyticsQuery::new().period(TimePeriod::Last30Days)
229    /// )?;
230    /// println!("Pending: {}", breakdown.pending);
231    /// println!("Shipped: {}", breakdown.shipped);
232    /// println!("Delivered: {}", breakdown.delivered);
233    /// # Ok::<(), CommerceError>(())
234    /// ```
235    pub fn order_status_breakdown(&self, query: AnalyticsQuery) -> Result<OrderStatusBreakdown> {
236        self.db.analytics().get_order_status_breakdown(query)
237    }
238
239    /// Get fulfillment metrics.
240    pub fn fulfillment_metrics(&self, query: AnalyticsQuery) -> Result<FulfillmentMetrics> {
241        self.db.analytics().get_fulfillment_metrics(query)
242    }
243
244    // ========================================================================
245    // Return Analytics
246    // ========================================================================
247
248    /// Get return metrics.
249    ///
250    /// # Example
251    ///
252    /// ```rust,no_run
253    /// # use stateset_embedded::*;
254    /// # let commerce = Commerce::new(":memory:")?;
255    /// let metrics = commerce.analytics().return_metrics(
256    ///     AnalyticsQuery::new().period(TimePeriod::ThisMonth)
257    /// )?;
258    /// println!("Returns: {}", metrics.total_returns);
259    /// println!("Return rate: {}%", metrics.return_rate_percent);
260    /// # Ok::<(), CommerceError>(())
261    /// ```
262    pub fn return_metrics(&self, query: AnalyticsQuery) -> Result<ReturnMetrics> {
263        self.db.analytics().get_return_metrics(query)
264    }
265
266    // ========================================================================
267    // Forecasting
268    // ========================================================================
269
270    /// Get demand forecast for inventory items.
271    ///
272    /// Predicts future demand based on historical sales data.
273    ///
274    /// # Arguments
275    ///
276    /// * `skus` - Optional list of SKUs to forecast. If None, forecasts all items.
277    /// * `days_ahead` - Number of days to forecast ahead.
278    ///
279    /// # Example
280    ///
281    /// ```rust,no_run
282    /// # use stateset_embedded::*;
283    /// # let commerce = Commerce::new(":memory:")?;
284    /// // Forecast for all items
285    /// let forecasts = commerce.analytics().demand_forecast(None, 30)?;
286    /// for f in forecasts {
287    ///     println!("{}: {} units/day, {} days until stockout",
288    ///         f.sku,
289    ///         f.average_daily_demand,
290    ///         f.days_until_stockout.unwrap_or(999)
291    ///     );
292    /// }
293    ///
294    /// // Forecast for specific SKUs
295    /// let forecasts = commerce.analytics().demand_forecast(
296    ///     Some(vec!["SKU-001".to_string(), "SKU-002".to_string()]),
297    ///     14
298    /// )?;
299    /// # Ok::<(), CommerceError>(())
300    /// ```
301    pub fn demand_forecast(
302        &self,
303        skus: Option<Vec<String>>,
304        days_ahead: u32,
305    ) -> Result<Vec<DemandForecast>> {
306        self.db.analytics().get_demand_forecast(skus, days_ahead)
307    }
308
309    /// Get revenue forecast.
310    ///
311    /// Predicts future revenue based on historical trends.
312    ///
313    /// # Arguments
314    ///
315    /// * `periods_ahead` - Number of periods to forecast.
316    /// * `granularity` - Time granularity (Day, Week, Month).
317    ///
318    /// # Example
319    ///
320    /// ```rust,no_run
321    /// # use stateset_embedded::*;
322    /// # let commerce = Commerce::new(":memory:")?;
323    /// let forecasts = commerce.analytics().revenue_forecast(3, TimeGranularity::Month)?;
324    /// for f in forecasts {
325    ///     println!("{}: ${} (${} - ${})",
326    ///         f.period,
327    ///         f.forecasted_revenue,
328    ///         f.lower_bound,
329    ///         f.upper_bound
330    ///     );
331    /// }
332    /// # Ok::<(), CommerceError>(())
333    /// ```
334    pub fn revenue_forecast(
335        &self,
336        periods_ahead: u32,
337        granularity: TimeGranularity,
338    ) -> Result<Vec<RevenueForecast>> {
339        self.db.analytics().get_revenue_forecast(periods_ahead, granularity)
340    }
341}