Files
vmall/openspec/changes/add-freight-templates/tasks.md
T

4.6 KiB

1. Migration and shared contract

  • 1.1 Add migration 0017_freight_templates.sql: freight_templates (shop FK, name, default flag with a partial unique index per shop, always-free toggle, by_piece/by_weight pricing method, first/additional unit fees as i64 minor units, integer first/additional unit sizes in pieces or grams, optional free-shipping threshold in i64 minor units), freight_region_rules (template FK, region code set, overriding fees and unit sizes), shipping_companies (code, {en, zh} JSONB name), orders.shipping_fee_minor, order_items pricing-method and template-id snapshot columns, and shipments.shipping_company_code, with shop/template indexes and cascading deletes.
  • 1.2 Add shared freight template, region rule, shipping company, and checkout shipping-quote types plus @vmall/shared API methods for merchant template CRUD, region-rule editing, company listing, and checkout fee quoting; all money in i64 minor units and weights in integer grams, no floats.
  • 1.3 Implement apps/api/src/modules/freight/ repository, service, DTO, handlers, and module registration with shop routes scoped through own_shop and services returning ApiResult<Dto>; add a product-to-template link on the product edit contract, rejecting templates of another shop.

2. Calculation service and tests

  • 2.1 Implement the pure shipping calculation service: per-shop grouping by resolved template (product template first, shop default second, zero fee fallback), quantity or integer-weight merging within a group, first-unit fee plus per-additional-unit fees with part units rounding up, always-free and free-shipping-threshold checks before fees, and region-rule fee overrides for matching destinations.
  • 2.2 Wire checkout to the calculation service in the order-creation transaction: require the destination address, compute each shop order's fee server-side ignoring client amounts, add it to the order total, and persist shipping_fee_minor plus per-item pricing-method and template snapshots.
  • 2.3 Add focused calculation tests at the boundaries: free-shipping threshold met and unmet, region rule overriding default fees, mixed templates in one shop order, partial additional-unit rounding, by-weight versus by-piece merging, and the no-template zero-fee fallback.

3. Shop-admin pages

  • 3.1 Build the shop-admin freight template management page (list, create/edit, default toggle, always-free and threshold fields, pricing method and unit sizes, region-rule editor, delete) reading and writing through @vmall/shared, styled with @vmall/ui primitives and shared tokens, with a navigation entry beside existing shop operations.
  • 3.2 Extend the shop-admin fulfillment flow with a shipping-company selector populated from the shared dictionary, required before marking an order shipped, showing the recorded company afterwards.

4. Mall checkout and mock

  • 4.1 Implement the shared shipping-quote and company client methods in apps/mall/mock/api.ts with deterministic fixture templates (per-shop by-piece and by-weight cases plus one region override), and register the shipping surface in Mall API selection with exact shared-client method picks, enabling it in the default live configuration alongside LIVE_PICKS.
  • 4.2 Update Mall checkout to select the shipping address before quoting, render each shop group's server-computed delivery fee and the combined shipping total in the selected currency, and show the persisted shipping_fee on payment and order detail.
  • 4.3 Add bilingual en/zh checkout shipping strings through the existing Mall locale source without per-page hard-coded copy.

5. Verification and tracker cleanup

  • 5.1 Add isolated API integration tests in apps/api/tests/, reusing the tests/common/mod.rs fixtures, covering freight template CRUD with own_shop isolation and single-default enforcement, checkout fee persistence and totals for multi-shop carts, region-rule and free-shipping-threshold edges, snapshot stability after template edits, and shipping-company selection and rejection of unknown companies.
  • 5.2 Build the affected frontends because the shared contract changes: pnpm --filter @vmall/shop-admin build, pnpm --filter @vmall/mall build, and pnpm --filter @vmall/admin build.
  • 5.3 Browser-smoke the running stack: create a template with a region rule in shop-admin, run a two-shop Mall checkout showing per-shop fees and totals, change the address to see fees update, pay, and ship with a selected company.
  • 5.4 Run openspec change validate add-freight-templates --strict and openspec validate --all --strict, and check every OpenSpec task.