Shop-scoped threshold rules with bilingual names, integer threshold/reduction (reduction < threshold), active windows and display order. Checkout applies the best eligible rule per shop with currency conversion; coupon/threshold/activity pricing are mutually exclusive per shop order. Reduction persists in orders.discount_minor + threshold_promotion_id and flows into payment totals; checkout idempotency covers the threshold selection. Delete archives referenced rules, hard-deletes unreferenced ones. - migration 0026: threshold_promotions + orders.threshold_promotion_id + coupon/threshold exclusivity CHECK - api: modules/promotion (CRUD, preview, checkout integration) - shared: ThresholdPromotion types, shop CRUD + preview client methods, checkout threshold_by_shop - shop-admin: promotions page + nav + en/zh locales - mall: exclusive promotion radio on checkout, live preview wiring, threshold label on order detail - tests: promotions.rs (scoping, validation, best-rule, exclusivity, activity-priced 409, totals, replay, archive-vs-delete) - openspec: archived 2026-10-19-add-threshold-promotions; spec threshold-promotions created, order/frontend specs updated
53 lines
3.5 KiB
Markdown
53 lines
3.5 KiB
Markdown
# Index: Order & Freight
|
|
|
|
Domain design: `docs/domains/orders.md`. Specs: `openspec/specs/order/`,
|
|
`shipment/`, `shipping/`, `payment/` (change `add-configurable-payments`).
|
|
|
|
## Backend (`apps/api`)
|
|
|
|
| File | Holds |
|
|
|---|---|
|
|
| `src/modules/order/service.rs` | checkout transaction (payment membership + header-hash idempotency), cancel, shipping quote |
|
|
| `src/modules/order/repo.rs` | `ORDER_COLS`/`ORDER_ITEM_COLS`, insert_order/insert_item, locks, status transitions |
|
|
| `src/modules/order/handlers.rs` | `/orders*` customer routes, `/shop/orders*`, `/admin/orders` |
|
|
| `src/modules/order/dto.rs` | OrderView, AddressBody, ShippingQuoteView |
|
|
| `src/modules/payment/service.rs` | payment resolution, eligible methods, attempts, wallet collection, group cancellation |
|
|
| `src/modules/payment/repo.rs` | payments/memberships/checkout_requests/attempts/receipts/refunds/commands/events rows |
|
|
| `src/modules/payment/adapters.rs` | wallet + Stripe crypto-only Checkout adapter boundary, capabilities |
|
|
| `src/modules/payment/worker.rs` | durable command lease/execute/recovery, supervised worker |
|
|
| `src/modules/payment/webhooks.rs` | raw-body Stripe signature/timestamp verification, dedup inbox |
|
|
| `src/modules/payment/refunds.rs` | original-method refund budgets, wallet/Stripe refund submission |
|
|
| `src/modules/payment/admin.rs` | channel CRUD/revisions/audit/verify, operations list/detail, reconcile |
|
|
| `src/modules/payment/handlers.rs` | `/payments*` owner routes, `/admin/payments*`, `/payments/webhooks/stripe/{id}` |
|
|
| `src/modules/payment/dto.rs` | payment DTOs, text enums, config shapes |
|
|
| `src/modules/fulfillment/` | shipments: create (company-validated), ship, confirm-delivered |
|
|
| `src/modules/freight/service.rs` | template CRUD, region rules, `shop_fee()` calculation, company dictionary |
|
|
| `src/modules/freight/handlers.rs` | `/shop/freight-templates*`, `/shipping/companies` |
|
|
| `migrations/0004_orders.sql` | orders/order_items/shipments base schema |
|
|
| `migrations/0017_freight_templates.sql` | freight tables, `orders.shipping_fee_minor`, item snapshots, `skus.weight_grams` |
|
|
| `migrations/0024_payments.sql` | payments domain, legacy-demo provenance, aftersale refund states |
|
|
| `migrations/0025_checkout_request_header_hash.sql` | cart-independent header hash for checkout idempotency |
|
|
| `migrations/0026_threshold_promotions.sql` | threshold rules, `orders.threshold_promotion_id`, coupon/threshold exclusivity check |
|
|
| `tests/orders.rs`, `tests/freight.rs`, `tests/payments.rs` | integration coverage |
|
|
|
|
## Shared contract (`packages/shared/src`)
|
|
|
|
`types.ts`: `Order`, `OrderItem`, `Shipment`, `FreightTemplate*`,
|
|
`ShippingCompany`, `ShippingQuote`, `Payment`, `CheckoutResult`,
|
|
`PaymentAttemptResult`, `EligibleMethod`, `NextAction`, `PaymentChannel*`,
|
|
`PaymentOperation*`, `RefundOperation`. `api.ts`: `checkout`,
|
|
`resolvePayment`, `getPayment`, `listPaymentMethods`, `createPaymentAttempt`,
|
|
`cancelPayment`, `quoteShipping`, `listShippingCompanies`, shop freight CRUD,
|
|
`createShipment`, admin channel/operations/reconcile methods.
|
|
|
|
## Frontends
|
|
|
|
- Mall: `pages/checkout/{index,pay,success}.vue`, `pages/user/orders/`,
|
|
`pages/user/addresses.vue`
|
|
- Mobile: `pages/checkout/`, `pages/orders/` (configured payment + return handling)
|
|
- Shop-admin: `pages/orders/`, `pages/shipments.vue`,
|
|
`pages/freight-templates.vue`, `components/ProductForm.vue`
|
|
(freight template + SKU weight)
|
|
- Admin: `pages/orders.vue` (read-only), `pages/payment-channels.vue`,
|
|
`pages/payments.vue` (operations list/detail/reconcile)
|