stateset_embedded/commerce/accessors.rs
1use super::Commerce;
2
3use crate::{
4 AccountsPayable, AccountsReceivable, Analytics, Backorders, Bom, Carts, CostAccounting, Credit,
5 CurrencyOps, CustomObjects, Customers, Erc8004, Fraud, Fulfillment, GeneralLedger, GiftCards,
6 Inventory, Invoices, Lots, Loyalty, Orders, Payments, Products, Promotions, PurchaseOrders,
7 Quality, Receiving, Returns, Reviews, SearchConfigs, Segments, Serials, Shipments,
8 ShippingZones, StoreCredits, Subscriptions, Tax, WarehouseOps, Warranties, Wishlists,
9 WorkOrders, X402,
10};
11
12impl Commerce {
13 /// Access order operations.
14 ///
15 /// # Example
16 ///
17 /// ```rust,ignore
18 /// use stateset_embedded::{Commerce, CreateOrder, CreateOrderItem};
19 /// use rust_decimal_macros::dec;
20 /// use uuid::Uuid;
21 ///
22 /// let commerce = Commerce::new("./store.db")?;
23 ///
24 /// let order = commerce.orders().create(CreateOrder {
25 /// customer_id: Uuid::new_v4(),
26 /// items: vec![CreateOrderItem {
27 /// product_id: Uuid::new_v4(),
28 /// sku: "SKU-001".into(),
29 /// name: "Widget".into(),
30 /// quantity: 2,
31 /// unit_price: dec!(29.99),
32 /// ..Default::default()
33 /// }],
34 /// ..Default::default()
35 /// })?;
36 /// # Ok::<(), stateset_embedded::CommerceError>(())
37 /// ```
38 #[must_use]
39 pub fn orders(&self) -> Orders {
40 #[cfg(feature = "events")]
41 {
42 Orders::new(self.db.clone(), self.event_system.clone(), self.metrics.clone())
43 }
44 #[cfg(not(feature = "events"))]
45 {
46 Orders::new(self.db.clone(), self.metrics.clone())
47 }
48 }
49
50 /// Access inventory operations.
51 ///
52 /// # Example
53 ///
54 /// ```rust,ignore
55 /// use stateset_embedded::{Commerce, CreateInventoryItem};
56 /// use rust_decimal_macros::dec;
57 ///
58 /// let commerce = Commerce::new("./store.db")?;
59 ///
60 /// // Create inventory item
61 /// commerce.inventory().create_item(CreateInventoryItem {
62 /// sku: "SKU-001".into(),
63 /// name: "Widget".into(),
64 /// initial_quantity: Some(dec!(100)),
65 /// ..Default::default()
66 /// })?;
67 ///
68 /// // Check stock
69 /// let stock = commerce.inventory().get_stock("SKU-001")?;
70 ///
71 /// // Adjust stock
72 /// commerce.inventory().adjust("SKU-001", dec!(-5), "Sold")?;
73 /// # Ok::<(), stateset_embedded::CommerceError>(())
74 /// ```
75 #[must_use]
76 pub fn inventory(&self) -> Inventory {
77 #[cfg(feature = "events")]
78 {
79 Inventory::new(self.db.clone(), self.event_system.clone(), self.metrics.clone())
80 }
81 #[cfg(not(feature = "events"))]
82 {
83 Inventory::new(self.db.clone(), self.metrics.clone())
84 }
85 }
86
87 /// Access customer operations.
88 ///
89 /// # Example
90 ///
91 /// ```rust,ignore
92 /// use stateset_embedded::{Commerce, CreateCustomer};
93 ///
94 /// let commerce = Commerce::new("./store.db")?;
95 ///
96 /// let customer = commerce.customers().create(CreateCustomer {
97 /// email: "alice@example.com".into(),
98 /// first_name: "Alice".into(),
99 /// last_name: "Smith".into(),
100 /// ..Default::default()
101 /// })?;
102 /// # Ok::<(), stateset_embedded::CommerceError>(())
103 /// ```
104 #[must_use]
105 pub fn customers(&self) -> Customers {
106 #[cfg(feature = "events")]
107 {
108 Customers::new(self.db.clone(), self.event_system.clone(), self.metrics.clone())
109 }
110 #[cfg(not(feature = "events"))]
111 {
112 Customers::new(self.db.clone(), self.metrics.clone())
113 }
114 }
115
116 /// Access product operations.
117 ///
118 /// # Example
119 ///
120 /// ```rust,ignore
121 /// use stateset_embedded::{Commerce, CreateProduct, CreateProductVariant};
122 /// use rust_decimal_macros::dec;
123 ///
124 /// let commerce = Commerce::new("./store.db")?;
125 ///
126 /// let product = commerce.products().create(CreateProduct {
127 /// name: "Premium Widget".into(),
128 /// description: Some("A high-quality widget".into()),
129 /// variants: Some(vec![CreateProductVariant {
130 /// sku: "WIDGET-001".into(),
131 /// price: dec!(49.99),
132 /// ..Default::default()
133 /// }]),
134 /// ..Default::default()
135 /// })?;
136 /// # Ok::<(), stateset_embedded::CommerceError>(())
137 /// ```
138 #[must_use]
139 pub fn products(&self) -> Products {
140 #[cfg(feature = "events")]
141 {
142 Products::new(self.db.clone(), self.event_system.clone(), self.metrics.clone())
143 }
144 #[cfg(not(feature = "events"))]
145 {
146 Products::new(self.db.clone(), self.metrics.clone())
147 }
148 }
149
150 /// Access custom objects (custom states / metaobjects) operations.
151 #[must_use]
152 pub fn custom_objects(&self) -> CustomObjects {
153 #[cfg(feature = "events")]
154 {
155 CustomObjects::new(self.db.clone(), self.event_system.clone())
156 }
157 #[cfg(not(feature = "events"))]
158 {
159 CustomObjects::new(self.db.clone())
160 }
161 }
162
163 /// Alias for `custom_objects()` (for users who prefer the "custom states" name).
164 #[must_use]
165 pub fn custom_states(&self) -> CustomObjects {
166 self.custom_objects()
167 }
168
169 /// Access return operations.
170 ///
171 /// # Example
172 ///
173 /// ```rust,ignore
174 /// use stateset_embedded::{Commerce, CreateReturn, CreateReturnItem, ReturnReason};
175 /// use uuid::Uuid;
176 ///
177 /// let commerce = Commerce::new("./store.db")?;
178 ///
179 /// let ret = commerce.returns().create(CreateReturn {
180 /// order_id: Uuid::new_v4(),
181 /// reason: ReturnReason::Defective,
182 /// items: vec![CreateReturnItem {
183 /// order_item_id: Uuid::new_v4(),
184 /// quantity: 1,
185 /// ..Default::default()
186 /// }],
187 /// ..Default::default()
188 /// })?;
189 /// # Ok::<(), stateset_embedded::CommerceError>(())
190 /// ```
191 #[must_use]
192 pub fn returns(&self) -> Returns {
193 #[cfg(feature = "events")]
194 {
195 Returns::new(self.db.clone(), self.event_system.clone(), self.metrics.clone())
196 }
197 #[cfg(not(feature = "events"))]
198 {
199 Returns::new(self.db.clone(), self.metrics.clone())
200 }
201 }
202
203 /// Access Bill of Materials (BOM) operations.
204 ///
205 /// # Example
206 ///
207 /// ```rust,ignore
208 /// use stateset_embedded::{Commerce, CreateBom, CreateBomComponent};
209 /// use rust_decimal_macros::dec;
210 /// use uuid::Uuid;
211 ///
212 /// let commerce = Commerce::new("./store.db")?;
213 ///
214 /// let bom = commerce.bom().create(CreateBom {
215 /// product_id: Uuid::new_v4(),
216 /// name: "Widget Assembly".into(),
217 /// components: Some(vec![
218 /// CreateBomComponent {
219 /// name: "Part A".into(),
220 /// quantity: dec!(2),
221 /// ..Default::default()
222 /// },
223 /// ]),
224 /// ..Default::default()
225 /// })?;
226 /// # Ok::<(), stateset_embedded::CommerceError>(())
227 /// ```
228 #[must_use]
229 pub fn bom(&self) -> Bom {
230 Bom::new(self.db.clone())
231 }
232
233 /// Access work order operations.
234 ///
235 /// # Example
236 ///
237 /// ```rust,ignore
238 /// use stateset_embedded::{Commerce, CreateWorkOrder};
239 /// use rust_decimal_macros::dec;
240 /// use uuid::Uuid;
241 ///
242 /// let commerce = Commerce::new("./store.db")?;
243 ///
244 /// let wo = commerce.work_orders().create(CreateWorkOrder {
245 /// product_id: Uuid::new_v4(),
246 /// quantity_to_build: dec!(100),
247 /// ..Default::default()
248 /// })?;
249 ///
250 /// // Start production
251 /// let wo = commerce.work_orders().start(wo.id)?;
252 /// # Ok::<(), stateset_embedded::CommerceError>(())
253 /// ```
254 #[must_use]
255 pub fn work_orders(&self) -> WorkOrders {
256 WorkOrders::new(self.db.clone())
257 }
258
259 /// Access shipment operations.
260 ///
261 /// # Example
262 ///
263 /// ```rust,ignore
264 /// use stateset_embedded::{Commerce, CreateShipment, CreateShipmentItem, ShippingCarrier};
265 /// use uuid::Uuid;
266 ///
267 /// let commerce = Commerce::new("./store.db")?;
268 ///
269 /// let shipment = commerce.shipments().create(CreateShipment {
270 /// order_id: Uuid::new_v4(),
271 /// carrier: Some(ShippingCarrier::Ups),
272 /// recipient_name: "Alice Smith".into(),
273 /// shipping_address: "123 Main St, City, ST 12345".into(),
274 /// items: Some(vec![CreateShipmentItem {
275 /// sku: "SKU-001".into(),
276 /// name: "Widget".into(),
277 /// quantity: 2,
278 /// ..Default::default()
279 /// }]),
280 /// ..Default::default()
281 /// })?;
282 ///
283 /// // Ship with tracking number
284 /// let shipment = commerce.shipments().ship(shipment.id, Some("1Z999AA10123456784".into()))?;
285 ///
286 /// // Mark as delivered
287 /// let shipment = commerce.shipments().mark_delivered(shipment.id)?;
288 /// # Ok::<(), stateset_embedded::CommerceError>(())
289 /// ```
290 #[must_use]
291 pub fn shipments(&self) -> Shipments {
292 Shipments::new(self.db.clone(), self.metrics.clone())
293 }
294
295 /// Access payment operations.
296 ///
297 /// # Example
298 ///
299 /// ```rust,ignore
300 /// use stateset_embedded::{Commerce, CreatePayment, PaymentMethodType, CardBrand};
301 /// use rust_decimal_macros::dec;
302 /// use uuid::Uuid;
303 ///
304 /// let commerce = Commerce::new("./store.db")?;
305 ///
306 /// let payment = commerce.payments().create(CreatePayment {
307 /// order_id: Some(Uuid::new_v4()),
308 /// payment_method: PaymentMethodType::CreditCard,
309 /// amount: dec!(99.99),
310 /// card_brand: Some(CardBrand::Visa),
311 /// card_last4: Some("4242".into()),
312 /// ..Default::default()
313 /// })?;
314 ///
315 /// // Mark payment as completed
316 /// let payment = commerce.payments().mark_completed(payment.id)?;
317 /// # Ok::<(), stateset_embedded::CommerceError>(())
318 /// ```
319 #[must_use]
320 pub fn payments(&self) -> Payments {
321 Payments::new(self.db.clone(), self.metrics.clone())
322 }
323
324 /// Access warranty operations.
325 ///
326 /// # Example
327 ///
328 /// ```rust,ignore
329 /// use stateset_embedded::{Commerce, CreateWarranty, WarrantyType};
330 /// use uuid::Uuid;
331 ///
332 /// let commerce = Commerce::new("./store.db")?;
333 ///
334 /// let warranty = commerce.warranties().create(CreateWarranty {
335 /// customer_id: Uuid::new_v4(),
336 /// product_id: Some(Uuid::new_v4()),
337 /// warranty_type: Some(WarrantyType::Extended),
338 /// duration_months: Some(24),
339 /// ..Default::default()
340 /// })?;
341 ///
342 /// // Check if warranty is valid
343 /// assert!(commerce.warranties().is_valid(warranty.id)?);
344 /// # Ok::<(), stateset_embedded::CommerceError>(())
345 /// ```
346 #[must_use]
347 pub fn warranties(&self) -> Warranties {
348 Warranties::new(self.db.clone())
349 }
350
351 /// Access purchase order operations.
352 ///
353 /// # Example
354 ///
355 /// ```rust,ignore
356 /// use stateset_embedded::{Commerce, CreatePurchaseOrder, CreatePurchaseOrderItem, CreateSupplier};
357 /// use rust_decimal_macros::dec;
358 ///
359 /// let commerce = Commerce::new("./store.db")?;
360 ///
361 /// // Create a supplier
362 /// let supplier = commerce.purchase_orders().create_supplier(CreateSupplier {
363 /// name: "Acme Supplies".into(),
364 /// email: Some("orders@acme.com".into()),
365 /// ..Default::default()
366 /// })?;
367 ///
368 /// // Create a purchase order
369 /// let po = commerce.purchase_orders().create(CreatePurchaseOrder {
370 /// supplier_id: supplier.id,
371 /// items: vec![CreatePurchaseOrderItem {
372 /// sku: "PART-001".into(),
373 /// name: "Widget Part".into(),
374 /// quantity: dec!(100),
375 /// unit_cost: dec!(5.99),
376 /// ..Default::default()
377 /// }],
378 /// ..Default::default()
379 /// })?;
380 ///
381 /// // Approve and send
382 /// let po = commerce.purchase_orders().submit(po.id)?;
383 /// let po = commerce.purchase_orders().approve(po.id, "admin")?;
384 /// let po = commerce.purchase_orders().send(po.id)?;
385 /// # Ok::<(), stateset_embedded::CommerceError>(())
386 /// ```
387 #[must_use]
388 pub fn purchase_orders(&self) -> PurchaseOrders {
389 PurchaseOrders::new(self.db.clone())
390 }
391
392 /// Access invoice operations.
393 ///
394 /// # Example
395 ///
396 /// ```rust,ignore
397 /// use stateset_embedded::{Commerce, CreateInvoice, CreateInvoiceItem, RecordInvoicePayment};
398 /// use rust_decimal_macros::dec;
399 /// use uuid::Uuid;
400 ///
401 /// let commerce = Commerce::new("./store.db")?;
402 ///
403 /// let invoice = commerce.invoices().create(CreateInvoice {
404 /// customer_id: Uuid::new_v4(),
405 /// billing_email: Some("customer@example.com".into()),
406 /// items: vec![CreateInvoiceItem {
407 /// description: "Professional Services".into(),
408 /// quantity: dec!(10),
409 /// unit_price: dec!(150.00),
410 /// ..Default::default()
411 /// }],
412 /// ..Default::default()
413 /// })?;
414 ///
415 /// // Send and record payment
416 /// let invoice = commerce.invoices().send(invoice.id)?;
417 /// let invoice = commerce.invoices().record_payment(invoice.id, RecordInvoicePayment {
418 /// amount: dec!(1500.00),
419 /// payment_method: Some("credit_card".into()),
420 /// ..Default::default()
421 /// })?;
422 /// # Ok::<(), stateset_embedded::CommerceError>(())
423 /// ```
424 #[must_use]
425 pub fn invoices(&self) -> Invoices {
426 Invoices::new(self.db.clone())
427 }
428
429 /// Access cart and checkout operations.
430 ///
431 /// # Example
432 ///
433 /// ```rust,ignore
434 /// use stateset_embedded::{Commerce, CreateCart, AddCartItem, CartAddress};
435 /// use rust_decimal_macros::dec;
436 /// use uuid::Uuid;
437 ///
438 /// let commerce = Commerce::new("./store.db")?;
439 ///
440 /// // Create a cart
441 /// let cart = commerce.carts().create(CreateCart {
442 /// customer_email: Some("alice@example.com".into()),
443 /// customer_name: Some("Alice Smith".into()),
444 /// ..Default::default()
445 /// })?;
446 ///
447 /// // Add items
448 /// commerce.carts().add_item(cart.id, AddCartItem {
449 /// sku: "SKU-001".into(),
450 /// name: "Widget".into(),
451 /// quantity: 2,
452 /// unit_price: dec!(29.99),
453 /// ..Default::default()
454 /// })?;
455 ///
456 /// // Set shipping address
457 /// commerce.carts().set_shipping_address(cart.id, CartAddress {
458 /// first_name: "Alice".into(),
459 /// last_name: "Smith".into(),
460 /// line1: "123 Main St".into(),
461 /// city: "Anytown".into(),
462 /// postal_code: "12345".into(),
463 /// country: "US".into(),
464 /// ..Default::default()
465 /// })?;
466 ///
467 /// // Complete checkout
468 /// let result = commerce.carts().complete(cart.id)?;
469 /// println!("Order created: {}", result.order_number);
470 /// # Ok::<(), stateset_embedded::CommerceError>(())
471 /// ```
472 #[must_use]
473 pub fn carts(&self) -> Carts {
474 Carts::new(self.db.clone(), self.metrics.clone())
475 }
476
477 /// Access analytics and forecasting operations.
478 ///
479 /// # Example
480 ///
481 /// ```rust,ignore
482 /// use stateset_embedded::{Commerce, AnalyticsQuery, TimePeriod};
483 ///
484 /// let commerce = Commerce::new("./store.db")?;
485 ///
486 /// // Get sales summary
487 /// let summary = commerce.analytics().sales_summary(
488 /// AnalyticsQuery::new().period(TimePeriod::Last30Days)
489 /// )?;
490 /// println!("Revenue: ${}", summary.total_revenue);
491 /// println!("Orders: {}", summary.order_count);
492 ///
493 /// // Get top products
494 /// let top = commerce.analytics().top_products(
495 /// AnalyticsQuery::new().period(TimePeriod::ThisMonth).limit(10)
496 /// )?;
497 ///
498 /// // Get inventory forecast
499 /// let forecasts = commerce.analytics().demand_forecast(None, 30)?;
500 /// for f in forecasts {
501 /// if let Some(days) = f.days_until_stockout {
502 /// if days < 14 {
503 /// println!("WARNING: {} will stock out in {} days", f.sku, days);
504 /// }
505 /// }
506 /// }
507 /// # Ok::<(), stateset_embedded::CommerceError>(())
508 /// ```
509 #[must_use]
510 pub fn analytics(&self) -> Analytics {
511 Analytics::new(self.db.clone())
512 }
513
514 /// Access currency and exchange rate operations.
515 ///
516 /// # Example
517 ///
518 /// ```rust,ignore
519 /// use stateset_embedded::{Commerce, Currency, ConvertCurrency};
520 /// use rust_decimal_macros::dec;
521 ///
522 /// let commerce = Commerce::new("./store.db")?;
523 ///
524 /// // Get exchange rate
525 /// if let Some(rate) = commerce.currency().get_rate(Currency::USD, Currency::EUR)? {
526 /// println!("1 USD = {} EUR", rate.rate);
527 /// }
528 ///
529 /// // Convert currency
530 /// let result = commerce.currency().convert(ConvertCurrency {
531 /// from: Currency::USD,
532 /// to: Currency::EUR,
533 /// amount: dec!(100.00),
534 /// })?;
535 /// println!("$100 USD = €{} EUR", result.converted_amount);
536 ///
537 /// // Set exchange rates
538 /// commerce.currency().set_rate(stateset_embedded::SetExchangeRate {
539 /// base_currency: Currency::USD,
540 /// quote_currency: Currency::EUR,
541 /// rate: dec!(0.92),
542 /// source: Some("manual".into()),
543 /// })?;
544 ///
545 /// // Update store settings
546 /// let settings = commerce.currency().get_settings()?;
547 /// println!("Base currency: {}", settings.base_currency);
548 /// # Ok::<(), stateset_embedded::CommerceError>(())
549 /// ```
550 #[must_use]
551 pub fn currency(&self) -> CurrencyOps {
552 CurrencyOps::new(self.db.clone())
553 }
554
555 /// Access tax calculation and management operations.
556 ///
557 /// Provides multi-jurisdiction tax calculation with support for:
558 /// - US sales tax (state, county, city levels)
559 /// - EU VAT (standard, reduced, zero-rated)
560 /// - Canadian GST/HST/PST/QST
561 /// - Customer exemptions (resale, non-profit, etc.)
562 ///
563 /// # Example
564 ///
565 /// ```rust,ignore
566 /// use stateset_embedded::{Commerce, TaxCalculationRequest, TaxLineItem, TaxAddress, ProductTaxCategory};
567 /// use rust_decimal_macros::dec;
568 ///
569 /// let commerce = Commerce::new("./store.db")?;
570 ///
571 /// // Calculate tax for a transaction
572 /// let result = commerce.tax().calculate(TaxCalculationRequest {
573 /// line_items: vec![TaxLineItem {
574 /// id: "item-1".into(),
575 /// quantity: dec!(2),
576 /// unit_price: dec!(29.99),
577 /// tax_category: ProductTaxCategory::Standard,
578 /// ..Default::default()
579 /// }],
580 /// shipping_address: TaxAddress {
581 /// country: "US".into(),
582 /// state: Some("CA".into()),
583 /// ..Default::default()
584 /// },
585 /// ..Default::default()
586 /// })?;
587 ///
588 /// println!("Tax: ${}", result.total_tax);
589 /// println!("Total: ${}", result.total);
590 ///
591 /// // Check effective rate for an address
592 /// let rate = commerce.tax().get_effective_rate(
593 /// &TaxAddress { country: "US".into(), state: Some("TX".into()), ..Default::default() },
594 /// ProductTaxCategory::Standard,
595 /// )?;
596 /// println!("Texas tax rate: {}%", rate * dec!(100));
597 /// # Ok::<(), stateset_embedded::CommerceError>(())
598 /// ```
599 #[must_use]
600 pub fn tax(&self) -> Tax {
601 Tax::new(self.db.clone())
602 }
603
604 /// Access promotions and discount operations.
605 ///
606 /// Provides comprehensive promotions engine supporting:
607 /// - Percentage and fixed amount discounts
608 /// - Buy X Get Y (BOGO) promotions
609 /// - Free shipping offers
610 /// - Tiered discounts based on spend/quantity
611 /// - Coupon code management
612 /// - Automatic promotions
613 ///
614 /// # Example
615 ///
616 /// ```rust,ignore
617 /// use stateset_embedded::{Commerce, CreatePromotion, PromotionType, ApplyPromotionsRequest, PromotionLineItem};
618 /// use rust_decimal_macros::dec;
619 ///
620 /// let commerce = Commerce::new("./store.db")?;
621 ///
622 /// // Create a 20% off promotion
623 /// let promo = commerce.promotions().create(CreatePromotion {
624 /// name: "Summer Sale".into(),
625 /// promotion_type: PromotionType::PercentageOff,
626 /// percentage_off: Some(dec!(0.20)),
627 /// ..Default::default()
628 /// })?;
629 ///
630 /// // Activate it
631 /// commerce.promotions().activate(promo.id)?;
632 ///
633 /// // Create a coupon code
634 /// commerce.promotions().create_coupon(stateset_embedded::CreateCouponCode {
635 /// promotion_id: promo.id,
636 /// code: "SUMMER20".into(),
637 /// usage_limit: Some(100),
638 /// ..Default::default()
639 /// })?;
640 ///
641 /// // Apply promotions to a cart
642 /// let result = commerce.promotions().apply(ApplyPromotionsRequest {
643 /// subtotal: dec!(100.00),
644 /// coupon_codes: vec!["SUMMER20".into()],
645 /// line_items: vec![PromotionLineItem {
646 /// id: "item-1".into(),
647 /// quantity: 2,
648 /// unit_price: dec!(50.00),
649 /// line_total: dec!(100.00),
650 /// ..Default::default()
651 /// }],
652 /// ..Default::default()
653 /// })?;
654 ///
655 /// println!("Discount: ${}", result.total_discount);
656 /// println!("Final total: ${}", result.grand_total);
657 /// # Ok::<(), stateset_embedded::CommerceError>(())
658 /// ```
659 #[must_use]
660 pub fn promotions(&self) -> Promotions {
661 Promotions::new(self.db.clone())
662 }
663
664 /// Access subscription management operations.
665 ///
666 /// # Example
667 ///
668 /// ```rust,ignore
669 /// use stateset_embedded::{Commerce, CreateSubscriptionPlan, CreateSubscription, BillingInterval};
670 /// use rust_decimal_macros::dec;
671 /// use uuid::Uuid;
672 ///
673 /// let commerce = Commerce::new("./store.db")?;
674 ///
675 /// // Create a subscription plan
676 /// let plan = commerce.subscriptions().create_plan(CreateSubscriptionPlan {
677 /// name: "Monthly Coffee Box".into(),
678 /// billing_interval: BillingInterval::Monthly,
679 /// price: dec!(29.99),
680 /// trial_days: Some(14),
681 /// ..Default::default()
682 /// })?;
683 ///
684 /// // Activate the plan
685 /// commerce.subscriptions().activate_plan(plan.id)?;
686 ///
687 /// // Subscribe a customer
688 /// let subscription = commerce.subscriptions().subscribe(CreateSubscription {
689 /// customer_id: Uuid::new_v4(),
690 /// plan_id: plan.id,
691 /// ..Default::default()
692 /// })?;
693 ///
694 /// println!("Subscription #{} created", subscription.subscription_number);
695 /// # Ok::<(), stateset_embedded::CommerceError>(())
696 /// ```
697 #[must_use]
698 pub fn subscriptions(&self) -> Subscriptions {
699 Subscriptions::new(self.db.clone(), self.metrics.clone())
700 }
701
702 /// Access quality control operations.
703 ///
704 /// # Example
705 ///
706 /// ```rust,ignore
707 /// use stateset_embedded::{Commerce, CreateInspection, InspectionType};
708 /// use uuid::Uuid;
709 ///
710 /// let commerce = Commerce::new("./store.db")?;
711 ///
712 /// let inspection = commerce.quality().create_inspection(CreateInspection {
713 /// inspection_type: InspectionType::Receiving,
714 /// reference_type: "purchase_order".into(),
715 /// reference_id: Uuid::new_v4(),
716 /// ..Default::default()
717 /// })?;
718 ///
719 /// println!("Created inspection #{}", inspection.inspection_number);
720 /// # Ok::<(), stateset_embedded::CommerceError>(())
721 /// ```
722 #[must_use]
723 pub fn quality(&self) -> Quality {
724 Quality::new(self.db.clone())
725 }
726
727 /// Access lot/batch tracking operations.
728 ///
729 /// # Example
730 ///
731 /// ```rust,ignore
732 /// use stateset_embedded::{Commerce, CreateLot};
733 /// use chrono::{Utc, Duration};
734 /// use rust_decimal_macros::dec;
735 ///
736 /// let commerce = Commerce::new("./store.db")?;
737 ///
738 /// let lot = commerce.lots().create(CreateLot {
739 /// lot_number: Some("LOT-2025-001".into()),
740 /// sku: "RAW-001".into(),
741 /// quantity_produced: dec!(1000),
742 /// expiration_date: Some(Utc::now() + Duration::days(365)),
743 /// ..Default::default()
744 /// })?;
745 ///
746 /// println!("Created lot {}", lot.lot_number);
747 /// # Ok::<(), stateset_embedded::CommerceError>(())
748 /// ```
749 #[must_use]
750 pub fn lots(&self) -> Lots {
751 Lots::new(self.db.clone())
752 }
753
754 /// Access serial number management operations.
755 ///
756 /// # Example
757 ///
758 /// ```rust,ignore
759 /// use stateset_embedded::{Commerce, CreateSerialNumber};
760 ///
761 /// let commerce = Commerce::new("./store.db")?;
762 ///
763 /// let serial = commerce.serials().create(CreateSerialNumber {
764 /// serial: Some("SN-12345-ABCD".into()),
765 /// sku: "LAPTOP-PRO-15".into(),
766 /// ..Default::default()
767 /// })?;
768 ///
769 /// println!("Created serial {}", serial.serial);
770 /// # Ok::<(), stateset_embedded::CommerceError>(())
771 /// ```
772 #[must_use]
773 pub fn serials(&self) -> Serials {
774 Serials::new(self.db.clone())
775 }
776
777 /// Access warehouse and location management operations.
778 ///
779 /// # Example
780 ///
781 /// ```rust,ignore
782 /// use stateset_embedded::{Commerce, CreateWarehouse, CreateLocation, WarehouseType, LocationType};
783 ///
784 /// let commerce = Commerce::new("./store.db")?;
785 ///
786 /// // Create a warehouse
787 /// let warehouse = commerce.warehouse().create_warehouse(CreateWarehouse {
788 /// code: "WH-001".into(),
789 /// name: "Main Distribution Center".into(),
790 /// warehouse_type: WarehouseType::Distribution,
791 /// ..Default::default()
792 /// })?;
793 ///
794 /// // Create a location
795 /// let location = commerce.warehouse().create_location(CreateLocation {
796 /// warehouse_id: warehouse.id,
797 /// location_type: LocationType::Pick,
798 /// zone: Some("A".into()),
799 /// aisle: Some("01".into()),
800 /// ..Default::default()
801 /// })?;
802 ///
803 /// println!("Created location {} in {}", location.code, warehouse.name);
804 /// # Ok::<(), stateset_embedded::CommerceError>(())
805 /// ```
806 #[must_use]
807 pub fn warehouse(&self) -> WarehouseOps {
808 #[cfg(feature = "events")]
809 {
810 WarehouseOps::new(self.db.clone(), self.event_system.clone())
811 }
812 #[cfg(not(feature = "events"))]
813 {
814 WarehouseOps::new(self.db.clone())
815 }
816 }
817
818 /// Access receiving and goods receipt operations.
819 ///
820 /// # Example
821 ///
822 /// ```rust,ignore
823 /// use stateset_embedded::{Commerce, CreateReceipt, CreateReceiptItem, ReceiptType};
824 /// use rust_decimal_macros::dec;
825 ///
826 /// let commerce = Commerce::new("./store.db")?;
827 ///
828 /// // Create a receipt
829 /// let receipt = commerce.receiving().create_receipt(CreateReceipt {
830 /// receipt_type: ReceiptType::PurchaseOrder,
831 /// warehouse_id: 1,
832 /// items: vec![CreateReceiptItem {
833 /// sku: "WIDGET-001".into(),
834 /// expected_quantity: dec!(100),
835 /// ..Default::default()
836 /// }],
837 /// ..Default::default()
838 /// })?;
839 ///
840 /// println!("Created receipt {}", receipt.receipt_number);
841 /// # Ok::<(), stateset_embedded::CommerceError>(())
842 /// ```
843 #[must_use]
844 pub fn receiving(&self) -> Receiving {
845 Receiving::new(self.db.clone())
846 }
847
848 /// Access fulfillment (pick/pack/ship) operations.
849 ///
850 /// # Example
851 ///
852 /// ```rust,ignore
853 /// use stateset_embedded::{Commerce, CreateWave, PickTaskFilter};
854 /// use uuid::Uuid;
855 ///
856 /// let commerce = Commerce::new("./store.db")?;
857 ///
858 /// // Create a wave from orders
859 /// let wave = commerce.fulfillment().create_wave(CreateWave {
860 /// warehouse_id: 1,
861 /// order_ids: vec![Uuid::new_v4()],
862 /// ..Default::default()
863 /// })?;
864 ///
865 /// // Get picks for the wave
866 /// let picks = commerce.fulfillment().get_picks_for_wave(wave.id)?;
867 /// # Ok::<(), stateset_embedded::CommerceError>(())
868 /// ```
869 #[must_use]
870 pub fn fulfillment(&self) -> Fulfillment {
871 Fulfillment::new(self.db.clone())
872 }
873
874 /// Access accounts payable (bills and supplier payments) operations.
875 ///
876 /// # Example
877 ///
878 /// ```rust,ignore
879 /// use stateset_embedded::{Commerce, CreateBill, CreateBillItem};
880 /// use rust_decimal_macros::dec;
881 /// use chrono::{Utc, Duration};
882 /// use uuid::Uuid;
883 ///
884 /// let commerce = Commerce::new("./store.db")?;
885 ///
886 /// // Create a bill from a supplier
887 /// let bill = commerce.accounts_payable().create_bill(CreateBill {
888 /// supplier_id: Uuid::new_v4(),
889 /// due_date: Utc::now() + Duration::days(30),
890 /// items: vec![CreateBillItem {
891 /// description: "Office supplies".into(),
892 /// quantity: dec!(1),
893 /// unit_price: dec!(150.00),
894 /// ..Default::default()
895 /// }],
896 /// ..Default::default()
897 /// })?;
898 ///
899 /// // Get aging summary
900 /// let aging = commerce.accounts_payable().get_aging_summary()?;
901 /// println!("Total AP: ${}", aging.total);
902 /// # Ok::<(), stateset_embedded::CommerceError>(())
903 /// ```
904 #[must_use]
905 pub fn accounts_payable(&self) -> AccountsPayable {
906 #[cfg(feature = "events")]
907 {
908 AccountsPayable::new(self.db.clone(), self.event_system.clone())
909 }
910 #[cfg(not(feature = "events"))]
911 {
912 AccountsPayable::new(self.db.clone())
913 }
914 }
915
916 /// Access cost accounting operations.
917 ///
918 /// # Example
919 ///
920 /// ```rust,ignore
921 /// use stateset_embedded::{Commerce, SetItemCost, CostMethod};
922 /// use rust_decimal_macros::dec;
923 ///
924 /// let commerce = Commerce::new("./store.db")?;
925 ///
926 /// // Set standard cost for an item
927 /// let cost = commerce.cost_accounting().set_item_cost(SetItemCost {
928 /// sku: "WIDGET-001".into(),
929 /// cost_method: Some(CostMethod::Average),
930 /// standard_cost: Some(dec!(10.00)),
931 /// ..Default::default()
932 /// })?;
933 ///
934 /// // Get inventory valuation
935 /// let valuation = commerce.cost_accounting().get_inventory_valuation(CostMethod::Average)?;
936 /// println!("Total inventory value: ${}", valuation.total_value);
937 /// # Ok::<(), stateset_embedded::CommerceError>(())
938 /// ```
939 #[must_use]
940 pub fn cost_accounting(&self) -> CostAccounting {
941 CostAccounting::new(self.db.clone())
942 }
943
944 /// Access credit management operations.
945 ///
946 /// # Example
947 ///
948 /// ```rust,ignore
949 /// use stateset_embedded::{Commerce, CreateCreditAccount};
950 /// use rust_decimal_macros::dec;
951 /// use uuid::Uuid;
952 ///
953 /// let commerce = Commerce::new("./store.db")?;
954 ///
955 /// // Create credit account for a customer
956 /// let account = commerce.credit().create_credit_account(CreateCreditAccount {
957 /// customer_id: Uuid::new_v4(),
958 /// credit_limit: dec!(10000.00),
959 /// payment_terms: Some("Net 30".into()),
960 /// ..Default::default()
961 /// })?;
962 ///
963 /// // Check credit for an order
964 /// let result = commerce.credit().check_credit(account.customer_id, dec!(5000.00))?;
965 /// println!("Credit approved: {}", result.approved);
966 /// # Ok::<(), stateset_embedded::CommerceError>(())
967 /// ```
968 #[must_use]
969 pub fn credit(&self) -> Credit {
970 Credit::new(self.db.clone())
971 }
972
973 /// Access backorder management operations.
974 ///
975 /// # Example
976 ///
977 /// ```rust,ignore
978 /// use stateset_embedded::{Commerce, CreateBackorder, BackorderPriority};
979 /// use rust_decimal_macros::dec;
980 /// use uuid::Uuid;
981 ///
982 /// let commerce = Commerce::new("./store.db")?;
983 ///
984 /// // Create a backorder when inventory is unavailable
985 /// let backorder = commerce.backorder().create_backorder(CreateBackorder {
986 /// order_id: Uuid::new_v4(),
987 /// customer_id: Uuid::new_v4(),
988 /// sku: "WIDGET-001".into(),
989 /// quantity: dec!(50),
990 /// priority: Some(BackorderPriority::High),
991 /// ..Default::default()
992 /// })?;
993 ///
994 /// // Get overdue backorders
995 /// let overdue = commerce.backorder().get_overdue_backorders()?;
996 /// println!("Overdue backorders: {}", overdue.len());
997 /// # Ok::<(), stateset_embedded::CommerceError>(())
998 /// ```
999 #[must_use]
1000 pub fn backorder(&self) -> Backorders {
1001 Backorders::new(self.db.clone())
1002 }
1003
1004 /// Access accounts receivable operations.
1005 ///
1006 /// Provides AR aging, collection activities, write-offs, credit memos,
1007 /// and customer statement generation.
1008 ///
1009 /// # Example
1010 ///
1011 /// ```rust,ignore
1012 /// use stateset_embedded::Commerce;
1013 ///
1014 /// let commerce = Commerce::new("./store.db")?;
1015 ///
1016 /// // Get AR aging summary
1017 /// let aging = commerce.accounts_receivable().get_aging_summary()?;
1018 /// println!("Current: ${}", aging.current);
1019 /// println!("1-30 days: ${}", aging.days_1_30);
1020 /// println!("31-60 days: ${}", aging.days_31_60);
1021 /// println!("61-90 days: ${}", aging.days_61_90);
1022 /// println!("90+ days: ${}", aging.days_over_90);
1023 ///
1024 /// // Get DSO (Days Sales Outstanding)
1025 /// let dso = commerce.accounts_receivable().get_dso(30)?;
1026 /// println!("DSO (30 day): {}", dso);
1027 /// # Ok::<(), stateset_embedded::CommerceError>(())
1028 /// ```
1029 #[must_use]
1030 pub fn accounts_receivable(&self) -> AccountsReceivable {
1031 AccountsReceivable::new(self.db.clone())
1032 }
1033
1034 /// Access general ledger operations.
1035 ///
1036 /// Provides chart of accounts management, journal entries,
1037 /// period management, and financial reporting.
1038 ///
1039 /// # Example
1040 ///
1041 /// ```rust,ignore
1042 /// use stateset_embedded::{Commerce, CreateJournalEntry};
1043 /// use chrono::NaiveDate;
1044 ///
1045 /// let commerce = Commerce::new("./store.db")?;
1046 ///
1047 /// // Initialize standard chart of accounts
1048 /// commerce.general_ledger().initialize_chart_of_accounts()?;
1049 ///
1050 /// // Generate trial balance
1051 /// let trial_balance = commerce.general_ledger().get_trial_balance(
1052 /// NaiveDate::from_ymd_opt(2025, 1, 31).unwrap()
1053 /// )?;
1054 /// println!("Total Debits: ${}", trial_balance.total_debits);
1055 /// println!("Total Credits: ${}", trial_balance.total_credits);
1056 /// println!("Balanced: {}", trial_balance.is_balanced);
1057 ///
1058 /// // Generate income statement
1059 /// let income = commerce.general_ledger().get_income_statement(
1060 /// NaiveDate::from_ymd_opt(2025, 1, 1).unwrap(),
1061 /// NaiveDate::from_ymd_opt(2025, 1, 31).unwrap(),
1062 /// )?;
1063 /// println!("Revenue: ${}", income.total_revenue);
1064 /// println!("Expenses: ${}", income.total_expenses);
1065 /// println!("Net Income: ${}", income.net_income);
1066 /// # Ok::<(), stateset_embedded::CommerceError>(())
1067 /// ```
1068 #[must_use]
1069 pub fn general_ledger(&self) -> GeneralLedger {
1070 #[cfg(feature = "events")]
1071 {
1072 GeneralLedger::new(self.db.clone(), self.event_system.clone())
1073 }
1074 #[cfg(not(feature = "events"))]
1075 {
1076 GeneralLedger::new(self.db.clone())
1077 }
1078 }
1079
1080 /// Access x402 payment protocol and agent card operations.
1081 ///
1082 /// Provides x402 stablecoin payment intents for AI agent commerce,
1083 /// including intent creation, signing, settlement tracking, and
1084 /// agent card management for A2A (agent-to-agent) commerce.
1085 ///
1086 /// # Example
1087 ///
1088 /// ```rust,ignore
1089 /// use stateset_embedded::{Commerce, CreateX402PaymentIntent, X402Network, X402Asset};
1090 /// use rust_decimal_macros::dec;
1091 ///
1092 /// let commerce = Commerce::new("./store.db")?;
1093 ///
1094 /// // Create a payment intent
1095 /// let intent = commerce.x402().create_intent(CreateX402PaymentIntent {
1096 /// payer_address: "0xBuyer...".into(),
1097 /// payee_address: "0xSeller...".into(),
1098 /// amount: dec!(100.00),
1099 /// asset: X402Asset::Usdc,
1100 /// network: X402Network::SetChain,
1101 /// ..Default::default()
1102 /// })?;
1103 ///
1104 /// // Register an agent card
1105 /// use stateset_embedded::{CreateAgentCard, A2ASkill};
1106 ///
1107 /// let card = commerce.x402().register_agent(CreateAgentCard {
1108 /// name: "Commerce Bot".into(),
1109 /// wallet_address: "0xAgent...".into(),
1110 /// public_key: "ed25519_pubkey_base64".into(),
1111 /// supported_networks: vec![X402Network::SetChain],
1112 /// supported_assets: vec![X402Asset::Usdc, X402Asset::SsUsd],
1113 /// a2a_skills: Some(vec![A2ASkill::Sell, A2ASkill::Quote]),
1114 /// ..Default::default()
1115 /// })?;
1116 ///
1117 /// // Discover agents with specific capabilities
1118 /// let sellers = commerce.x402().discover_agents(
1119 /// Some(vec![X402Network::SetChain]),
1120 /// Some(vec![X402Asset::Usdc]),
1121 /// Some(vec!["Sell".to_string()]),
1122 /// None,
1123 /// )?;
1124 /// # Ok::<(), stateset_embedded::CommerceError>(())
1125 /// ```
1126 #[must_use]
1127 pub fn x402(&self) -> X402 {
1128 X402::new(self.db.clone())
1129 }
1130
1131 /// Access ERC-8004 trustless agent registries.
1132 ///
1133 /// Provides identity, reputation, and validation registry operations
1134 /// for trustless agent discovery across organizational boundaries.
1135 #[must_use]
1136 pub fn erc8004(&self) -> Erc8004 {
1137 Erc8004::new(self.db.clone())
1138 }
1139
1140 /// Access gift card operations.
1141 ///
1142 /// Provides gift card issuance, charging, refunding, and transaction history.
1143 #[must_use]
1144 pub fn gift_cards(&self) -> GiftCards {
1145 GiftCards::new(self.db.clone())
1146 }
1147
1148 /// Access store credit operations.
1149 ///
1150 /// Provides store credit management including balance adjustments and application to orders.
1151 #[must_use]
1152 pub fn store_credits(&self) -> StoreCredits {
1153 StoreCredits::new(self.db.clone())
1154 }
1155
1156 /// Access customer segment operations.
1157 ///
1158 /// Provides customer grouping, membership management, and segment targeting.
1159 #[must_use]
1160 pub fn segments(&self) -> Segments {
1161 Segments::new(self.db.clone())
1162 }
1163
1164 /// Access shipping zone and method operations.
1165 ///
1166 /// Provides shipping zone management, method configuration, and rate calculation.
1167 #[must_use]
1168 pub fn shipping_zones(&self) -> ShippingZones {
1169 ShippingZones::new(self.db.clone())
1170 }
1171
1172 /// Access sales / fulfillment channel operations.
1173 #[must_use]
1174 pub fn channels(&self) -> crate::Channels {
1175 crate::Channels::new(self.db.clone())
1176 }
1177
1178 /// Access B2B company (account) operations.
1179 #[must_use]
1180 pub fn companies(&self) -> crate::Companies {
1181 crate::Companies::new(self.db.clone())
1182 }
1183
1184 /// Access transfer order operations (inter-warehouse stock movement).
1185 #[must_use]
1186 pub fn transfer_orders(&self) -> crate::TransferOrders {
1187 crate::TransferOrders::new(self.db.clone())
1188 }
1189
1190 /// Access units-of-measure operations (classes, UOMs, conversion rules).
1191 #[must_use]
1192 pub fn units_of_measure(&self) -> crate::UnitsOfMeasure {
1193 crate::UnitsOfMeasure::new(self.db.clone())
1194 }
1195
1196 /// Access production batch operations.
1197 #[must_use]
1198 pub fn production_batches(&self) -> crate::ProductionBatches {
1199 crate::ProductionBatches::new(self.db.clone())
1200 }
1201
1202 /// Access supplier SKU operations.
1203 #[must_use]
1204 pub fn supplier_skus(&self) -> crate::SupplierSkus {
1205 crate::SupplierSkus::new(self.db.clone())
1206 }
1207
1208 /// Access fixed asset register operations.
1209 #[must_use]
1210 pub fn fixed_assets(&self) -> crate::FixedAssets {
1211 #[cfg(feature = "events")]
1212 {
1213 crate::FixedAssets::new(self.db.clone(), self.event_system.clone())
1214 }
1215 #[cfg(not(feature = "events"))]
1216 {
1217 crate::FixedAssets::new(self.db.clone())
1218 }
1219 }
1220
1221 /// Access backup, restore and export/import operations.
1222 ///
1223 /// # Example
1224 ///
1225 /// ```rust,ignore
1226 /// let commerce = stateset_embedded::Commerce::new("./store.db")?;
1227 /// let report = commerce.maintenance().backup_to("./backups/nightly.db")?;
1228 /// # Ok::<(), stateset_embedded::CommerceError>(())
1229 /// ```
1230 #[must_use]
1231 pub fn maintenance(&self) -> crate::Maintenance {
1232 #[cfg(feature = "sqlite")]
1233 {
1234 crate::Maintenance::new(
1235 self.db.clone(),
1236 self.sqlite_db.clone(),
1237 self.sqlite_path.clone(),
1238 )
1239 }
1240 #[cfg(not(feature = "sqlite"))]
1241 {
1242 crate::Maintenance::new(self.db.clone())
1243 }
1244 }
1245
1246 /// Access revenue recognition (ASC 606) operations.
1247 #[must_use]
1248 pub fn revenue_recognition(&self) -> crate::RevenueRecognition {
1249 #[cfg(feature = "events")]
1250 {
1251 crate::RevenueRecognition::new(self.db.clone(), self.event_system.clone())
1252 }
1253 #[cfg(not(feature = "events"))]
1254 {
1255 crate::RevenueRecognition::new(self.db.clone())
1256 }
1257 }
1258
1259 /// Access vendor return operations.
1260 #[must_use]
1261 pub fn vendor_returns(&self) -> crate::VendorReturns {
1262 crate::VendorReturns::new(self.db.clone())
1263 }
1264
1265 /// Access vendor credit operations.
1266 #[must_use]
1267 pub fn vendor_credits(&self) -> crate::VendorCredits {
1268 crate::VendorCredits::new(self.db.clone())
1269 }
1270
1271 /// Access payment obligation operations.
1272 #[must_use]
1273 pub fn payment_obligations(&self) -> crate::PaymentObligations {
1274 crate::PaymentObligations::new(self.db.clone())
1275 }
1276
1277 /// Access price level (B2B pricing tier) operations.
1278 #[must_use]
1279 pub fn price_levels(&self) -> crate::PriceLevels {
1280 crate::PriceLevels::new(self.db.clone())
1281 }
1282
1283 /// Access prepayment operations.
1284 #[must_use]
1285 pub fn prepayments(&self) -> crate::Prepayments {
1286 crate::Prepayments::new(self.db.clone())
1287 }
1288
1289 /// Access price schedule (time-bounded pricing) operations.
1290 #[must_use]
1291 pub fn price_schedules(&self) -> crate::PriceSchedules {
1292 crate::PriceSchedules::new(self.db.clone())
1293 }
1294
1295 /// Access activity log (subject history) operations.
1296 #[must_use]
1297 pub fn activity_logs(&self) -> crate::ActivityLogs {
1298 crate::ActivityLogs::new(self.db.clone())
1299 }
1300
1301 /// Access integration mapping operations.
1302 #[must_use]
1303 pub fn integration_mappings(&self) -> crate::IntegrationMappings {
1304 crate::IntegrationMappings::new(self.db.clone())
1305 }
1306
1307 /// Access inbound shipment (ASN) operations.
1308 #[must_use]
1309 pub fn inbound_shipments(&self) -> crate::InboundShipments {
1310 crate::InboundShipments::new(self.db.clone())
1311 }
1312
1313 /// Access purgatory (order ingestion staging) operations.
1314 #[must_use]
1315 pub fn purgatory(&self) -> crate::Purgatory {
1316 crate::Purgatory::new(self.db.clone())
1317 }
1318
1319 /// Access print station operations.
1320 #[must_use]
1321 pub fn print_stations(&self) -> crate::PrintStations {
1322 crate::PrintStations::new(self.db.clone())
1323 }
1324
1325 /// Access EDI document operations.
1326 #[must_use]
1327 pub fn edi_documents(&self) -> crate::EdiDocuments {
1328 crate::EdiDocuments::new(self.db.clone())
1329 }
1330
1331 /// Access integration field-mapping operations.
1332 #[must_use]
1333 pub fn integration_field_mappings(&self) -> crate::IntegrationFieldMappings {
1334 crate::IntegrationFieldMappings::new(self.db.clone())
1335 }
1336
1337 /// Access customer operational topology snapshot operations.
1338 #[must_use]
1339 pub fn topology_snapshots(&self) -> crate::TopologySnapshots {
1340 crate::TopologySnapshots::new(self.db.clone())
1341 }
1342
1343 /// Access stock snapshot (point-in-time inventory) operations.
1344 #[must_use]
1345 pub fn stock_snapshots(&self) -> crate::StockSnapshots {
1346 crate::StockSnapshots::new(self.db.clone())
1347 }
1348
1349 /// Access product review operations.
1350 ///
1351 /// Provides review creation, moderation, summaries, and helpful/reported tracking.
1352 #[must_use]
1353 pub fn reviews(&self) -> Reviews {
1354 Reviews::new(self.db.clone())
1355 }
1356
1357 /// Access wishlist operations.
1358 ///
1359 /// Provides wishlist creation, item management, and customer wish tracking.
1360 #[must_use]
1361 pub fn wishlists(&self) -> Wishlists {
1362 Wishlists::new(self.db.clone())
1363 }
1364
1365 /// Access loyalty program operations.
1366 ///
1367 /// Provides loyalty program management, customer enrollment, points tracking,
1368 /// and reward catalog operations.
1369 #[must_use]
1370 pub fn loyalty(&self) -> Loyalty {
1371 Loyalty::new(self.db.clone())
1372 }
1373
1374 /// Access fraud detection operations.
1375 ///
1376 /// Provides fraud risk assessment, rule management, and manual review workflows.
1377 #[must_use]
1378 pub fn fraud(&self) -> Fraud {
1379 Fraud::new(self.db.clone())
1380 }
1381
1382 /// Access search configuration operations.
1383 ///
1384 /// Provides search configuration management including active config selection.
1385 #[must_use]
1386 pub fn search_config(&self) -> SearchConfigs {
1387 SearchConfigs::new(self.db.clone())
1388 }
1389
1390 /// Calculate and apply tax to a cart based on its shipping address.
1391 ///
1392 /// This method:
1393 /// 1. Retrieves the cart and its items
1394 /// 2. Uses the shipping address to determine tax jurisdiction
1395 /// 3. Calculates tax for each item based on jurisdiction and product category
1396 /// 4. Applies customer exemptions if applicable
1397 /// 5. Updates the cart with the calculated tax
1398 ///
1399 /// # Example
1400 ///
1401 /// ```rust,ignore
1402 /// use stateset_embedded::{Commerce, CreateCart, AddCartItem, CartAddress};
1403 /// use rust_decimal_macros::dec;
1404 /// use uuid::Uuid;
1405 ///
1406 /// let commerce = Commerce::new("./store.db")?;
1407 ///
1408 /// // Create a cart with items
1409 /// let cart = commerce.carts().create(CreateCart {
1410 /// customer_email: Some("alice@example.com".into()),
1411 /// ..Default::default()
1412 /// })?;
1413 ///
1414 /// commerce.carts().add_item(cart.id, AddCartItem {
1415 /// sku: "SKU-001".into(),
1416 /// name: "Widget".into(),
1417 /// quantity: 2,
1418 /// unit_price: dec!(29.99),
1419 /// ..Default::default()
1420 /// })?;
1421 ///
1422 /// // Set shipping address
1423 /// commerce.carts().set_shipping_address(cart.id, CartAddress {
1424 /// first_name: "Alice".into(),
1425 /// last_name: "Smith".into(),
1426 /// line1: "123 Main St".into(),
1427 /// city: "Los Angeles".into(),
1428 /// state: Some("CA".into()),
1429 /// postal_code: "90210".into(),
1430 /// country: "US".into(),
1431 /// ..Default::default()
1432 /// })?;
1433 ///
1434 /// // Calculate and apply tax
1435 /// let result = commerce.calculate_cart_tax(cart.id)?;
1436 /// println!("Tax: ${}", result.total_tax);
1437 /// println!("Updated cart total: ${}", commerce.carts().get(cart.id)?.unwrap().grand_total);
1438 /// # Ok::<(), stateset_embedded::CommerceError>(())
1439 /// ```
1440 pub fn calculate_cart_tax(
1441 &self,
1442 cart_id: uuid::Uuid,
1443 ) -> stateset_core::Result<stateset_core::TaxCalculationResult> {
1444 use rust_decimal::Decimal;
1445 use stateset_core::{ProductTaxCategory, TaxAddress, TaxCalculationRequest, TaxLineItem};
1446
1447 let cart_id: stateset_core::CartId = cart_id.into();
1448
1449 // Get the cart
1450 let cart = self.carts().get(cart_id)?.ok_or(stateset_core::CommerceError::NotFound)?;
1451
1452 // Need a shipping address to calculate tax
1453 let shipping_address = cart.shipping_address.ok_or_else(|| {
1454 stateset_core::CommerceError::ValidationError(
1455 "Shipping address required to calculate tax".into(),
1456 )
1457 })?;
1458
1459 // Convert CartAddress to TaxAddress
1460 let tax_address = TaxAddress {
1461 country: shipping_address.country,
1462 state: shipping_address.state,
1463 city: Some(shipping_address.city),
1464 postal_code: Some(shipping_address.postal_code),
1465 line1: Some(shipping_address.line1),
1466 line2: shipping_address.line2,
1467 };
1468
1469 // Convert cart items to TaxLineItems
1470 let line_items: Vec<TaxLineItem> = cart
1471 .items
1472 .iter()
1473 .map(|item| {
1474 TaxLineItem {
1475 id: item.id.to_string(),
1476 sku: Some(item.sku.clone()),
1477 product_id: item.product_id,
1478 quantity: Decimal::from(item.quantity),
1479 unit_price: item.unit_price,
1480 discount_amount: item.discount_amount,
1481 tax_category: ProductTaxCategory::Standard, // Default to standard, can be enhanced
1482 tax_code: None,
1483 description: Some(item.name.clone()),
1484 }
1485 })
1486 .collect();
1487
1488 // Build tax calculation request
1489 let request = TaxCalculationRequest {
1490 line_items,
1491 shipping_address: tax_address,
1492 customer_id: cart.customer_id.map(Into::into),
1493 currency: cart.currency,
1494 shipping_amount: Some(cart.shipping_amount),
1495 ..Default::default()
1496 };
1497
1498 // Calculate tax
1499 let result = self.tax().calculate(request)?;
1500
1501 // Apply tax to cart
1502 self.carts().set_tax(cart_id, result.total_tax)?;
1503
1504 Ok(result)
1505 }
1506
1507 /// Calculate and apply promotions to a cart.
1508 ///
1509 /// This method:
1510 /// 1. Retrieves the cart and its items
1511 /// 2. Finds all applicable automatic promotions
1512 /// 3. Validates any coupon codes applied to the cart
1513 /// 4. Calculates discounts respecting stacking rules
1514 /// 5. Updates the cart with the calculated discount
1515 ///
1516 /// # Example
1517 ///
1518 /// ```rust,ignore
1519 /// use stateset_embedded::{Commerce, CreateCart, AddCartItem};
1520 /// use rust_decimal_macros::dec;
1521 ///
1522 /// let commerce = Commerce::new("./store.db")?;
1523 ///
1524 /// // Create a cart with items
1525 /// let cart = commerce.carts().create(CreateCart {
1526 /// customer_email: Some("alice@example.com".into()),
1527 /// ..Default::default()
1528 /// })?;
1529 ///
1530 /// commerce.carts().add_item(cart.id, AddCartItem {
1531 /// sku: "SKU-001".into(),
1532 /// name: "Widget".into(),
1533 /// quantity: 2,
1534 /// unit_price: dec!(49.99),
1535 /// ..Default::default()
1536 /// })?;
1537 ///
1538 /// // Apply a coupon code
1539 /// commerce.carts().apply_discount(cart.id, "SUMMER20")?;
1540 ///
1541 /// // Calculate and apply promotions
1542 /// let result = commerce.apply_cart_promotions(cart.id)?;
1543 /// println!("Discount: ${}", result.total_discount);
1544 /// println!("Applied promotions: {:?}", result.applied_promotions.len());
1545 ///
1546 /// // Cart now has discount applied
1547 /// let updated_cart = commerce.carts().get(cart.id)?.unwrap();
1548 /// println!("New total: ${}", updated_cart.grand_total);
1549 /// # Ok::<(), stateset_embedded::CommerceError>(())
1550 /// ```
1551 pub fn apply_cart_promotions(
1552 &self,
1553 cart_id: uuid::Uuid,
1554 ) -> stateset_core::Result<stateset_core::ApplyPromotionsResult> {
1555 use stateset_core::{
1556 ApplyPromotionsRequest, PromotionLineItem, UpdateCart, UpdateCartItem,
1557 };
1558
1559 let cart_id: stateset_core::CartId = cart_id.into();
1560
1561 // Get the cart
1562 let cart = self.carts().get(cart_id)?.ok_or(stateset_core::CommerceError::NotFound)?;
1563
1564 // Convert cart items to PromotionLineItems
1565 let line_items: Vec<PromotionLineItem> = cart
1566 .items
1567 .iter()
1568 .map(|item| {
1569 PromotionLineItem {
1570 id: item.id.to_string(),
1571 product_id: item.product_id,
1572 variant_id: item.variant_id,
1573 sku: Some(item.sku.clone()),
1574 category_ids: vec![], // Could be enhanced to load from product
1575 quantity: item.quantity,
1576 unit_price: item.unit_price,
1577 line_total: item.total,
1578 }
1579 })
1580 .collect();
1581
1582 // Build promotion request
1583 let coupon_codes = cart.coupon_code.map(|c| vec![c]).unwrap_or_default();
1584
1585 let request = ApplyPromotionsRequest {
1586 cart_id: Some(cart_id),
1587 customer_id: cart.customer_id,
1588 subtotal: cart.subtotal,
1589 shipping_amount: cart.shipping_amount,
1590 shipping_country: cart.shipping_address.as_ref().map(|a| a.country.clone()),
1591 shipping_state: cart.shipping_address.as_ref().and_then(|a| a.state.clone()),
1592 currency: cart.currency,
1593 coupon_codes,
1594 line_items,
1595 is_first_order: false, // Could check customer order history
1596 };
1597
1598 // Apply promotions
1599 let result = self.promotions().apply(request)?;
1600
1601 let discount_description = result
1602 .applied_promotions
1603 .iter()
1604 .map(|p| p.promotion_name.as_str())
1605 .collect::<Vec<_>>()
1606 .join(", ");
1607
1608 let discount_description =
1609 if discount_description.is_empty() { None } else { Some(discount_description) };
1610
1611 self.carts().update(
1612 cart_id,
1613 UpdateCart {
1614 discount_amount: Some(result.total_discount),
1615 discount_description,
1616 ..Default::default()
1617 },
1618 )?;
1619
1620 // Update individual item discounts if there are line item discounts
1621 for line_discount in &result.line_item_discounts {
1622 if let Ok(item_id) = line_discount.line_item_id.parse::<uuid::Uuid>() {
1623 self.carts().update_item(
1624 item_id,
1625 UpdateCartItem {
1626 discount_amount: Some(line_discount.discount_amount),
1627 ..Default::default()
1628 },
1629 )?;
1630 }
1631 }
1632
1633 // Recalculate cart totals
1634 self.carts().recalculate(cart_id)?;
1635
1636 // Record promotion usage for tracking
1637 for applied in &result.applied_promotions {
1638 // Look up coupon_id if a coupon code was used
1639 let coupon_id = if let Some(ref code) = applied.coupon_code {
1640 self.promotions().get_coupon_by_code(code)?.map(|c| c.id)
1641 } else {
1642 None
1643 };
1644
1645 let _ = self.promotions().record_usage(
1646 applied.promotion_id,
1647 coupon_id,
1648 cart.customer_id,
1649 None, // order_id - will be set when order is created
1650 Some(cart_id),
1651 applied.discount_amount,
1652 cart.currency.as_str(),
1653 );
1654 }
1655
1656 Ok(result)
1657 }
1658}