# order Specification ## Purpose Checkout splitting a cart into per-shop orders, plus order lifecycle and ownership. ## Requirements ### Requirement: Checkout splits by shop `POST /api/orders/checkout` SHALL create one order per distinct shop in the cart, in a single database transaction: stock decrement, order + item insert with price snapshots, cart clear, and requested coupon redemption. All amounts use the cart's SKU currencies converted into the buyer-chosen display currency at checkout time. The request MAY select at most one owned coupon per generated shop order; the server SHALL validate its ownership, shop, status, validity window, threshold, and converted amount, then persist `coupon_id`, `discount_minor`, and the post-discount `total_minor`. The client SHALL NOT provide a discount amount. This requirement does not define activity prices; a later flash-sale or group-buying change that rewrites checkout SHALL restate these coupon clauses and SHALL reject a coupon on any shop order that applied an activity price. #### Scenario: two shops → two orders - **WHEN** the cart contains SKUs from shops A and B - **THEN** two orders are created, each with only its shop's items, and the cart is empty #### Scenario: insufficient stock - **WHEN** any line's qty exceeds SKU stock - **THEN** the whole checkout returns 409 and no order is created and stock is unchanged #### Scenario: coupon applies to one matching shop - **WHEN** the customer selects an eligible coupon issued by shop A for a cart containing shops A and B - **THEN** only shop A's order records that coupon and its server-calculated discount ### Requirement: Order lifecycle Status transitions SHALL be: pending_payment → paid → fulfilling → shipped → completed; cancellable only from pending_payment, which MUST restore stock and restore a redeemed coupon to claimed status when the order has one. #### Scenario: cancel restores stock - **WHEN** a customer cancels a pending_payment order - **THEN** stock of each SKU increases by the ordered qty and status is cancelled #### Scenario: cancel restores coupon - **WHEN** a customer cancels a pending_payment order with a redeemed coupon - **THEN** the coupon is detached from the order and becomes claimed #### Scenario: illegal transition rejected - **WHEN** cancelling a paid order via the customer endpoint - **THEN** the API returns 409 ### Requirement: Order ownership Customers SHALL see only their own orders; shop roles only their shop's orders; platform_admin sees all. #### Scenario: cross-customer read denied - **WHEN** customer X requests customer Y's order id - **THEN** the API returns 404