feat(marketing): add threshold promotions (满减)
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