@aglyn/plugins-commerce 1.0.0-beta.229 → 1.0.0-beta.231
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +13 -13
- package/src/index.d.ts +0 -1
- package/src/index.js +0 -1
- package/src/index.js.map +1 -1
- package/src/lib/barcode/barcode-decode.d.ts +71 -0
- package/src/lib/barcode/barcode-decode.js +498 -0
- package/src/lib/barcode/barcode-decode.js.map +1 -0
- package/src/lib/barcode/barcode-encode.d.ts +44 -0
- package/src/lib/barcode/barcode-encode.js +138 -0
- package/src/lib/barcode/barcode-encode.js.map +1 -0
- package/src/lib/barcode/barcode-scanner.component.d.ts +23 -0
- package/src/lib/barcode/barcode-scanner.component.js +260 -0
- package/src/lib/barcode/barcode-scanner.component.js.map +1 -0
- package/src/lib/barcode/scan-button.component.d.ts +10 -0
- package/src/lib/barcode/scan-button.component.js +62 -0
- package/src/lib/barcode/scan-button.component.js.map +1 -0
- package/src/lib/barcode/scanner-wedge.d.ts +35 -0
- package/src/lib/barcode/scanner-wedge.js +108 -0
- package/src/lib/barcode/scanner-wedge.js.map +1 -0
- package/src/lib/components/account.js +10 -1
- package/src/lib/components/account.js.map +1 -1
- package/src/lib/components/cart-extras.d.ts +45 -0
- package/src/lib/components/cart-extras.js +127 -0
- package/src/lib/components/cart-extras.js.map +1 -0
- package/src/lib/components/cart.js +82 -15
- package/src/lib/components/cart.js.map +1 -1
- package/src/lib/components/checkout-return-notice.d.ts +26 -0
- package/src/lib/components/checkout-return-notice.js +48 -0
- package/src/lib/components/checkout-return-notice.js.map +1 -0
- package/src/lib/components/commerce-console-page.js +124 -0
- package/src/lib/components/commerce-console-page.js.map +1 -1
- package/src/lib/components/commerce-console-sections.d.ts +1 -1
- package/src/lib/components/commerce-console-sections.js +4 -0
- package/src/lib/components/commerce-console-sections.js.map +1 -1
- package/src/lib/components/console/bulk-fulfill.d.ts +44 -0
- package/src/lib/components/console/bulk-fulfill.js +84 -0
- package/src/lib/components/console/bulk-fulfill.js.map +1 -0
- package/src/lib/components/console/customer-notifications-card.component.d.ts +19 -0
- package/src/lib/components/console/customer-notifications-card.component.js +149 -0
- package/src/lib/components/console/customer-notifications-card.component.js.map +1 -0
- package/src/lib/components/console/host-orders-card.component.js +84 -5
- package/src/lib/components/console/host-orders-card.component.js.map +1 -1
- package/src/lib/components/console/locations-card.component.js +164 -57
- package/src/lib/components/console/locations-card.component.js.map +1 -1
- package/src/lib/components/console/order-detail-dialog.component.js +209 -61
- package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
- package/src/lib/components/console/order-fulfillment-panel.component.d.ts +48 -0
- package/src/lib/components/console/order-fulfillment-panel.component.js +542 -0
- package/src/lib/components/console/order-fulfillment-panel.component.js.map +1 -0
- package/src/lib/components/console/order-invoice.component.d.ts +33 -0
- package/src/lib/components/console/order-invoice.component.js +81 -0
- package/src/lib/components/console/order-invoice.component.js.map +1 -0
- package/src/lib/components/console/order-receipt-resend.component.d.ts +21 -0
- package/src/lib/components/console/order-receipt-resend.component.js +203 -0
- package/src/lib/components/console/order-receipt-resend.component.js.map +1 -0
- package/src/lib/components/console/order-returns.component.d.ts +36 -0
- package/src/lib/components/console/order-returns.component.js +142 -0
- package/src/lib/components/console/order-returns.component.js.map +1 -0
- package/src/lib/components/console/order-shipping-actions.component.d.ts +54 -0
- package/src/lib/components/console/order-shipping-actions.component.js +149 -0
- package/src/lib/components/console/order-shipping-actions.component.js.map +1 -0
- package/src/lib/components/console/order-webhooks-card.component.d.ts +50 -0
- package/src/lib/components/console/order-webhooks-card.component.js +623 -0
- package/src/lib/components/console/order-webhooks-card.component.js.map +1 -0
- package/src/lib/components/console/order-zones.d.ts +155 -0
- package/src/lib/components/console/order-zones.js +40 -0
- package/src/lib/components/console/order-zones.js.map +1 -0
- package/src/lib/components/console/payment-methods-card.component.d.ts +67 -0
- package/src/lib/components/console/payment-methods-card.component.js +395 -0
- package/src/lib/components/console/payment-methods-card.component.js.map +1 -0
- package/src/lib/components/console/pos/pos-api.d.ts +124 -0
- package/src/lib/components/console/pos/pos-api.js +101 -0
- package/src/lib/components/console/pos/pos-api.js.map +1 -0
- package/src/lib/components/console/pos/pos-cart-panel.component.d.ts +36 -0
- package/src/lib/components/console/pos/pos-cart-panel.component.js +160 -0
- package/src/lib/components/console/pos/pos-cart-panel.component.js.map +1 -0
- package/src/lib/components/console/pos/pos-item-dialog.component.d.ts +39 -0
- package/src/lib/components/console/pos/pos-item-dialog.component.js +352 -0
- package/src/lib/components/console/pos/pos-item-dialog.component.js.map +1 -0
- package/src/lib/components/console/pos/pos-product-grid.component.d.ts +47 -0
- package/src/lib/components/console/pos/pos-product-grid.component.js +272 -0
- package/src/lib/components/console/pos/pos-product-grid.component.js.map +1 -0
- package/src/lib/components/console/pos/pos-receipt-panel.component.d.ts +27 -0
- package/src/lib/components/console/pos/pos-receipt-panel.component.js +282 -0
- package/src/lib/components/console/pos/pos-receipt-panel.component.js.map +1 -0
- package/src/lib/components/console/pos/pos-tender-dialogs.component.d.ts +53 -0
- package/src/lib/components/console/pos/pos-tender-dialogs.component.js +445 -0
- package/src/lib/components/console/pos/pos-tender-dialogs.component.js.map +1 -0
- package/src/lib/components/console/pos/pos-tender-panel.component.d.ts +31 -0
- package/src/lib/components/console/pos/pos-tender-panel.component.js +640 -0
- package/src/lib/components/console/pos/pos-tender-panel.component.js.map +1 -0
- package/src/lib/components/console/pos/use-pos-display.d.ts +43 -0
- package/src/lib/components/console/pos/use-pos-display.js +161 -0
- package/src/lib/components/console/pos/use-pos-display.js.map +1 -0
- package/src/lib/components/console/pos-devices-card.component.d.ts +14 -0
- package/src/lib/components/console/pos-devices-card.component.js +546 -0
- package/src/lib/components/console/pos-devices-card.component.js.map +1 -0
- package/src/lib/components/console/pos-display/brand-screen.d.ts +33 -0
- package/src/lib/components/console/pos-display/brand-screen.js +85 -0
- package/src/lib/components/console/pos-display/brand-screen.js.map +1 -0
- package/src/lib/components/console/pos-display/cart-screen.d.ts +29 -0
- package/src/lib/components/console/pos-display/cart-screen.js +166 -0
- package/src/lib/components/console/pos-display/cart-screen.js.map +1 -0
- package/src/lib/components/console/pos-display/pairing-screen.d.ts +24 -0
- package/src/lib/components/console/pos-display/pairing-screen.js +127 -0
- package/src/lib/components/console/pos-display/pairing-screen.js.map +1 -0
- package/src/lib/components/console/pos-display/pos-display-api.d.ts +90 -0
- package/src/lib/components/console/pos-display/pos-display-api.js +140 -0
- package/src/lib/components/console/pos-display/pos-display-api.js.map +1 -0
- package/src/lib/components/console/pos-display/receipt-screen.d.ts +35 -0
- package/src/lib/components/console/pos-display/receipt-screen.js +200 -0
- package/src/lib/components/console/pos-display/receipt-screen.js.map +1 -0
- package/src/lib/components/console/pos-display/tip-screen.d.ts +36 -0
- package/src/lib/components/console/pos-display/tip-screen.js +211 -0
- package/src/lib/components/console/pos-display/tip-screen.js.map +1 -0
- package/src/lib/components/console/pos-display-page.component.d.ts +16 -0
- package/src/lib/components/console/pos-display-page.component.js +407 -0
- package/src/lib/components/console/pos-display-page.component.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-customer-lookup.component.d.ts +40 -0
- package/src/lib/components/console/pos-ops/pos-customer-lookup.component.js +289 -0
- package/src/lib/components/console/pos-ops/pos-customer-lookup.component.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-last-receipt.component.d.ts +34 -0
- package/src/lib/components/console/pos-ops/pos-last-receipt.component.js +61 -0
- package/src/lib/components/console/pos-ops/pos-last-receipt.component.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-operations-bar.component.d.ts +38 -0
- package/src/lib/components/console/pos-ops/pos-operations-bar.component.js +129 -0
- package/src/lib/components/console/pos-ops/pos-operations-bar.component.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-ops-api.d.ts +37 -0
- package/src/lib/components/console/pos-ops/pos-ops-api.js +60 -0
- package/src/lib/components/console/pos-ops/pos-ops-api.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-pin-pad.component.d.ts +48 -0
- package/src/lib/components/console/pos-ops/pos-pin-pad.component.js +220 -0
- package/src/lib/components/console/pos-ops/pos-pin-pad.component.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-receipt-actions.component.d.ts +63 -0
- package/src/lib/components/console/pos-ops/pos-receipt-actions.component.js +186 -0
- package/src/lib/components/console/pos-ops/pos-receipt-actions.component.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-receipt.d.ts +39 -0
- package/src/lib/components/console/pos-ops/pos-receipt.js +182 -0
- package/src/lib/components/console/pos-ops/pos-receipt.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-return-dialog.component.d.ts +40 -0
- package/src/lib/components/console/pos-ops/pos-return-dialog.component.js +465 -0
- package/src/lib/components/console/pos-ops/pos-return-dialog.component.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-shift-history-card.component.d.ts +29 -0
- package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js +253 -0
- package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-shift-panel.component.d.ts +34 -0
- package/src/lib/components/console/pos-ops/pos-shift-panel.component.js +494 -0
- package/src/lib/components/console/pos-ops/pos-shift-panel.component.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-shift-report.component.d.ts +37 -0
- package/src/lib/components/console/pos-ops/pos-shift-report.component.js +102 -0
- package/src/lib/components/console/pos-ops/pos-shift-report.component.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-staff-pins-card.component.d.ts +30 -0
- package/src/lib/components/console/pos-ops/pos-staff-pins-card.component.js +277 -0
- package/src/lib/components/console/pos-ops/pos-staff-pins-card.component.js.map +1 -0
- package/src/lib/components/console/pos-ops/register-ops.d.ts +28 -0
- package/src/lib/components/console/pos-ops/register-ops.js +28 -0
- package/src/lib/components/console/pos-ops/register-ops.js.map +1 -0
- package/src/lib/components/console/pos-ops/use-pos-cashier.d.ts +46 -0
- package/src/lib/components/console/pos-ops/use-pos-cashier.js +128 -0
- package/src/lib/components/console/pos-ops/use-pos-cashier.js.map +1 -0
- package/src/lib/components/console/pos-ops/use-pos-sale-receipt.d.ts +36 -0
- package/src/lib/components/console/pos-ops/use-pos-sale-receipt.js +64 -0
- package/src/lib/components/console/pos-ops/use-pos-sale-receipt.js.map +1 -0
- package/src/lib/components/console/pos-page.component.d.ts +13 -5
- package/src/lib/components/console/pos-page.component.js +729 -657
- package/src/lib/components/console/pos-page.component.js.map +1 -1
- package/src/lib/components/console/product-editor-dialog.component.js +51 -7
- package/src/lib/components/console/product-editor-dialog.component.js.map +1 -1
- package/src/lib/components/console/product-labels-dialog.component.d.ts +13 -0
- package/src/lib/components/console/product-labels-dialog.component.js +197 -0
- package/src/lib/components/console/product-labels-dialog.component.js.map +1 -0
- package/src/lib/components/console/product-register-fields.component.d.ts +19 -0
- package/src/lib/components/console/product-register-fields.component.js +241 -0
- package/src/lib/components/console/product-register-fields.component.js.map +1 -0
- package/src/lib/components/console/product-zones.d.ts +58 -2
- package/src/lib/components/console/product-zones.js +10 -2
- package/src/lib/components/console/product-zones.js.map +1 -1
- package/src/lib/components/console/products-hub-card.component.js +51 -11
- package/src/lib/components/console/products-hub-card.component.js.map +1 -1
- package/src/lib/components/console/register-hardware-card.component.d.ts +33 -0
- package/src/lib/components/console/register-hardware-card.component.js +826 -0
- package/src/lib/components/console/register-hardware-card.component.js.map +1 -0
- package/src/lib/components/console/registers-card.component.js +24 -5
- package/src/lib/components/console/registers-card.component.js.map +1 -1
- package/src/lib/components/console/return-actions.d.ts +38 -0
- package/src/lib/components/console/return-actions.js +76 -0
- package/src/lib/components/console/return-actions.js.map +1 -0
- package/src/lib/components/console/return-detail-dialog.component.d.ts +34 -0
- package/src/lib/components/console/return-detail-dialog.component.js +718 -0
- package/src/lib/components/console/return-detail-dialog.component.js.map +1 -0
- package/src/lib/components/console/return-settings-card.component.d.ts +34 -0
- package/src/lib/components/console/return-settings-card.component.js +195 -0
- package/src/lib/components/console/return-settings-card.component.js.map +1 -0
- package/src/lib/components/console/return-zones.d.ts +87 -0
- package/src/lib/components/console/return-zones.js +31 -0
- package/src/lib/components/console/return-zones.js.map +1 -0
- package/src/lib/components/console/returns-card.component.d.ts +45 -0
- package/src/lib/components/console/returns-card.component.js +159 -0
- package/src/lib/components/console/returns-card.component.js.map +1 -0
- package/src/lib/components/console/shipping-settings-card.component.js +161 -5
- package/src/lib/components/console/shipping-settings-card.component.js.map +1 -1
- package/src/lib/components/console/shippingeasy-card.component.d.ts +59 -0
- package/src/lib/components/console/shippingeasy-card.component.js +378 -0
- package/src/lib/components/console/shippingeasy-card.component.js.map +1 -0
- package/src/lib/components/console/shipstation-card.component.d.ts +35 -0
- package/src/lib/components/console/shipstation-card.component.js +345 -0
- package/src/lib/components/console/shipstation-card.component.js.map +1 -0
- package/src/lib/components/console/start-return-dialog.component.d.ts +40 -0
- package/src/lib/components/console/start-return-dialog.component.js +243 -0
- package/src/lib/components/console/start-return-dialog.component.js.map +1 -0
- package/src/lib/components/console/stock-movements-card.component.js +2 -1
- package/src/lib/components/console/stock-movements-card.component.js.map +1 -1
- package/src/lib/components/console/store-settings-card.component.js +2 -66
- package/src/lib/components/console/store-settings-card.component.js.map +1 -1
- package/src/lib/components/console/store-zones.d.ts +42 -0
- package/src/lib/components/console/store-zones.js +39 -0
- package/src/lib/components/console/store-zones.js.map +1 -0
- package/src/lib/components/order-status.d.ts +36 -0
- package/src/lib/components/order-status.js +502 -0
- package/src/lib/components/order-status.js.map +1 -0
- package/src/lib/components/product-detail.js +44 -2
- package/src/lib/components/product-detail.js.map +1 -1
- package/src/lib/components/return-request.d.ts +32 -0
- package/src/lib/components/return-request.js +576 -0
- package/src/lib/components/return-request.js.map +1 -0
- package/src/lib/components/storefront-payment-appearance.d.ts +32 -0
- package/src/lib/components/storefront-payment-appearance.js +114 -0
- package/src/lib/components/storefront-payment-appearance.js.map +1 -0
- package/src/lib/components/storefront-payment-element.d.ts +57 -1
- package/src/lib/components/storefront-payment-element.js +332 -33
- package/src/lib/components/storefront-payment-element.js.map +1 -1
- package/src/lib/constants/order-status.d.ts +22 -0
- package/src/lib/constants/order-status.js +22 -0
- package/src/lib/constants/order-status.js.map +1 -0
- package/src/lib/constants/return-request.d.ts +27 -0
- package/src/lib/constants/return-request.js +32 -0
- package/src/lib/constants/return-request.js.map +1 -0
- package/src/lib/constants/stock-movement-query.js +2 -1
- package/src/lib/constants/stock-movement-query.js.map +1 -1
- package/src/lib/declarations.console-server.js +9 -0
- package/src/lib/declarations.console-server.js.map +1 -1
- package/src/lib/declarations.server.d.ts +2 -1
- package/src/lib/declarations.server.js +47 -1
- package/src/lib/declarations.server.js.map +1 -1
- package/src/lib/model/buyer-notifications.d.ts +59 -0
- package/src/lib/model/buyer-notifications.js +97 -0
- package/src/lib/model/buyer-notifications.js.map +1 -0
- package/src/lib/model/commerce-orders.d.ts +127 -1
- package/src/lib/model/commerce-orders.js +24 -15
- package/src/lib/model/commerce-orders.js.map +1 -1
- package/src/lib/model/commerce-payment-methods.d.ts +146 -0
- package/src/lib/model/commerce-payment-methods.js +247 -0
- package/src/lib/model/commerce-payment-methods.js.map +1 -0
- package/src/lib/model/commerce-pos-ops.d.ts +437 -0
- package/src/lib/model/commerce-pos-ops.js +721 -0
- package/src/lib/model/commerce-pos-ops.js.map +1 -0
- package/src/lib/model/commerce-pos.d.ts +263 -0
- package/src/lib/model/commerce-pos.js +375 -0
- package/src/lib/model/commerce-pos.js.map +1 -0
- package/src/lib/model/commerce-printers.d.ts +211 -0
- package/src/lib/model/commerce-printers.js +181 -0
- package/src/lib/model/commerce-printers.js.map +1 -0
- package/src/lib/model/commerce-receipt.d.ts +97 -0
- package/src/lib/model/commerce-receipt.js +180 -0
- package/src/lib/model/commerce-receipt.js.map +1 -0
- package/src/lib/model/commerce-returns.d.ts +207 -0
- package/src/lib/model/commerce-returns.js +300 -0
- package/src/lib/model/commerce-returns.js.map +1 -0
- package/src/lib/model/commerce-shipping.d.ts +44 -1
- package/src/lib/model/commerce-shipping.js +53 -9
- package/src/lib/model/commerce-shipping.js.map +1 -1
- package/src/lib/model/commerce-tax-engine.d.ts +90 -0
- package/src/lib/model/commerce-tax-engine.js +129 -0
- package/src/lib/model/commerce-tax-engine.js.map +1 -0
- package/src/lib/model/commerce.d.ts +88 -2
- package/src/lib/model/commerce.js +89 -1
- package/src/lib/model/commerce.js.map +1 -1
- package/src/lib/model/index.d.ts +15 -0
- package/src/lib/model/index.js +15 -0
- package/src/lib/model/index.js.map +1 -1
- package/src/lib/model/order-events.d.ts +154 -0
- package/src/lib/model/order-events.js +153 -0
- package/src/lib/model/order-events.js.map +1 -0
- package/src/lib/model/order-fulfillment.d.ts +117 -0
- package/src/lib/model/order-fulfillment.js +217 -0
- package/src/lib/model/order-fulfillment.js.map +1 -0
- package/src/lib/model/order-history.d.ts +58 -0
- package/src/lib/model/order-history.js +22 -0
- package/src/lib/model/order-history.js.map +1 -0
- package/src/lib/model/order-list-fields.d.ts +9 -1
- package/src/lib/model/order-list-fields.js +7 -1
- package/src/lib/model/order-list-fields.js.map +1 -1
- package/src/lib/model/order-shipping-export.d.ts +91 -0
- package/src/lib/model/order-shipping-export.js +192 -0
- package/src/lib/model/order-shipping-export.js.map +1 -0
- package/src/lib/model/order-status-view.d.ts +103 -0
- package/src/lib/model/order-status-view.js +156 -0
- package/src/lib/model/order-status-view.js.map +1 -0
- package/src/lib/model/order-webhooks.d.ts +142 -0
- package/src/lib/model/order-webhooks.js +91 -0
- package/src/lib/model/order-webhooks.js.map +1 -0
- package/src/lib/model/product-channel.d.ts +56 -0
- package/src/lib/model/product-channel.js +86 -0
- package/src/lib/model/product-channel.js.map +1 -0
- package/src/lib/model/product-modifiers.d.ts +80 -0
- package/src/lib/model/product-modifiers.js +140 -0
- package/src/lib/model/product-modifiers.js.map +1 -0
- package/src/lib/model/shippingeasy.d.ts +94 -0
- package/src/lib/model/shippingeasy.js +267 -0
- package/src/lib/model/shippingeasy.js.map +1 -0
- package/src/lib/model/shipstation.d.ts +125 -0
- package/src/lib/model/shipstation.js +399 -0
- package/src/lib/model/shipstation.js.map +1 -0
- package/src/lib/model/smart-collection-reads.d.ts +32 -0
- package/src/lib/model/smart-collection-reads.js +63 -0
- package/src/lib/model/smart-collection-reads.js.map +1 -0
- package/src/lib/model/tracking-url.d.ts +74 -0
- package/src/lib/model/tracking-url.js +159 -0
- package/src/lib/model/tracking-url.js.map +1 -0
- package/src/lib/plugin-config.d.ts +13 -0
- package/src/lib/plugin-config.js +77 -5
- package/src/lib/plugin-config.js.map +1 -1
- package/src/lib/plugin.js +23 -0
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/pos-ops-config.d.ts +39 -0
- package/src/lib/pos-ops-config.js +88 -0
- package/src/lib/pos-ops-config.js.map +1 -0
- package/src/lib/printing/print-document.d.ts +106 -0
- package/src/lib/printing/print-document.js +464 -0
- package/src/lib/printing/print-document.js.map +1 -0
- package/src/lib/printing/product-labels.d.ts +58 -0
- package/src/lib/printing/product-labels.js +116 -0
- package/src/lib/printing/product-labels.js.map +1 -0
- package/src/lib/printing/render-epson.d.ts +57 -0
- package/src/lib/printing/render-epson.js +135 -0
- package/src/lib/printing/render-epson.js.map +1 -0
- package/src/lib/printing/render-star.d.ts +45 -0
- package/src/lib/printing/render-star.js +100 -0
- package/src/lib/printing/render-star.js.map +1 -0
- package/src/lib/printing/render-text.d.ts +25 -0
- package/src/lib/printing/render-text.js +53 -0
- package/src/lib/printing/render-text.js.map +1 -0
- package/src/lib/server/api-v1/openapi.js +27 -4
- package/src/lib/server/api-v1/openapi.js.map +1 -1
- package/src/lib/server/api-v1/order-view.d.ts +67 -0
- package/src/lib/server/api-v1/order-view.js +120 -0
- package/src/lib/server/api-v1/order-view.js.map +1 -0
- package/src/lib/server/api-v1/orders-and-products.js +58 -65
- package/src/lib/server/api-v1/orders-and-products.js.map +1 -1
- package/src/lib/server/billing-webhook.js +135 -28
- package/src/lib/server/billing-webhook.js.map +1 -1
- package/src/lib/server/cancel-order.js +29 -0
- package/src/lib/server/cancel-order.js.map +1 -1
- package/src/lib/server/carrier-rates-availability.d.ts +26 -0
- package/src/lib/server/carrier-rates-availability.js +76 -0
- package/src/lib/server/carrier-rates-availability.js.map +1 -0
- package/src/lib/server/carrier-shipping.d.ts +84 -0
- package/src/lib/server/carrier-shipping.js +135 -0
- package/src/lib/server/carrier-shipping.js.map +1 -0
- package/src/lib/server/cart-checkout.d.ts +2 -0
- package/src/lib/server/cart-checkout.js +226 -22
- package/src/lib/server/cart-checkout.js.map +1 -1
- package/src/lib/server/checkout-extras.d.ts +64 -0
- package/src/lib/server/checkout-extras.js +157 -0
- package/src/lib/server/checkout-extras.js.map +1 -0
- package/src/lib/server/{feed.d.ts → checkout-status.d.ts} +2 -7
- package/src/lib/server/checkout-status.js +111 -0
- package/src/lib/server/checkout-status.js.map +1 -0
- package/src/lib/server/checkout.js +86 -9
- package/src/lib/server/checkout.js.map +1 -1
- package/src/lib/server/draft-order.js +34 -5
- package/src/lib/server/draft-order.js.map +1 -1
- package/src/lib/server/fulfill-order.d.ts +127 -10
- package/src/lib/server/fulfill-order.js +451 -49
- package/src/lib/server/fulfill-order.js.map +1 -1
- package/src/lib/server/legacy-feed.d.ts +28 -0
- package/src/lib/server/legacy-feed.js +52 -0
- package/src/lib/server/legacy-feed.js.map +1 -0
- package/src/lib/server/native-checkout.d.ts +34 -15
- package/src/lib/server/native-checkout.js +32 -17
- package/src/lib/server/native-checkout.js.map +1 -1
- package/src/lib/server/order-event-host-emit.d.ts +23 -0
- package/src/lib/server/order-event-host-emit.js +30 -0
- package/src/lib/server/order-event-host-emit.js.map +1 -0
- package/src/lib/server/order-event-triggers.d.ts +37 -0
- package/src/lib/server/order-event-triggers.js +119 -0
- package/src/lib/server/order-event-triggers.js.map +1 -0
- package/src/lib/server/order-events.d.ts +62 -0
- package/src/lib/server/order-events.js +109 -0
- package/src/lib/server/order-events.js.map +1 -0
- package/src/lib/server/order-history.d.ts +23 -0
- package/src/lib/server/order-history.js +65 -0
- package/src/lib/server/order-history.js.map +1 -0
- package/src/lib/server/order-notifications.d.ts +185 -0
- package/src/lib/server/order-notifications.js +567 -0
- package/src/lib/server/order-notifications.js.map +1 -0
- package/src/lib/server/order-receipt-send.d.ts +39 -0
- package/src/lib/server/order-receipt-send.js +151 -0
- package/src/lib/server/order-receipt-send.js.map +1 -0
- package/src/lib/server/order-status-token.d.ts +31 -0
- package/src/lib/server/order-status-token.js +75 -0
- package/src/lib/server/order-status-token.js.map +1 -0
- package/src/lib/server/order-status.d.ts +58 -0
- package/src/lib/server/order-status.js +141 -0
- package/src/lib/server/order-status.js.map +1 -0
- package/src/lib/server/order-webhooks.d.ts +108 -0
- package/src/lib/server/order-webhooks.js +622 -0
- package/src/lib/server/order-webhooks.js.map +1 -0
- package/src/lib/server/orders-shipping-prepare.d.ts +26 -0
- package/src/lib/server/orders-shipping-prepare.js +121 -0
- package/src/lib/server/orders-shipping-prepare.js.map +1 -0
- package/src/lib/server/payment-method-domains.d.ts +209 -0
- package/src/lib/server/payment-method-domains.js +444 -0
- package/src/lib/server/payment-method-domains.js.map +1 -0
- package/src/lib/server/payment-methods.d.ts +77 -0
- package/src/lib/server/payment-methods.js +284 -0
- package/src/lib/server/payment-methods.js.map +1 -0
- package/src/lib/server/pos-auth.d.ts +50 -0
- package/src/lib/server/pos-auth.js +121 -0
- package/src/lib/server/pos-auth.js.map +1 -0
- package/src/lib/server/pos-customer.d.ts +49 -0
- package/src/lib/server/pos-customer.js +257 -0
- package/src/lib/server/pos-customer.js.map +1 -0
- package/src/lib/server/pos-display.d.ts +57 -0
- package/src/lib/server/pos-display.js +419 -0
- package/src/lib/server/pos-display.js.map +1 -0
- package/src/lib/server/pos-fee-month.d.ts +34 -0
- package/src/lib/server/pos-fee-month.js +36 -0
- package/src/lib/server/pos-fee-month.js.map +1 -0
- package/src/lib/server/pos-ops-gate.d.ts +161 -0
- package/src/lib/server/pos-ops-gate.js +295 -0
- package/src/lib/server/pos-ops-gate.js.map +1 -0
- package/src/lib/server/pos-ops-routes.d.ts +22 -0
- package/src/lib/server/pos-ops-routes.js +36 -0
- package/src/lib/server/pos-ops-routes.js.map +1 -0
- package/src/lib/server/pos-order.d.ts +1 -18
- package/src/lib/server/pos-order.js +222 -42
- package/src/lib/server/pos-order.js.map +1 -1
- package/src/lib/server/pos-payment.d.ts +39 -0
- package/src/lib/server/pos-payment.js +922 -0
- package/src/lib/server/pos-payment.js.map +1 -0
- package/src/lib/server/pos-print.d.ts +82 -0
- package/src/lib/server/pos-print.js +193 -0
- package/src/lib/server/pos-print.js.map +1 -0
- package/src/lib/server/pos-readers.d.ts +27 -0
- package/src/lib/server/pos-readers.js +276 -0
- package/src/lib/server/pos-readers.js.map +1 -0
- package/src/lib/server/pos-refund-authority.d.ts +60 -0
- package/src/lib/server/pos-refund-authority.js +72 -0
- package/src/lib/server/pos-refund-authority.js.map +1 -0
- package/src/lib/server/pos-return.d.ts +58 -0
- package/src/lib/server/pos-return.js +891 -0
- package/src/lib/server/pos-return.js.map +1 -0
- package/src/lib/server/pos-sale-stamp.d.ts +66 -0
- package/src/lib/server/pos-sale-stamp.js +84 -0
- package/src/lib/server/pos-sale-stamp.js.map +1 -0
- package/src/lib/server/pos-sale.d.ts +170 -0
- package/src/lib/server/pos-sale.js +461 -0
- package/src/lib/server/pos-sale.js.map +1 -0
- package/src/lib/server/pos-shift.d.ts +45 -0
- package/src/lib/server/pos-shift.js +484 -0
- package/src/lib/server/pos-shift.js.map +1 -0
- package/src/lib/server/pos-staff-pin.d.ts +26 -0
- package/src/lib/server/pos-staff-pin.js +339 -0
- package/src/lib/server/pos-staff-pin.js.map +1 -0
- package/src/lib/server/pos-stripe.d.ts +91 -0
- package/src/lib/server/pos-stripe.js +129 -0
- package/src/lib/server/pos-stripe.js.map +1 -0
- package/src/lib/server/pos-terminal-connection-token.d.ts +48 -0
- package/src/lib/server/pos-terminal-connection-token.js +166 -0
- package/src/lib/server/pos-terminal-connection-token.js.map +1 -0
- package/src/lib/server/pos-terminal.d.ts +218 -0
- package/src/lib/server/pos-terminal.js +1014 -0
- package/src/lib/server/pos-terminal.js.map +1 -0
- package/src/lib/server/print-queue.d.ts +124 -0
- package/src/lib/server/print-queue.js +301 -0
- package/src/lib/server/print-queue.js.map +1 -0
- package/src/lib/server/printer-poll.d.ts +75 -0
- package/src/lib/server/printer-poll.js +325 -0
- package/src/lib/server/printer-poll.js.map +1 -0
- package/src/lib/server/printer-secret.d.ts +39 -0
- package/src/lib/server/printer-secret.js +56 -0
- package/src/lib/server/printer-secret.js.map +1 -0
- package/src/lib/server/printers.d.ts +114 -0
- package/src/lib/server/printers.js +546 -0
- package/src/lib/server/printers.js.map +1 -0
- package/src/lib/server/product-ai-capability.d.ts +42 -0
- package/src/lib/server/product-ai-capability.js +159 -0
- package/src/lib/server/product-ai-capability.js.map +1 -0
- package/src/lib/server/product-catalog.d.ts +42 -0
- package/src/lib/server/product-catalog.js +305 -0
- package/src/lib/server/product-catalog.js.map +1 -0
- package/src/lib/server/product-drafts.d.ts +119 -0
- package/src/lib/server/product-drafts.js +384 -0
- package/src/lib/server/product-drafts.js.map +1 -0
- package/src/lib/server/refund.js +110 -45
- package/src/lib/server/refund.js.map +1 -1
- package/src/lib/server/reserve.js +2 -0
- package/src/lib/server/reserve.js.map +1 -1
- package/src/lib/server/return-status-action.d.ts +37 -0
- package/src/lib/server/return-status-action.js +57 -0
- package/src/lib/server/return-status-action.js.map +1 -0
- package/src/lib/server/returns.d.ts +119 -0
- package/src/lib/server/returns.js +938 -0
- package/src/lib/server/returns.js.map +1 -0
- package/src/lib/server/shipment-records.d.ts +36 -0
- package/src/lib/server/shipment-records.js +289 -0
- package/src/lib/server/shipment-records.js.map +1 -0
- package/src/lib/server/shipping-connector-gates.d.ts +40 -0
- package/src/lib/server/shipping-connector-gates.js +97 -0
- package/src/lib/server/shipping-connector-gates.js.map +1 -0
- package/src/lib/server/shipping-connectors.d.ts +29 -0
- package/src/lib/server/shipping-connectors.js +236 -0
- package/src/lib/server/shipping-connectors.js.map +1 -0
- package/src/lib/server/shippingeasy.d.ts +238 -0
- package/src/lib/server/shippingeasy.js +787 -0
- package/src/lib/server/shippingeasy.js.map +1 -0
- package/src/lib/server/shipstation.d.ts +129 -0
- package/src/lib/server/shipstation.js +483 -0
- package/src/lib/server/shipstation.js.map +1 -0
- package/src/lib/server/site-page-resolver.d.ts +5 -0
- package/src/lib/server/site-page-resolver.js +156 -1
- package/src/lib/server/site-page-resolver.js.map +1 -1
- package/src/lib/server/stock-levels.d.ts +21 -0
- package/src/lib/server/stock-levels.js +263 -0
- package/src/lib/server/stock-levels.js.map +1 -0
- package/src/lib/server/stripe-refund.d.ts +47 -0
- package/src/lib/server/stripe-refund.js +87 -0
- package/src/lib/server/stripe-refund.js.map +1 -0
- package/src/lib/server/supplier-update.js +46 -5
- package/src/lib/server/supplier-update.js.map +1 -1
- package/src/lib/server/tax-engine-quote.d.ts +47 -0
- package/src/lib/server/tax-engine-quote.js +105 -0
- package/src/lib/server/tax-engine-quote.js.map +1 -0
- package/src/lib/server.js +146 -2
- package/src/lib/server.js.map +1 -1
- package/src/lib/site.js +12 -0
- package/src/lib/site.js.map +1 -1
- package/src/lib/subprocessors.d.ts +26 -0
- package/src/lib/subprocessors.js +50 -0
- package/src/lib/subprocessors.js.map +1 -0
- package/src/lib/tenant-emails.js +461 -3
- package/src/lib/tenant-emails.js.map +1 -1
- package/src/lib/testing/fake-firestore.d.ts +45 -0
- package/src/lib/testing/fake-firestore.js +189 -0
- package/src/lib/testing/fake-firestore.js.map +1 -0
- package/src/lib/testing/memory-firestore.d.ts +123 -0
- package/src/lib/testing/memory-firestore.js +274 -0
- package/src/lib/testing/memory-firestore.js.map +1 -0
- package/src/lib/testing/pos-ops-harness.d.ts +50 -0
- package/src/lib/testing/pos-ops-harness.js +184 -0
- package/src/lib/testing/pos-ops-harness.js.map +1 -0
- package/src/lib/testing/pos-ops-memory-firestore.d.ts +55 -0
- package/src/lib/testing/pos-ops-memory-firestore.js +376 -0
- package/src/lib/testing/pos-ops-memory-firestore.js.map +1 -0
- package/src/lib/transfer/records-transfer.d.ts +11 -1
- package/src/lib/transfer/records-transfer.js +127 -5
- package/src/lib/transfer/records-transfer.js.map +1 -1
- package/src/lib/transfer/records.server.d.ts +9 -2
- package/src/lib/transfer/records.server.js +58 -7
- package/src/lib/transfer/records.server.js.map +1 -1
- package/src/lib/transfer/register-transfer-resources.js +40 -1
- package/src/lib/transfer/register-transfer-resources.js.map +1 -1
- package/src/lib/transfer/register-transfer-ui.js +4 -1
- package/src/lib/transfer/register-transfer-ui.js.map +1 -1
- package/src/lib/transfer/shipping-presets.d.ts +23 -0
- package/src/lib/transfer/shipping-presets.js +156 -0
- package/src/lib/transfer/shipping-presets.js.map +1 -0
- package/src/lib/transfer/tracking-transfer.d.ts +101 -0
- package/src/lib/transfer/tracking-transfer.js +546 -0
- package/src/lib/transfer/tracking-transfer.js.map +1 -0
- package/src/lib/transfer/tracking.server.d.ts +37 -0
- package/src/lib/transfer/tracking.server.js +393 -0
- package/src/lib/transfer/tracking.server.js.map +1 -0
- package/src/lib/transfer/transfer-keys.d.ts +2 -1
- package/src/lib/transfer/transfer-keys.js +6 -2
- package/src/lib/transfer/transfer-keys.js.map +1 -1
- package/src/lib/utils/code128.d.ts +37 -0
- package/src/lib/utils/code128.js +199 -0
- package/src/lib/utils/code128.js.map +1 -0
- package/src/lib/utils/order-invoice.d.ts +55 -0
- package/src/lib/utils/order-invoice.js +127 -0
- package/src/lib/utils/order-invoice.js.map +1 -0
- package/src/lib/utils/use-checkout-return-notice.d.ts +34 -0
- package/src/lib/utils/use-checkout-return-notice.js +78 -0
- package/src/lib/utils/use-checkout-return-notice.js.map +1 -0
- package/src/lib/utils/use-storefront-purchase-event.js +4 -0
- package/src/lib/utils/use-storefront-purchase-event.js.map +1 -1
- package/src/lib/server/feed.js +0 -69
- package/src/lib/server/feed.js.map +0 -1
|
@@ -16,6 +16,9 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
|
16
16
|
* limitations under the License.
|
|
17
17
|
*/ import * as CommerceModel from "../model/index.js";
|
|
18
18
|
import { firebaseAdmin } from "@aglyn/tenant-data-admin";
|
|
19
|
+
import { notifyOrderBuyer } from "./order-notifications.js";
|
|
20
|
+
import { ORDER_CANCELLED_EVENT } from "../model/order-events.js";
|
|
21
|
+
import { raiseOrderEvent } from "./order-events.js";
|
|
19
22
|
import { capRestockLines, resolveTrackedRestockLines, saleReleaseCaps } from "./restock-flag.js";
|
|
20
23
|
/**
|
|
21
24
|
* Cancelling an order RELEASES its stock (AGL-1808) — the opposite of what the
|
|
@@ -170,6 +173,18 @@ import { capRestockLines, resolveTrackedRestockLines, saleReleaseCaps } from "./
|
|
|
170
173
|
}
|
|
171
174
|
};
|
|
172
175
|
}
|
|
176
|
+
// An OPEN register sale that has taken money (AGL-3607) is voided at
|
|
177
|
+
// the register, which hands each payment back first. Cancelling it here
|
|
178
|
+
// would mark it cancelled with a card charge, a gift card debit or a
|
|
179
|
+
// room charge still standing.
|
|
180
|
+
if (order.status === 'pending' && CommerceModel.orderPayments(order).some((payment)=>payment.status === 'succeeded' || payment.status === 'pending') && Array.isArray(order.payments)) {
|
|
181
|
+
return {
|
|
182
|
+
status: 409,
|
|
183
|
+
body: {
|
|
184
|
+
error: 'This register sale has payments on it. Void it at the register, ' + 'which hands each payment back first.'
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
}
|
|
173
188
|
// A POS CARD order's decrement happens in the webhook that pays it —
|
|
174
189
|
// and before AGL-1825 it did not happen AT ALL: the paying branch's
|
|
175
190
|
// decrement was gated on `productId` metadata the register's session
|
|
@@ -288,6 +303,8 @@ import { capRestockLines, resolveTrackedRestockLines, saleReleaseCaps } from "./
|
|
|
288
303
|
const units = releasedLines.reduce((sum, line)=>sum + line.quantity, 0);
|
|
289
304
|
const patch = {
|
|
290
305
|
status: 'cancelled',
|
|
306
|
+
// What a shipping tool's feed asks to learn of the cancel (AGL-3613).
|
|
307
|
+
updatedAtMs: atMs,
|
|
291
308
|
timeline: CommerceModel.appendOrderEvent(order, 'cancelled', units > 0 ? `${units} ${units === 1 ? 'unit' : 'units'} returned to stock` : undefined, atMs)
|
|
292
309
|
};
|
|
293
310
|
// An open restock question about THIS order's stock, raised by a partial
|
|
@@ -351,6 +368,18 @@ import { capRestockLines, resolveTrackedRestockLines, saleReleaseCaps } from "./
|
|
|
351
368
|
});
|
|
352
369
|
}
|
|
353
370
|
}
|
|
371
|
+
// The buyer is told (AGL-3610) — only by the request that cancelled it.
|
|
372
|
+
if (outcome.status === 200 && !outcome.body.alreadyCancelled) {
|
|
373
|
+
await notifyOrderBuyer({
|
|
374
|
+
hostId,
|
|
375
|
+
orderId
|
|
376
|
+
}, 'cancelled');
|
|
377
|
+
await raiseOrderEvent(ORDER_CANCELLED_EVENT, {
|
|
378
|
+
hostId,
|
|
379
|
+
orderId,
|
|
380
|
+
key: 'cancelled'
|
|
381
|
+
});
|
|
382
|
+
}
|
|
354
383
|
return res.status(outcome.status).json(outcome.body);
|
|
355
384
|
} catch (error) {
|
|
356
385
|
// Nothing landed — the transaction is all-or-nothing — so the order is
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/cancel-order.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as CommerceModel from '../model'\nimport { firebaseAdmin } from '@aglyn/tenant-data-admin'\nimport { type PluginApiHandler } from '@aglyn/aglyn/server'\nimport {\n capRestockLines,\n resolveTrackedRestockLines,\n saleReleaseCaps,\n} from './restock-flag'\n\n/**\n * Cancelling an order RELEASES its stock (AGL-1808) — the opposite of what the\n * reversal doors do, and for a structural reason rather than a preference.\n *\n * AGL-1797 refused to increment on a refund or a chargeback because the goods\n * may well be gone: a refund with no return, or a shopper who kept the item and\n * took the money, leaves stock that incrementing would INVENT. It flags and\n * lets the merchant answer. Cancellation carries no such question, and the\n * guarantee is `ORDER_TRANSITIONS`:\n *\n * pending: ['paid', 'cancelled'],\n * paid: ['partially_fulfilled', 'fulfilled', 'cancelled', 'refunded'],\n * partially_fulfilled | fulfilled | delivered: no 'cancelled'\n *\n * so a cancelled order was never fulfilled and nothing ever shipped. The units\n * are still on the shelf; the only wrong number is ours.\n *\n * THE GUARANTEE HAD TO BE ENFORCED BEFORE IT COULD BE RELIED ON, and that is\n * why this is a handler rather than a few lines in the console. The transition\n * table said the right thing but nothing consulted it on the way IN: the order\n * dialog cancelled with a client `updateDoc`, and `canTransitionOrder` only\n * decided whether to render the button. The Firestore rules impose no status\n * machine — an order update is allowed to any admin or editor — so a dialog\n * held open while the order shipped in another tab (or any other client) could\n * write `cancelled` straight onto a `fulfilled` order, and an automatic\n * increment behind that would restock goods already in the post. Re-asking the\n * transition INSIDE the transaction that writes the status is what turns the\n * comment into a guarantee, and it is what makes the release safe.\n *\n * `pending` RELEASES NOTHING, which is the other half the issue's premise\n * missed. Stock is decremented when the money lands, not when the order is\n * written: `draft-order.ts` and the POS card path both open a `pending` order\n * and decrement only in the webhook that pays it. Incrementing on a cancelled\n * `pending` order would invent inventory exactly the way AGL-1797 refused to —\n * so only a `paid` order, the one status reachable here whose sale provably\n * decremented, releases anything.\n *\n * ONE LEDGER, NOT A SECOND STOCK WRITER. The increment goes through\n * `adjustVariantInventory` and logs an `InventoryAdjustment` per line, the same\n * pair the sale paths and the products hub's \"Adjust stock\" write, with the new\n * `cancellation` reason and the `orderId`. An increment with no ledger row\n * would leave the hub's stock history unable to explain a count that moved on\n * its own — the mirror of AGL-1797's argument against writing a row for stock\n * that had NOT moved.\n *\n * ONLY WHAT THE SALE DECREMENTED comes back: `resolveTrackedRestockLines`, the\n * helper AGL-1797 already built, applies the sale path's own\n * `variant.inventory != null` test to the products as they stand now. A store\n * that tracks no stock gets a plain cancellation and no adjustment rows.\n *\n * IT FAILS THE CANCEL RATHER THAN LOSING THE RELEASE. `flagOrderRestock`\n * swallows its errors because the money had already moved and the flag was a\n * postscript; here the status flip and the stock write are one act, so they\n * share a transaction and a failure leaves the order uncancelled for the\n * merchant to retry. A cancelled order whose stock never came back is the\n * original bug.\n *\n * ONCE. The transaction's own read is the guard: a second cancel — a retried\n * request, two admins clicking together — finds `cancelled`, which\n * `canTransitionOrder` cannot leave, and returns without touching stock. Two\n * increments of the same units is the failure mode this shape exists to\n * prevent, and it is measured rather than asserted (`cancel-order.spec.ts`).\n *\n * REACHED FROM THE CONSOLE since AGL-1818: `order-detail-dialog`'s\n * `handleCancel` POSTs here with the console id token, and the client\n * `updateDoc` cancel it replaced is gone. (The wiring landed separately from\n * the route because the dialog belonged to a concurrent agent, AGL-1806,\n * when the route was written.)\n */\nexport const cancelOrderHandler: PluginApiHandler = async (req, res) => {\n if (req.method !== 'POST') {\n return res.status(405).json({ error: 'Method not allowed' })\n }\n const authorization = String(req.headers.authorization ?? '')\n const idToken = authorization.startsWith('Bearer ')\n ? authorization.slice('Bearer '.length)\n : undefined\n if (!idToken) return res.status(401).json({ error: 'Unauthenticated' })\n const body =\n typeof req.body === 'string' ? JSON.parse(req.body) : (req.body ?? {})\n const hostId = String(body.hostId ?? '')\n const orderId = String(body.orderId ?? '')\n if (!hostId || !orderId) {\n return res.status(400).json({ error: 'Missing hostId or orderId' })\n }\n // Firestore reserves `__…__` ids and `.doc()` throws SYNCHRONOUSLY on one,\n // which would surface as a 500 on a caller's typo rather than the 400 it is.\n if (/^__.*__$/.test(hostId) || /^__.*__$/.test(orderId)) {\n return res.status(400).json({ error: 'Missing hostId or orderId' })\n }\n\n try {\n const decoded = await firebaseAdmin.app().auth().verifyIdToken(idToken)\n const firestore = firebaseAdmin.app().firestore()\n const hostRef = firestore.collection('hosts').doc(hostId)\n const hostSnapshot = await hostRef.get()\n if (!hostSnapshot.exists) {\n return res.status(404).json({ error: 'Unknown site' })\n }\n // The role the CLIENT write already had, not a stricter one. Order updates\n // fall through the rules' host catch-all, which admits `admin` and\n // `editor` — narrowing to admin here would take the cancel button away\n // from editors who have always had it, and widening it past what the rules\n // allow would make this endpoint the way around them.\n const memberRole = (hostSnapshot.get('memberRoles') ?? {})[decoded.uid]\n if (memberRole !== 'admin' && memberRole !== 'editor') {\n return res.status(403).json({ error: 'Not permitted' })\n }\n const orderRef = hostRef.collection('orders').doc(orderId)\n\n const outcome = await firestore.runTransaction(async (transaction) => {\n const snapshot = await transaction.get(orderRef)\n if (!snapshot.exists) {\n return { status: 404, body: { error: 'Unknown order' } }\n }\n const order = CommerceModel.liftLegacyOrder(\n (snapshot.data() ?? {}) as never,\n )\n // A redelivered click, or the second of two admins. Answered as success\n // because it IS the state the caller asked for — reporting 409 here\n // teaches an admin that the cancel failed and invites a third attempt —\n // but nothing is written, so the units are released exactly once.\n if (order.status === 'cancelled') {\n return {\n status: 200,\n body: { ok: true, alreadyCancelled: true, released: 0, units: 0 },\n }\n }\n if (!CommerceModel.canTransitionOrder(order.status, 'cancelled')) {\n return {\n status: 409,\n body: { error: `Orders in \"${order.status}\" cannot cancel` },\n }\n }\n\n // A POS CARD order's decrement happens in the webhook that pays it —\n // and before AGL-1825 it did not happen AT ALL: the paying branch's\n // decrement was gated on `productId` metadata the register's session\n // never carried. Releasing such an order restocks units that were never\n // taken, turning the silent under-count into a silent over-count. The\n // sale's own ledger is the discriminator: every decrement pairs with a\n // `reason: 'sale'` row (AGL-1807 closed the last hole, and the AGL-1825\n // decrement writes them from day one), so a paid card order with no\n // sale row is one whose sale took nothing — and nothing is released.\n //\n // Scoped to card orders (the `pos-card-pending` timeline event) rather\n // than applied to every order, because one historical path decremented\n // WITHOUT rows — draft links paid before AGL-1807 — and asking the\n // ledger to vouch for those would wrongly strand their stock. The\n // residual is stated plainly: the sibling-shaped decrement/ledger pair\n // is two swallowed sequential writes, so a card order whose ledger add\n // alone failed will not release — a bounded under-count on that one\n // order, visible as a sale missing from the hub's history, against the\n // alternative of inflating stock on every pre-fix cancel.\n //\n // One equality filter, so the automatic single-field index answers it;\n // the reason test runs here, over the handful of rows one order has.\n //\n // THE SAME READ NOW ALSO BOUNDS HOW MUCH COMES BACK (AGL-2149), so it is\n // no longer scoped to card orders. `adjustVariantInventory` floors at\n // zero, and that floor silently absorbs the overshoot on a BACKORDER\n // product: stock 0, `canPurchase` admits the sale because the policy says\n // to, three units sell, `Math.max(0, 0 + -3)` leaves the count at 0 —\n // and a `+3` here would hand the merchant three units nobody has and a\n // stock badge offering them. The sale rows carry `appliedDelta` for\n // exactly this: `delta` stays the units sold (the merchant's history),\n // `appliedDelta` says how many the count could actually give up.\n //\n // Only lines the ledger DESCRIBES are capped. A pair the ledger says\n // nothing about restores as before, which is what keeps the pre-AGL-1807\n // draft links — decremented with no row at all — from having their stock\n // stranded, and what keeps a single swallowed ledger write from turning\n // into a lost restock on an unrelated line of the same order.\n let saleDecremented = true\n // The cap rule itself lives beside the restock flag, which now bounds\n // the question it ASKS by the same ledger this bounds the stock it\n // RETURNS (AGL-2325). One implementation, so a prompt naming more units\n // than a cancellation would put back is not expressible.\n let releaseCap: ReadonlyMap<string, number> = new Map<string, number>()\n if (order.status === 'paid') {\n const orderAdjustments = await transaction.get(\n hostRef\n .collection('inventoryAdjustments')\n .where('orderId', '==', orderId),\n )\n const saleRows = orderAdjustments.docs.filter(\n (row) => row.get('reason') === 'sale',\n )\n if (\n order.channel === 'pos' &&\n (order.timeline ?? []).some(\n (event) => event.event === 'pos-card-pending',\n )\n ) {\n saleDecremented = saleRows.length > 0\n }\n releaseCap = saleReleaseCaps(saleRows)\n }\n\n // `paid` is the only status reachable here whose sale decremented; see\n // the header. Reads happen before any write, as a transaction requires.\n const { lines, products } =\n order.status === 'paid' && saleDecremented\n ? await resolveTrackedRestockLines(hostRef, order, (ref) =>\n transaction.get(ref),\n )\n : {\n lines: [],\n products: new Map<string, CommerceModel.HostProduct>(),\n }\n\n const atMs = Date.now()\n // Grouped by product, because two lines of one product (two variants, or\n // the same variant twice) are two deltas against ONE document: writing\n // them separately would compute both from the same read and land only\n // the last, silently dropping units.\n const byProduct = new Map<string, CommerceModel.OrderRestockLine[]>()\n // Never more than the sale actually took off the shelf (AGL-2149).\n for (const line of capRestockLines(lines, releaseCap)) {\n byProduct.set(line.productId, [\n ...(byProduct.get(line.productId) ?? []),\n line,\n ])\n }\n for (const [productId, productLines] of byProduct) {\n const product = products.get(productId)\n if (!product) continue\n let variants = product.variants\n for (const line of productLines) {\n variants = CommerceModel.adjustVariantInventory(\n { variants },\n line.variantId,\n line.quantity,\n // The bucket the sale came out of, for a location-tracked store\n // (AGL-286). Absent on every path that decremented the flat count,\n // where `adjustVariantInventory` puts it back the same way.\n order.locationId || undefined,\n )\n }\n // `update()`, not `set(…, { merge: true })` as the sale paths use: the\n // transaction has just read this product, so it exists, and a product\n // deleted under us must not be conjured back as a stub holding nothing\n // but a variants array.\n transaction.update(hostRef.collection('products').doc(productId), {\n variants,\n // The total and the storefront's In stock verdict (AGL-3321).\n ...CommerceModel.productStockFields({ ...product, variants }),\n updatedAtMs: atMs,\n })\n for (const line of productLines) {\n transaction.create(hostRef.collection('inventoryAdjustments').doc(), {\n productId,\n variantId: line.variantId,\n delta: line.quantity,\n reason: 'cancellation',\n orderId,\n ...(order.locationId ? { locationId: order.locationId } : {}),\n atMs,\n } satisfies CommerceModel.InventoryAdjustment)\n }\n }\n\n // From the CAPPED lines, not the order's, so the timeline reports what\n // was actually put back (AGL-2149).\n const releasedLines = [...byProduct.values()].flat()\n const units = releasedLines.reduce((sum, line) => sum + line.quantity, 0)\n const patch: Record<string, unknown> = {\n status: 'cancelled',\n timeline: CommerceModel.appendOrderEvent(\n order,\n 'cancelled',\n units > 0\n ? `${units} ${units === 1 ? 'unit' : 'units'} returned to stock`\n : undefined,\n atMs,\n ),\n }\n // An open restock question about THIS order's stock, raised by a partial\n // refund before the cancellation (AGL-1797). The units it asked about are\n // the ones just put back, so leaving it open would invite the merchant to\n // restock them a second time from the order dialog — the double-count\n // that flag exists to avoid. Answered with what actually happened.\n if (units > 0 && order.restockCheck && !order.restockCheck.resolution) {\n patch.restockCheck = {\n ...order.restockCheck,\n resolution: 'restocked',\n resolvedAtMs: atMs,\n resolvedBy: decoded.uid,\n } satisfies CommerceModel.OrderRestockCheck\n }\n transaction.update(orderRef, patch)\n return {\n status: 200,\n body: { ok: true, released: releasedLines.length, units },\n // The live Stripe page this cancellation orphans, if any (AGL-2244).\n // Read inside the transaction that flips the status so the expiry\n // below cannot act on an order some other writer paid meanwhile.\n expireSessionId:\n order.status === 'pending' ? (order.checkoutSessionId ?? '') : '',\n }\n })\n // EXPIRE THE PAYMENT LINK (AGL-2244). Cancelling a `pending` draft order or\n // POS card sale left its Checkout Session live: the URL is on the\n // customer's phone or in the email the merchant sent, and Stripe keeps it\n // payable for 24 hours. Paying it captured real money on the merchant's\n // account and the completing webhook then discarded the event — its\n // `status !== 'pending'` guard cannot tell a redelivery from a cancelled\n // order — so the sale existed in Stripe and nowhere in the product: no\n // order, no stock move, no contact, no notification, not even a timeline\n // line. The webhook now says so when it happens; this is the half that\n // stops it happening.\n //\n // OUTSIDE the transaction, because it is a network call, and best-effort\n // by design: the cancellation itself already landed and is what the\n // merchant asked for. A failure here leaves the pre-existing behaviour\n // (a payable link) plus the webhook's new record of it, which is strictly\n // better than failing a cancel that has already released stock. Stripe\n // answers 400 for a session that is already expired or already paid, and\n // both are states this has nothing to add to.\n const expireSessionId = (outcome as { expireSessionId?: string })\n .expireSessionId\n if (expireSessionId && process.env.STRIPE_SECRET_KEY) {\n const expiry = await fetch(\n `https://api.stripe.com/v1/checkout/sessions/${expireSessionId}/expire`,\n {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${process.env.STRIPE_SECRET_KEY}`,\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n },\n ).catch(() => null)\n if (!expiry?.ok) {\n console.error(\n 'Cancelled order: Stripe session not expired, the payment link may still be payable',\n { hostId, orderId, sessionId: expireSessionId },\n )\n }\n }\n return res.status(outcome.status).json(outcome.body)\n } catch (error) {\n // Nothing landed — the transaction is all-or-nothing — so the order is\n // still open and the merchant can try again. Deliberately NOT the swallow\n // `flagOrderRestock` uses: there the money had already moved and only a\n // postscript was at risk; here a swallowed failure is a cancelled order\n // whose stock never came back, which is the bug this closes.\n console.error('cancelOrder failed', error)\n return res.status(500).json({ error: 'Cancel failed' })\n }\n}\n"],"names":["CommerceModel","firebaseAdmin","capRestockLines","resolveTrackedRestockLines","saleReleaseCaps","cancelOrderHandler","req","res","body","method","status","json","error","authorization","String","headers","idToken","startsWith","slice","length","undefined","JSON","parse","hostId","orderId","test","hostSnapshot","decoded","app","auth","verifyIdToken","firestore","hostRef","collection","doc","get","exists","memberRole","uid","orderRef","outcome","runTransaction","transaction","snapshot","order","liftLegacyOrder","data","ok","alreadyCancelled","released","units","canTransitionOrder","saleDecremented","releaseCap","Map","orderAdjustments","where","saleRows","docs","filter","row","channel","timeline","some","event","lines","products","ref","atMs","Date","now","byProduct","line","set","productId","productLines","product","variants","adjustVariantInventory","variantId","quantity","locationId","update","productStockFields","updatedAtMs","create","delta","reason","releasedLines","values","flat","reduce","sum","patch","appendOrderEvent","restockCheck","resolution","resolvedAtMs","resolvedBy","expireSessionId","checkoutSessionId","process","env","STRIPE_SECRET_KEY","expiry","fetch","Authorization","catch","console","sessionId"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/cancel-order.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as CommerceModel from '../model'\nimport { firebaseAdmin } from '@aglyn/tenant-data-admin'\nimport { notifyOrderBuyer } from './order-notifications'\nimport { ORDER_CANCELLED_EVENT } from '../model/order-events'\nimport { raiseOrderEvent } from './order-events'\nimport { type PluginApiHandler } from '@aglyn/aglyn/server'\nimport {\n capRestockLines,\n resolveTrackedRestockLines,\n saleReleaseCaps,\n} from './restock-flag'\n\n/**\n * Cancelling an order RELEASES its stock (AGL-1808) — the opposite of what the\n * reversal doors do, and for a structural reason rather than a preference.\n *\n * AGL-1797 refused to increment on a refund or a chargeback because the goods\n * may well be gone: a refund with no return, or a shopper who kept the item and\n * took the money, leaves stock that incrementing would INVENT. It flags and\n * lets the merchant answer. Cancellation carries no such question, and the\n * guarantee is `ORDER_TRANSITIONS`:\n *\n * pending: ['paid', 'cancelled'],\n * paid: ['partially_fulfilled', 'fulfilled', 'cancelled', 'refunded'],\n * partially_fulfilled | fulfilled | delivered: no 'cancelled'\n *\n * so a cancelled order was never fulfilled and nothing ever shipped. The units\n * are still on the shelf; the only wrong number is ours.\n *\n * THE GUARANTEE HAD TO BE ENFORCED BEFORE IT COULD BE RELIED ON, and that is\n * why this is a handler rather than a few lines in the console. The transition\n * table said the right thing but nothing consulted it on the way IN: the order\n * dialog cancelled with a client `updateDoc`, and `canTransitionOrder` only\n * decided whether to render the button. The Firestore rules impose no status\n * machine — an order update is allowed to any admin or editor — so a dialog\n * held open while the order shipped in another tab (or any other client) could\n * write `cancelled` straight onto a `fulfilled` order, and an automatic\n * increment behind that would restock goods already in the post. Re-asking the\n * transition INSIDE the transaction that writes the status is what turns the\n * comment into a guarantee, and it is what makes the release safe.\n *\n * `pending` RELEASES NOTHING, which is the other half the issue's premise\n * missed. Stock is decremented when the money lands, not when the order is\n * written: `draft-order.ts` and the POS card path both open a `pending` order\n * and decrement only in the webhook that pays it. Incrementing on a cancelled\n * `pending` order would invent inventory exactly the way AGL-1797 refused to —\n * so only a `paid` order, the one status reachable here whose sale provably\n * decremented, releases anything.\n *\n * ONE LEDGER, NOT A SECOND STOCK WRITER. The increment goes through\n * `adjustVariantInventory` and logs an `InventoryAdjustment` per line, the same\n * pair the sale paths and the products hub's \"Adjust stock\" write, with the new\n * `cancellation` reason and the `orderId`. An increment with no ledger row\n * would leave the hub's stock history unable to explain a count that moved on\n * its own — the mirror of AGL-1797's argument against writing a row for stock\n * that had NOT moved.\n *\n * ONLY WHAT THE SALE DECREMENTED comes back: `resolveTrackedRestockLines`, the\n * helper AGL-1797 already built, applies the sale path's own\n * `variant.inventory != null` test to the products as they stand now. A store\n * that tracks no stock gets a plain cancellation and no adjustment rows.\n *\n * IT FAILS THE CANCEL RATHER THAN LOSING THE RELEASE. `flagOrderRestock`\n * swallows its errors because the money had already moved and the flag was a\n * postscript; here the status flip and the stock write are one act, so they\n * share a transaction and a failure leaves the order uncancelled for the\n * merchant to retry. A cancelled order whose stock never came back is the\n * original bug.\n *\n * ONCE. The transaction's own read is the guard: a second cancel — a retried\n * request, two admins clicking together — finds `cancelled`, which\n * `canTransitionOrder` cannot leave, and returns without touching stock. Two\n * increments of the same units is the failure mode this shape exists to\n * prevent, and it is measured rather than asserted (`cancel-order.spec.ts`).\n *\n * REACHED FROM THE CONSOLE since AGL-1818: `order-detail-dialog`'s\n * `handleCancel` POSTs here with the console id token, and the client\n * `updateDoc` cancel it replaced is gone. (The wiring landed separately from\n * the route because the dialog belonged to a concurrent agent, AGL-1806,\n * when the route was written.)\n */\nexport const cancelOrderHandler: PluginApiHandler = async (req, res) => {\n if (req.method !== 'POST') {\n return res.status(405).json({ error: 'Method not allowed' })\n }\n const authorization = String(req.headers.authorization ?? '')\n const idToken = authorization.startsWith('Bearer ')\n ? authorization.slice('Bearer '.length)\n : undefined\n if (!idToken) return res.status(401).json({ error: 'Unauthenticated' })\n const body =\n typeof req.body === 'string' ? JSON.parse(req.body) : (req.body ?? {})\n const hostId = String(body.hostId ?? '')\n const orderId = String(body.orderId ?? '')\n if (!hostId || !orderId) {\n return res.status(400).json({ error: 'Missing hostId or orderId' })\n }\n // Firestore reserves `__…__` ids and `.doc()` throws SYNCHRONOUSLY on one,\n // which would surface as a 500 on a caller's typo rather than the 400 it is.\n if (/^__.*__$/.test(hostId) || /^__.*__$/.test(orderId)) {\n return res.status(400).json({ error: 'Missing hostId or orderId' })\n }\n\n try {\n const decoded = await firebaseAdmin.app().auth().verifyIdToken(idToken)\n const firestore = firebaseAdmin.app().firestore()\n const hostRef = firestore.collection('hosts').doc(hostId)\n const hostSnapshot = await hostRef.get()\n if (!hostSnapshot.exists) {\n return res.status(404).json({ error: 'Unknown site' })\n }\n // The role the CLIENT write already had, not a stricter one. Order updates\n // fall through the rules' host catch-all, which admits `admin` and\n // `editor` — narrowing to admin here would take the cancel button away\n // from editors who have always had it, and widening it past what the rules\n // allow would make this endpoint the way around them.\n const memberRole = (hostSnapshot.get('memberRoles') ?? {})[decoded.uid]\n if (memberRole !== 'admin' && memberRole !== 'editor') {\n return res.status(403).json({ error: 'Not permitted' })\n }\n const orderRef = hostRef.collection('orders').doc(orderId)\n\n const outcome = await firestore.runTransaction(async (transaction) => {\n const snapshot = await transaction.get(orderRef)\n if (!snapshot.exists) {\n return { status: 404, body: { error: 'Unknown order' } }\n }\n const order = CommerceModel.liftLegacyOrder(\n (snapshot.data() ?? {}) as never,\n )\n // A redelivered click, or the second of two admins. Answered as success\n // because it IS the state the caller asked for — reporting 409 here\n // teaches an admin that the cancel failed and invites a third attempt —\n // but nothing is written, so the units are released exactly once.\n if (order.status === 'cancelled') {\n return {\n status: 200,\n body: { ok: true, alreadyCancelled: true, released: 0, units: 0 },\n }\n }\n if (!CommerceModel.canTransitionOrder(order.status, 'cancelled')) {\n return {\n status: 409,\n body: { error: `Orders in \"${order.status}\" cannot cancel` },\n }\n }\n // An OPEN register sale that has taken money (AGL-3607) is voided at\n // the register, which hands each payment back first. Cancelling it here\n // would mark it cancelled with a card charge, a gift card debit or a\n // room charge still standing.\n if (\n order.status === 'pending' &&\n CommerceModel.orderPayments(order).some(\n (payment) => payment.status === 'succeeded' || payment.status === 'pending',\n ) &&\n Array.isArray(order.payments)\n ) {\n return {\n status: 409,\n body: {\n error:\n 'This register sale has payments on it. Void it at the register, ' +\n 'which hands each payment back first.',\n },\n }\n }\n\n // A POS CARD order's decrement happens in the webhook that pays it —\n // and before AGL-1825 it did not happen AT ALL: the paying branch's\n // decrement was gated on `productId` metadata the register's session\n // never carried. Releasing such an order restocks units that were never\n // taken, turning the silent under-count into a silent over-count. The\n // sale's own ledger is the discriminator: every decrement pairs with a\n // `reason: 'sale'` row (AGL-1807 closed the last hole, and the AGL-1825\n // decrement writes them from day one), so a paid card order with no\n // sale row is one whose sale took nothing — and nothing is released.\n //\n // Scoped to card orders (the `pos-card-pending` timeline event) rather\n // than applied to every order, because one historical path decremented\n // WITHOUT rows — draft links paid before AGL-1807 — and asking the\n // ledger to vouch for those would wrongly strand their stock. The\n // residual is stated plainly: the sibling-shaped decrement/ledger pair\n // is two swallowed sequential writes, so a card order whose ledger add\n // alone failed will not release — a bounded under-count on that one\n // order, visible as a sale missing from the hub's history, against the\n // alternative of inflating stock on every pre-fix cancel.\n //\n // One equality filter, so the automatic single-field index answers it;\n // the reason test runs here, over the handful of rows one order has.\n //\n // THE SAME READ NOW ALSO BOUNDS HOW MUCH COMES BACK (AGL-2149), so it is\n // no longer scoped to card orders. `adjustVariantInventory` floors at\n // zero, and that floor silently absorbs the overshoot on a BACKORDER\n // product: stock 0, `canPurchase` admits the sale because the policy says\n // to, three units sell, `Math.max(0, 0 + -3)` leaves the count at 0 —\n // and a `+3` here would hand the merchant three units nobody has and a\n // stock badge offering them. The sale rows carry `appliedDelta` for\n // exactly this: `delta` stays the units sold (the merchant's history),\n // `appliedDelta` says how many the count could actually give up.\n //\n // Only lines the ledger DESCRIBES are capped. A pair the ledger says\n // nothing about restores as before, which is what keeps the pre-AGL-1807\n // draft links — decremented with no row at all — from having their stock\n // stranded, and what keeps a single swallowed ledger write from turning\n // into a lost restock on an unrelated line of the same order.\n let saleDecremented = true\n // The cap rule itself lives beside the restock flag, which now bounds\n // the question it ASKS by the same ledger this bounds the stock it\n // RETURNS (AGL-2325). One implementation, so a prompt naming more units\n // than a cancellation would put back is not expressible.\n let releaseCap: ReadonlyMap<string, number> = new Map<string, number>()\n if (order.status === 'paid') {\n const orderAdjustments = await transaction.get(\n hostRef\n .collection('inventoryAdjustments')\n .where('orderId', '==', orderId),\n )\n const saleRows = orderAdjustments.docs.filter(\n (row) => row.get('reason') === 'sale',\n )\n if (\n order.channel === 'pos' &&\n (order.timeline ?? []).some(\n (event) => event.event === 'pos-card-pending',\n )\n ) {\n saleDecremented = saleRows.length > 0\n }\n releaseCap = saleReleaseCaps(saleRows)\n }\n\n // `paid` is the only status reachable here whose sale decremented; see\n // the header. Reads happen before any write, as a transaction requires.\n const { lines, products } =\n order.status === 'paid' && saleDecremented\n ? await resolveTrackedRestockLines(hostRef, order, (ref) =>\n transaction.get(ref),\n )\n : {\n lines: [],\n products: new Map<string, CommerceModel.HostProduct>(),\n }\n\n const atMs = Date.now()\n // Grouped by product, because two lines of one product (two variants, or\n // the same variant twice) are two deltas against ONE document: writing\n // them separately would compute both from the same read and land only\n // the last, silently dropping units.\n const byProduct = new Map<string, CommerceModel.OrderRestockLine[]>()\n // Never more than the sale actually took off the shelf (AGL-2149).\n for (const line of capRestockLines(lines, releaseCap)) {\n byProduct.set(line.productId, [\n ...(byProduct.get(line.productId) ?? []),\n line,\n ])\n }\n for (const [productId, productLines] of byProduct) {\n const product = products.get(productId)\n if (!product) continue\n let variants = product.variants\n for (const line of productLines) {\n variants = CommerceModel.adjustVariantInventory(\n { variants },\n line.variantId,\n line.quantity,\n // The bucket the sale came out of, for a location-tracked store\n // (AGL-286). Absent on every path that decremented the flat count,\n // where `adjustVariantInventory` puts it back the same way.\n order.locationId || undefined,\n )\n }\n // `update()`, not `set(…, { merge: true })` as the sale paths use: the\n // transaction has just read this product, so it exists, and a product\n // deleted under us must not be conjured back as a stub holding nothing\n // but a variants array.\n transaction.update(hostRef.collection('products').doc(productId), {\n variants,\n // The total and the storefront's In stock verdict (AGL-3321).\n ...CommerceModel.productStockFields({ ...product, variants }),\n updatedAtMs: atMs,\n })\n for (const line of productLines) {\n transaction.create(hostRef.collection('inventoryAdjustments').doc(), {\n productId,\n variantId: line.variantId,\n delta: line.quantity,\n reason: 'cancellation',\n orderId,\n ...(order.locationId ? { locationId: order.locationId } : {}),\n atMs,\n } satisfies CommerceModel.InventoryAdjustment)\n }\n }\n\n // From the CAPPED lines, not the order's, so the timeline reports what\n // was actually put back (AGL-2149).\n const releasedLines = [...byProduct.values()].flat()\n const units = releasedLines.reduce((sum, line) => sum + line.quantity, 0)\n const patch: Record<string, unknown> = {\n status: 'cancelled',\n // What a shipping tool's feed asks to learn of the cancel (AGL-3613).\n updatedAtMs: atMs,\n timeline: CommerceModel.appendOrderEvent(\n order,\n 'cancelled',\n units > 0\n ? `${units} ${units === 1 ? 'unit' : 'units'} returned to stock`\n : undefined,\n atMs,\n ),\n }\n // An open restock question about THIS order's stock, raised by a partial\n // refund before the cancellation (AGL-1797). The units it asked about are\n // the ones just put back, so leaving it open would invite the merchant to\n // restock them a second time from the order dialog — the double-count\n // that flag exists to avoid. Answered with what actually happened.\n if (units > 0 && order.restockCheck && !order.restockCheck.resolution) {\n patch.restockCheck = {\n ...order.restockCheck,\n resolution: 'restocked',\n resolvedAtMs: atMs,\n resolvedBy: decoded.uid,\n } satisfies CommerceModel.OrderRestockCheck\n }\n transaction.update(orderRef, patch)\n return {\n status: 200,\n body: { ok: true, released: releasedLines.length, units },\n // The live Stripe page this cancellation orphans, if any (AGL-2244).\n // Read inside the transaction that flips the status so the expiry\n // below cannot act on an order some other writer paid meanwhile.\n expireSessionId:\n order.status === 'pending' ? (order.checkoutSessionId ?? '') : '',\n }\n })\n // EXPIRE THE PAYMENT LINK (AGL-2244). Cancelling a `pending` draft order or\n // POS card sale left its Checkout Session live: the URL is on the\n // customer's phone or in the email the merchant sent, and Stripe keeps it\n // payable for 24 hours. Paying it captured real money on the merchant's\n // account and the completing webhook then discarded the event — its\n // `status !== 'pending'` guard cannot tell a redelivery from a cancelled\n // order — so the sale existed in Stripe and nowhere in the product: no\n // order, no stock move, no contact, no notification, not even a timeline\n // line. The webhook now says so when it happens; this is the half that\n // stops it happening.\n //\n // OUTSIDE the transaction, because it is a network call, and best-effort\n // by design: the cancellation itself already landed and is what the\n // merchant asked for. A failure here leaves the pre-existing behaviour\n // (a payable link) plus the webhook's new record of it, which is strictly\n // better than failing a cancel that has already released stock. Stripe\n // answers 400 for a session that is already expired or already paid, and\n // both are states this has nothing to add to.\n const expireSessionId = (outcome as { expireSessionId?: string })\n .expireSessionId\n if (expireSessionId && process.env.STRIPE_SECRET_KEY) {\n const expiry = await fetch(\n `https://api.stripe.com/v1/checkout/sessions/${expireSessionId}/expire`,\n {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${process.env.STRIPE_SECRET_KEY}`,\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n },\n ).catch(() => null)\n if (!expiry?.ok) {\n console.error(\n 'Cancelled order: Stripe session not expired, the payment link may still be payable',\n { hostId, orderId, sessionId: expireSessionId },\n )\n }\n }\n // The buyer is told (AGL-3610) — only by the request that cancelled it.\n if (outcome.status === 200 && !(outcome.body as { alreadyCancelled?: boolean }).alreadyCancelled) {\n await notifyOrderBuyer({ hostId, orderId }, 'cancelled')\n await raiseOrderEvent(ORDER_CANCELLED_EVENT, { hostId, orderId, key: 'cancelled' })\n }\n return res.status(outcome.status).json(outcome.body)\n } catch (error) {\n // Nothing landed — the transaction is all-or-nothing — so the order is\n // still open and the merchant can try again. Deliberately NOT the swallow\n // `flagOrderRestock` uses: there the money had already moved and only a\n // postscript was at risk; here a swallowed failure is a cancelled order\n // whose stock never came back, which is the bug this closes.\n console.error('cancelOrder failed', error)\n return res.status(500).json({ error: 'Cancel failed' })\n }\n}\n"],"names":["CommerceModel","firebaseAdmin","notifyOrderBuyer","ORDER_CANCELLED_EVENT","raiseOrderEvent","capRestockLines","resolveTrackedRestockLines","saleReleaseCaps","cancelOrderHandler","req","res","body","method","status","json","error","authorization","String","headers","idToken","startsWith","slice","length","undefined","JSON","parse","hostId","orderId","test","hostSnapshot","decoded","app","auth","verifyIdToken","firestore","hostRef","collection","doc","get","exists","memberRole","uid","orderRef","outcome","runTransaction","transaction","snapshot","order","liftLegacyOrder","data","ok","alreadyCancelled","released","units","canTransitionOrder","orderPayments","some","payment","Array","isArray","payments","saleDecremented","releaseCap","Map","orderAdjustments","where","saleRows","docs","filter","row","channel","timeline","event","lines","products","ref","atMs","Date","now","byProduct","line","set","productId","productLines","product","variants","adjustVariantInventory","variantId","quantity","locationId","update","productStockFields","updatedAtMs","create","delta","reason","releasedLines","values","flat","reduce","sum","patch","appendOrderEvent","restockCheck","resolution","resolvedAtMs","resolvedBy","expireSessionId","checkoutSessionId","process","env","STRIPE_SECRET_KEY","expiry","fetch","Authorization","catch","console","sessionId","key"],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import type { PluginApiHandler } from '@aglyn/aglyn/server';
|
|
18
|
+
/**
|
|
19
|
+
* `GET commerce/shipping/carrier-rates?hostId` (AGL-3612): whether this site
|
|
20
|
+
* can price shipping by carrier, and the services it may offer — what the
|
|
21
|
+
* Shipping card asks before it shows the Carrier rates kind. Answered from
|
|
22
|
+
* core's quoter seam, so it is `available: false` wherever no plugin quotes
|
|
23
|
+
* carriers or the deployment names no carrier provider, and the kind is not
|
|
24
|
+
* offered. A site collaborator may ask; nothing here is a secret.
|
|
25
|
+
*/
|
|
26
|
+
export declare const carrierRatesAvailabilityHandler: PluginApiHandler;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ import { pluginShippingRateQuoter } from "@aglyn/aglyn/plugin-manager/plugin-shipping-rates";
|
|
17
|
+
import { firebaseAdmin } from "@aglyn/tenant-data-admin";
|
|
18
|
+
import { isRefusedIdToken } from "@aglyn/tenant-data-admin/server/id-token-refusal";
|
|
19
|
+
/**
|
|
20
|
+
* `GET commerce/shipping/carrier-rates?hostId` (AGL-3612): whether this site
|
|
21
|
+
* can price shipping by carrier, and the services it may offer — what the
|
|
22
|
+
* Shipping card asks before it shows the Carrier rates kind. Answered from
|
|
23
|
+
* core's quoter seam, so it is `available: false` wherever no plugin quotes
|
|
24
|
+
* carriers or the deployment names no carrier provider, and the kind is not
|
|
25
|
+
* offered. A site collaborator may ask; nothing here is a secret.
|
|
26
|
+
*/ export const carrierRatesAvailabilityHandler = async (req, res)=>{
|
|
27
|
+
var _req_headers_authorization, _ref;
|
|
28
|
+
var _req_query;
|
|
29
|
+
if (req.method !== 'GET') return res.status(405).json({
|
|
30
|
+
error: 'Method not allowed'
|
|
31
|
+
});
|
|
32
|
+
const authorization = String((_req_headers_authorization = req.headers.authorization) != null ? _req_headers_authorization : '');
|
|
33
|
+
if (!authorization.startsWith('Bearer ')) return res.status(401).json({
|
|
34
|
+
error: 'Unauthenticated'
|
|
35
|
+
});
|
|
36
|
+
const hostId = String((_ref = (_req_query = req.query) == null ? void 0 : _req_query['hostId']) != null ? _ref : '');
|
|
37
|
+
if (!hostId || hostId.includes('/') || /^__.*__$/.test(hostId)) {
|
|
38
|
+
return res.status(400).json({
|
|
39
|
+
error: 'Missing hostId'
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
let decoded;
|
|
43
|
+
try {
|
|
44
|
+
decoded = await firebaseAdmin.app().auth().verifyIdToken(authorization.slice('Bearer '.length));
|
|
45
|
+
} catch (error) {
|
|
46
|
+
if (!isRefusedIdToken(error)) throw error;
|
|
47
|
+
return res.status(401).json({
|
|
48
|
+
error: 'Unauthenticated'
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
var _host_get;
|
|
53
|
+
const host = await firebaseAdmin.app().firestore().collection('hosts').doc(hostId).get();
|
|
54
|
+
if (!host.exists) return res.status(404).json({
|
|
55
|
+
error: 'Unknown site'
|
|
56
|
+
});
|
|
57
|
+
const role = ((_host_get = host.get('memberRoles')) != null ? _host_get : {})[decoded.uid];
|
|
58
|
+
if (!role && decoded['staff'] !== true) return res.status(403).json({
|
|
59
|
+
error: 'Not permitted'
|
|
60
|
+
});
|
|
61
|
+
const quoter = pluginShippingRateQuoter();
|
|
62
|
+
const available = quoter ? await quoter.available(hostId).catch(()=>false) : false;
|
|
63
|
+
const services = available && quoter ? await quoter.listServices(hostId).catch(()=>[]) : [];
|
|
64
|
+
return res.status(200).json({
|
|
65
|
+
available,
|
|
66
|
+
services
|
|
67
|
+
});
|
|
68
|
+
} catch (unused) {
|
|
69
|
+
return res.status(200).json({
|
|
70
|
+
available: false,
|
|
71
|
+
services: []
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
//# sourceMappingURL=carrier-rates-availability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/carrier-rates-availability.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { pluginShippingRateQuoter } from '@aglyn/aglyn/plugin-manager/plugin-shipping-rates'\nimport type { PluginApiHandler } from '@aglyn/aglyn/server'\nimport { firebaseAdmin } from '@aglyn/tenant-data-admin'\nimport { isRefusedIdToken } from '@aglyn/tenant-data-admin/server/id-token-refusal'\n\n/**\n * `GET commerce/shipping/carrier-rates?hostId` (AGL-3612): whether this site\n * can price shipping by carrier, and the services it may offer — what the\n * Shipping card asks before it shows the Carrier rates kind. Answered from\n * core's quoter seam, so it is `available: false` wherever no plugin quotes\n * carriers or the deployment names no carrier provider, and the kind is not\n * offered. A site collaborator may ask; nothing here is a secret.\n */\nexport const carrierRatesAvailabilityHandler: PluginApiHandler = async (req, res) => {\n if (req.method !== 'GET') return res.status(405).json({ error: 'Method not allowed' })\n const authorization = String(req.headers.authorization ?? '')\n if (!authorization.startsWith('Bearer ')) return res.status(401).json({ error: 'Unauthenticated' })\n const hostId = String((req.query as Record<string, unknown> | undefined)?.['hostId'] ?? '')\n if (!hostId || hostId.includes('/') || /^__.*__$/.test(hostId)) {\n return res.status(400).json({ error: 'Missing hostId' })\n }\n let decoded\n try {\n decoded = await firebaseAdmin.app().auth().verifyIdToken(authorization.slice('Bearer '.length))\n } catch (error) {\n if (!isRefusedIdToken(error)) throw error\n return res.status(401).json({ error: 'Unauthenticated' })\n }\n try {\n const host = await firebaseAdmin.app().firestore().collection('hosts').doc(hostId).get()\n if (!host.exists) return res.status(404).json({ error: 'Unknown site' })\n const role = (host.get('memberRoles') ?? {})[decoded.uid]\n if (!role && decoded['staff'] !== true) return res.status(403).json({ error: 'Not permitted' })\n const quoter = pluginShippingRateQuoter()\n const available = quoter ? await quoter.available(hostId).catch(() => false) : false\n const services = available && quoter ? await quoter.listServices(hostId).catch(() => []) : []\n return res.status(200).json({ available, services })\n } catch {\n return res.status(200).json({ available: false, services: [] })\n }\n}\n"],"names":["pluginShippingRateQuoter","firebaseAdmin","isRefusedIdToken","carrierRatesAvailabilityHandler","req","res","method","status","json","error","authorization","String","headers","startsWith","hostId","query","includes","test","decoded","app","auth","verifyIdToken","slice","length","host","firestore","collection","doc","get","exists","role","uid","quoter","available","catch","services","listServices"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,wBAAwB,QAAQ,oDAAmD;AAE5F,SAASC,aAAa,QAAQ,2BAA0B;AACxD,SAASC,gBAAgB,QAAQ,mDAAkD;AAEnF;;;;;;;CAOC,GACD,OAAO,MAAMC,kCAAoD,OAAOC,KAAKC;QAE9CD;QAENA;IAHvB,IAAIA,IAAIE,MAAM,KAAK,OAAO,OAAOD,IAAIE,MAAM,CAAC,KAAKC,IAAI,CAAC;QAAEC,OAAO;IAAqB;IACpF,MAAMC,gBAAgBC,QAAOP,6BAAAA,IAAIQ,OAAO,CAACF,aAAa,YAAzBN,6BAA6B;IAC1D,IAAI,CAACM,cAAcG,UAAU,CAAC,YAAY,OAAOR,IAAIE,MAAM,CAAC,KAAKC,IAAI,CAAC;QAAEC,OAAO;IAAkB;IACjG,MAAMK,SAASH,gBAAQP,aAAAA,IAAIW,KAAK,qBAAV,AAACX,UAAmD,CAAC,SAAS,mBAAI;IACxF,IAAI,CAACU,UAAUA,OAAOE,QAAQ,CAAC,QAAQ,WAAWC,IAAI,CAACH,SAAS;QAC9D,OAAOT,IAAIE,MAAM,CAAC,KAAKC,IAAI,CAAC;YAAEC,OAAO;QAAiB;IACxD;IACA,IAAIS;IACJ,IAAI;QACFA,UAAU,MAAMjB,cAAckB,GAAG,GAAGC,IAAI,GAAGC,aAAa,CAACX,cAAcY,KAAK,CAAC,UAAUC,MAAM;IAC/F,EAAE,OAAOd,OAAO;QACd,IAAI,CAACP,iBAAiBO,QAAQ,MAAMA;QACpC,OAAOJ,IAAIE,MAAM,CAAC,KAAKC,IAAI,CAAC;YAAEC,OAAO;QAAkB;IACzD;IACA,IAAI;YAGYe;QAFd,MAAMA,OAAO,MAAMvB,cAAckB,GAAG,GAAGM,SAAS,GAAGC,UAAU,CAAC,SAASC,GAAG,CAACb,QAAQc,GAAG;QACtF,IAAI,CAACJ,KAAKK,MAAM,EAAE,OAAOxB,IAAIE,MAAM,CAAC,KAAKC,IAAI,CAAC;YAAEC,OAAO;QAAe;QACtE,MAAMqB,OAAO,EAACN,YAAAA,KAAKI,GAAG,CAAC,0BAATJ,YAA2B,CAAC,EAAE,CAACN,QAAQa,GAAG,CAAC;QACzD,IAAI,CAACD,QAAQZ,OAAO,CAAC,QAAQ,KAAK,MAAM,OAAOb,IAAIE,MAAM,CAAC,KAAKC,IAAI,CAAC;YAAEC,OAAO;QAAgB;QAC7F,MAAMuB,SAAShC;QACf,MAAMiC,YAAYD,SAAS,MAAMA,OAAOC,SAAS,CAACnB,QAAQoB,KAAK,CAAC,IAAM,SAAS;QAC/E,MAAMC,WAAWF,aAAaD,SAAS,MAAMA,OAAOI,YAAY,CAACtB,QAAQoB,KAAK,CAAC,IAAM,EAAE,IAAI,EAAE;QAC7F,OAAO7B,IAAIE,MAAM,CAAC,KAAKC,IAAI,CAAC;YAAEyB;YAAWE;QAAS;IACpD,EAAE,eAAM;QACN,OAAO9B,IAAIE,MAAM,CAAC,KAAKC,IAAI,CAAC;YAAEyB,WAAW;YAAOE,UAAU,EAAE;QAAC;IAC/D;AACF,EAAC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import { type PluginShippingParcel } from '@aglyn/aglyn/plugin-manager/plugin-shipping-rates';
|
|
18
|
+
import * as CommerceModel from '../model';
|
|
19
|
+
/**
|
|
20
|
+
* LIVE CARRIER RATES AT CHECKOUT (AGL-3612): the `carrier` rate kind, priced
|
|
21
|
+
* by asking core's `core.shipping-rate-quoter` — whichever plugin quotes
|
|
22
|
+
* carriers — and never by importing it.
|
|
23
|
+
*
|
|
24
|
+
* ## Quoted before the session exists, on every door
|
|
25
|
+
*
|
|
26
|
+
* Stripe's hosted Checkout cannot change a session's shipping options once
|
|
27
|
+
* the shopper types an address ("The hosted page integration doesn't support
|
|
28
|
+
* dynamically customizing shipping options"), and the in-page form can only
|
|
29
|
+
* by a server update after the fact — while this module's callers fix the
|
|
30
|
+
* platform fee and the Connect transfer from the session's options at
|
|
31
|
+
* creation. So the quote is taken BEFORE the session, against the
|
|
32
|
+
* destination the shopper declares (country and postal code), and the
|
|
33
|
+
* session is then restricted to that country exactly as a zone rate is
|
|
34
|
+
* (AGL-1721). The same code serves cart checkout, buy-now and a draft
|
|
35
|
+
* order's link, hosted and in-page, and the fee arithmetic downstream sees
|
|
36
|
+
* ordinary options.
|
|
37
|
+
*
|
|
38
|
+
* ## The fallback is the merchant's own
|
|
39
|
+
*
|
|
40
|
+
* No quoter, a quoter not available for this site, or a quote that fails or
|
|
41
|
+
* takes longer than {@link CommerceModel.CARRIER_QUOTE_TIMEOUT_MS}: the plan
|
|
42
|
+
* is exactly the one {@link CommerceModel.planCheckoutShipping} makes from
|
|
43
|
+
* the table, where a carrier rate offers nothing and its fallback rate is
|
|
44
|
+
* offered. A store with no carrier rate never reaches the quoter at all, so
|
|
45
|
+
* its sessions are byte-identical to the ones before this existed.
|
|
46
|
+
*/
|
|
47
|
+
export interface CarrierShippingCart {
|
|
48
|
+
subtotalCents: number;
|
|
49
|
+
totalGrams: number;
|
|
50
|
+
/** One parcel's dimensions, when the cart is one product that has them. */
|
|
51
|
+
parcel?: Omit<PluginShippingParcel, 'weightGrams'>;
|
|
52
|
+
}
|
|
53
|
+
export interface CarrierShippingDestination {
|
|
54
|
+
country?: unknown;
|
|
55
|
+
postalCode?: unknown;
|
|
56
|
+
state?: unknown;
|
|
57
|
+
city?: unknown;
|
|
58
|
+
}
|
|
59
|
+
/** A postal code a shopper declared, trimmed and bounded, or `undefined`. */
|
|
60
|
+
export declare function normalizeCheckoutPostalCode(value: unknown): string | undefined;
|
|
61
|
+
export type CarrierShippingPlan = CommerceModel.CheckoutShippingPlan & {
|
|
62
|
+
/** Set when the plan offers live quotes: the postal code they were priced for. */
|
|
63
|
+
quotedPostalCode?: string;
|
|
64
|
+
/**
|
|
65
|
+
* The destination's zone prices by carrier and the store can quote, but the
|
|
66
|
+
* shopper has not said where in the country: ask for a postal code.
|
|
67
|
+
*/
|
|
68
|
+
needsPostalCode?: boolean;
|
|
69
|
+
};
|
|
70
|
+
/** What a shopper is told when a postal code is needed. */
|
|
71
|
+
export declare const CARRIER_POSTAL_CODE_MESSAGE = "Enter the postal code you\u2019re shipping to.";
|
|
72
|
+
/**
|
|
73
|
+
* The shipping half of a session for a store that may price by carrier.
|
|
74
|
+
* See the module comment; `planCheckoutShipping` is the whole answer for any
|
|
75
|
+
* store without a carrier rate.
|
|
76
|
+
*/
|
|
77
|
+
export declare function planCheckoutShippingWithCarriers(input: {
|
|
78
|
+
hostId: string;
|
|
79
|
+
settings: CommerceModel.ShippingSettings | undefined;
|
|
80
|
+
cart: CarrierShippingCart;
|
|
81
|
+
destination: CarrierShippingDestination;
|
|
82
|
+
currency?: string;
|
|
83
|
+
timeoutMs?: number;
|
|
84
|
+
}): Promise<CarrierShippingPlan>;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright 2026 Aglyn LLC
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/ import { pluginShippingRateQuoter, quotePluginShippingRates } from "@aglyn/aglyn/plugin-manager/plugin-shipping-rates";
|
|
18
|
+
import * as CommerceModel from "../model/index.js";
|
|
19
|
+
/** A postal code a shopper declared, trimmed and bounded, or `undefined`. */ export function normalizeCheckoutPostalCode(value) {
|
|
20
|
+
if (typeof value !== 'string') return undefined;
|
|
21
|
+
const code = value.trim().toUpperCase().slice(0, 12);
|
|
22
|
+
return /^[A-Z0-9][A-Z0-9 -]{1,11}$/.test(code) ? code : undefined;
|
|
23
|
+
}
|
|
24
|
+
/** What a shopper is told when a postal code is needed. */ export const CARRIER_POSTAL_CODE_MESSAGE = 'Enter the postal code you’re shipping to.';
|
|
25
|
+
/**
|
|
26
|
+
* The shipping half of a session for a store that may price by carrier.
|
|
27
|
+
* See the module comment; `planCheckoutShipping` is the whole answer for any
|
|
28
|
+
* store without a carrier rate.
|
|
29
|
+
*/ export async function planCheckoutShippingWithCarriers(input) {
|
|
30
|
+
var _input_currency, _cart_parcel, _input_timeoutMs;
|
|
31
|
+
const { settings, cart } = input;
|
|
32
|
+
const tablePlan = ()=>CommerceModel.planCheckoutShipping(settings, {
|
|
33
|
+
subtotalCents: cart.subtotalCents,
|
|
34
|
+
totalGrams: cart.totalGrams
|
|
35
|
+
}, input.destination.country);
|
|
36
|
+
if (!CommerceModel.hasCarrierRates(settings)) return tablePlan();
|
|
37
|
+
const quoter = pluginShippingRateQuoter();
|
|
38
|
+
if (!quoter) return tablePlan();
|
|
39
|
+
const available = await quoter.available(input.hostId).catch(()=>false);
|
|
40
|
+
if (!available) return tablePlan();
|
|
41
|
+
const country = CommerceModel.normalizeCheckoutShippingCountry(input.destination.country);
|
|
42
|
+
if (!country) {
|
|
43
|
+
// Carrier prices differ by address by construction, so a session that
|
|
44
|
+
// does not know the destination cannot be honest about any of them.
|
|
45
|
+
return {
|
|
46
|
+
countries: CommerceModel.CHECKOUT_SHIPPING_COUNTRIES,
|
|
47
|
+
options: [],
|
|
48
|
+
refusal: 'destination-required'
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
const carrierRates = CommerceModel.carrierRatesFor(settings, country);
|
|
52
|
+
if (!carrierRates.length) return tablePlan();
|
|
53
|
+
const postalCode = normalizeCheckoutPostalCode(input.destination.postalCode);
|
|
54
|
+
if (!postalCode) {
|
|
55
|
+
return {
|
|
56
|
+
countries: [
|
|
57
|
+
country
|
|
58
|
+
],
|
|
59
|
+
options: [],
|
|
60
|
+
refusal: 'destination-required',
|
|
61
|
+
needsPostalCode: true
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
const currency = String((_input_currency = input.currency) != null ? _input_currency : 'usd').toLowerCase();
|
|
65
|
+
const quotes = await quotePluginShippingRates({
|
|
66
|
+
hostId: input.hostId,
|
|
67
|
+
to: _extends({
|
|
68
|
+
country,
|
|
69
|
+
postalCode
|
|
70
|
+
}, typeof input.destination.state === 'string' && input.destination.state.trim() ? {
|
|
71
|
+
state: input.destination.state.trim().slice(0, 40)
|
|
72
|
+
} : {}, typeof input.destination.city === 'string' && input.destination.city.trim() ? {
|
|
73
|
+
city: input.destination.city.trim().slice(0, 80)
|
|
74
|
+
} : {}),
|
|
75
|
+
parcels: [
|
|
76
|
+
_extends({
|
|
77
|
+
weightGrams: Math.max(0, Math.round(cart.totalGrams))
|
|
78
|
+
}, (_cart_parcel = cart.parcel) != null ? _cart_parcel : {})
|
|
79
|
+
],
|
|
80
|
+
currency,
|
|
81
|
+
valueCents: Math.max(0, Math.round(cart.subtotalCents))
|
|
82
|
+
}, {
|
|
83
|
+
timeoutMs: (_input_timeoutMs = input.timeoutMs) != null ? _input_timeoutMs : CommerceModel.CARRIER_QUOTE_TIMEOUT_MS
|
|
84
|
+
});
|
|
85
|
+
if (!quotes || !quotes.length) return tablePlan();
|
|
86
|
+
const quoted = [];
|
|
87
|
+
const hidden = new Set();
|
|
88
|
+
for (const rate of carrierRates){
|
|
89
|
+
var _ref;
|
|
90
|
+
var _rate_carrier, _rate_carrier1;
|
|
91
|
+
const services = ((_ref = (_rate_carrier = rate.carrier) == null ? void 0 : _rate_carrier.services) != null ? _ref : []).map((key)=>key.toLowerCase());
|
|
92
|
+
const offered = quotes.filter((quote)=>quote.currency === currency && (!services.length || services.includes(quote.serviceKey.toLowerCase())));
|
|
93
|
+
if (!offered.length) continue;
|
|
94
|
+
if ((_rate_carrier1 = rate.carrier) == null ? void 0 : _rate_carrier1.fallbackRateId) hidden.add(rate.carrier.fallbackRateId);
|
|
95
|
+
for (const quote of offered){
|
|
96
|
+
quoted.push({
|
|
97
|
+
rateId: CommerceModel.carrierOptionRateId(rate.id, quote.serviceKey),
|
|
98
|
+
name: (quote.estimatedDays ? `${quote.label} (${quote.estimatedDays} business day${quote.estimatedDays === 1 ? '' : 's'})` : quote.label).slice(0, 100),
|
|
99
|
+
amountCents: CommerceModel.carrierOptionAmountCents(quote.amountCents, rate.carrier)
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (!quoted.length) return tablePlan();
|
|
104
|
+
// The table's own options for this destination stay — a flat rate the
|
|
105
|
+
// merchant offers beside carriers, local pickup — less any fallback a
|
|
106
|
+
// carrier rate replaced now that it has quotes.
|
|
107
|
+
const table = CommerceModel.resolveCheckoutShippingOptions(settings, [
|
|
108
|
+
country
|
|
109
|
+
], {
|
|
110
|
+
subtotalCents: cart.subtotalCents,
|
|
111
|
+
totalGrams: cart.totalGrams
|
|
112
|
+
}).filter((option)=>!hidden.has(option.rateId));
|
|
113
|
+
// One option per name: two carrier rates quoting the same service keep the
|
|
114
|
+
// cheaper, so a shopper never sees the same service twice.
|
|
115
|
+
const byName = new Map();
|
|
116
|
+
for (const option of [
|
|
117
|
+
...table,
|
|
118
|
+
...quoted
|
|
119
|
+
]){
|
|
120
|
+
const existing = byName.get(option.name);
|
|
121
|
+
if (!existing || option.amountCents < existing.amountCents) byName.set(option.name, option);
|
|
122
|
+
}
|
|
123
|
+
const options = [
|
|
124
|
+
...byName.values()
|
|
125
|
+
].sort((a, b)=>a.amountCents - b.amountCents || a.rateId.localeCompare(b.rateId)).slice(0, CommerceModel.MAX_CHECKOUT_SHIPPING_OPTIONS);
|
|
126
|
+
return {
|
|
127
|
+
countries: [
|
|
128
|
+
country
|
|
129
|
+
],
|
|
130
|
+
options,
|
|
131
|
+
quotedPostalCode: postalCode
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
//# sourceMappingURL=carrier-shipping.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/carrier-shipping.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n pluginShippingRateQuoter,\n quotePluginShippingRates,\n type PluginShippingParcel,\n} from '@aglyn/aglyn/plugin-manager/plugin-shipping-rates'\nimport * as CommerceModel from '../model'\n\n/**\n * LIVE CARRIER RATES AT CHECKOUT (AGL-3612): the `carrier` rate kind, priced\n * by asking core's `core.shipping-rate-quoter` — whichever plugin quotes\n * carriers — and never by importing it.\n *\n * ## Quoted before the session exists, on every door\n *\n * Stripe's hosted Checkout cannot change a session's shipping options once\n * the shopper types an address (\"The hosted page integration doesn't support\n * dynamically customizing shipping options\"), and the in-page form can only\n * by a server update after the fact — while this module's callers fix the\n * platform fee and the Connect transfer from the session's options at\n * creation. So the quote is taken BEFORE the session, against the\n * destination the shopper declares (country and postal code), and the\n * session is then restricted to that country exactly as a zone rate is\n * (AGL-1721). The same code serves cart checkout, buy-now and a draft\n * order's link, hosted and in-page, and the fee arithmetic downstream sees\n * ordinary options.\n *\n * ## The fallback is the merchant's own\n *\n * No quoter, a quoter not available for this site, or a quote that fails or\n * takes longer than {@link CommerceModel.CARRIER_QUOTE_TIMEOUT_MS}: the plan\n * is exactly the one {@link CommerceModel.planCheckoutShipping} makes from\n * the table, where a carrier rate offers nothing and its fallback rate is\n * offered. A store with no carrier rate never reaches the quoter at all, so\n * its sessions are byte-identical to the ones before this existed.\n */\n\nexport interface CarrierShippingCart {\n subtotalCents: number\n totalGrams: number\n /** One parcel's dimensions, when the cart is one product that has them. */\n parcel?: Omit<PluginShippingParcel, 'weightGrams'>\n}\n\nexport interface CarrierShippingDestination {\n country?: unknown\n postalCode?: unknown\n state?: unknown\n city?: unknown\n}\n\n/** A postal code a shopper declared, trimmed and bounded, or `undefined`. */\nexport function normalizeCheckoutPostalCode(value: unknown): string | undefined {\n if (typeof value !== 'string') return undefined\n const code = value.trim().toUpperCase().slice(0, 12)\n return /^[A-Z0-9][A-Z0-9 -]{1,11}$/.test(code) ? code : undefined\n}\n\nexport type CarrierShippingPlan = CommerceModel.CheckoutShippingPlan & {\n /** Set when the plan offers live quotes: the postal code they were priced for. */\n quotedPostalCode?: string\n /**\n * The destination's zone prices by carrier and the store can quote, but the\n * shopper has not said where in the country: ask for a postal code.\n */\n needsPostalCode?: boolean\n}\n\n/** What a shopper is told when a postal code is needed. */\nexport const CARRIER_POSTAL_CODE_MESSAGE = 'Enter the postal code you’re shipping to.'\n\n/**\n * The shipping half of a session for a store that may price by carrier.\n * See the module comment; `planCheckoutShipping` is the whole answer for any\n * store without a carrier rate.\n */\nexport async function planCheckoutShippingWithCarriers(input: {\n hostId: string\n settings: CommerceModel.ShippingSettings | undefined\n cart: CarrierShippingCart\n destination: CarrierShippingDestination\n currency?: string\n timeoutMs?: number\n}): Promise<CarrierShippingPlan> {\n const { settings, cart } = input\n const tablePlan = () =>\n CommerceModel.planCheckoutShipping(\n settings,\n { subtotalCents: cart.subtotalCents, totalGrams: cart.totalGrams },\n input.destination.country,\n )\n if (!CommerceModel.hasCarrierRates(settings)) return tablePlan()\n const quoter = pluginShippingRateQuoter()\n if (!quoter) return tablePlan()\n const available = await quoter.available(input.hostId).catch(() => false)\n if (!available) return tablePlan()\n\n const country = CommerceModel.normalizeCheckoutShippingCountry(input.destination.country)\n if (!country) {\n // Carrier prices differ by address by construction, so a session that\n // does not know the destination cannot be honest about any of them.\n return { countries: CommerceModel.CHECKOUT_SHIPPING_COUNTRIES, options: [], refusal: 'destination-required' }\n }\n const carrierRates = CommerceModel.carrierRatesFor(settings, country)\n if (!carrierRates.length) return tablePlan()\n const postalCode = normalizeCheckoutPostalCode(input.destination.postalCode)\n if (!postalCode) {\n return {\n countries: [country],\n options: [],\n refusal: 'destination-required',\n needsPostalCode: true,\n }\n }\n\n const currency = String(input.currency ?? 'usd').toLowerCase()\n const quotes = await quotePluginShippingRates(\n {\n hostId: input.hostId,\n to: {\n country,\n postalCode,\n ...(typeof input.destination.state === 'string' && input.destination.state.trim()\n ? { state: input.destination.state.trim().slice(0, 40) }\n : {}),\n ...(typeof input.destination.city === 'string' && input.destination.city.trim()\n ? { city: input.destination.city.trim().slice(0, 80) }\n : {}),\n },\n parcels: [{ weightGrams: Math.max(0, Math.round(cart.totalGrams)), ...(cart.parcel ?? {}) }],\n currency,\n valueCents: Math.max(0, Math.round(cart.subtotalCents)),\n },\n { timeoutMs: input.timeoutMs ?? CommerceModel.CARRIER_QUOTE_TIMEOUT_MS },\n )\n if (!quotes || !quotes.length) return tablePlan()\n\n const quoted: CommerceModel.ResolvedShippingRate[] = []\n const hidden = new Set<string>()\n for (const rate of carrierRates) {\n const services = (rate.carrier?.services ?? []).map((key) => key.toLowerCase())\n const offered = quotes.filter(\n (quote) => quote.currency === currency && (!services.length || services.includes(quote.serviceKey.toLowerCase())),\n )\n if (!offered.length) continue\n if (rate.carrier?.fallbackRateId) hidden.add(rate.carrier.fallbackRateId)\n for (const quote of offered) {\n quoted.push({\n rateId: CommerceModel.carrierOptionRateId(rate.id, quote.serviceKey),\n name: (quote.estimatedDays\n ? `${quote.label} (${quote.estimatedDays} business day${quote.estimatedDays === 1 ? '' : 's'})`\n : quote.label\n ).slice(0, 100),\n amountCents: CommerceModel.carrierOptionAmountCents(quote.amountCents, rate.carrier),\n })\n }\n }\n if (!quoted.length) return tablePlan()\n\n // The table's own options for this destination stay — a flat rate the\n // merchant offers beside carriers, local pickup — less any fallback a\n // carrier rate replaced now that it has quotes.\n const table = CommerceModel.resolveCheckoutShippingOptions(\n settings,\n [country],\n { subtotalCents: cart.subtotalCents, totalGrams: cart.totalGrams },\n ).filter((option) => !hidden.has(option.rateId))\n // One option per name: two carrier rates quoting the same service keep the\n // cheaper, so a shopper never sees the same service twice.\n const byName = new Map<string, CommerceModel.ResolvedShippingRate>()\n for (const option of [...table, ...quoted]) {\n const existing = byName.get(option.name)\n if (!existing || option.amountCents < existing.amountCents) byName.set(option.name, option)\n }\n const options = [...byName.values()]\n .sort((a, b) => a.amountCents - b.amountCents || a.rateId.localeCompare(b.rateId))\n .slice(0, CommerceModel.MAX_CHECKOUT_SHIPPING_OPTIONS)\n return { countries: [country], options, quotedPostalCode: postalCode }\n}\n"],"names":["pluginShippingRateQuoter","quotePluginShippingRates","CommerceModel","normalizeCheckoutPostalCode","value","undefined","code","trim","toUpperCase","slice","test","CARRIER_POSTAL_CODE_MESSAGE","planCheckoutShippingWithCarriers","input","cart","settings","tablePlan","planCheckoutShipping","subtotalCents","totalGrams","destination","country","hasCarrierRates","quoter","available","hostId","catch","normalizeCheckoutShippingCountry","countries","CHECKOUT_SHIPPING_COUNTRIES","options","refusal","carrierRates","carrierRatesFor","length","postalCode","needsPostalCode","currency","String","toLowerCase","quotes","to","state","city","parcels","weightGrams","Math","max","round","parcel","valueCents","timeoutMs","CARRIER_QUOTE_TIMEOUT_MS","quoted","hidden","Set","rate","services","carrier","map","key","offered","filter","quote","includes","serviceKey","fallbackRateId","add","push","rateId","carrierOptionRateId","id","name","estimatedDays","label","amountCents","carrierOptionAmountCents","table","resolveCheckoutShippingOptions","option","has","byName","Map","existing","get","set","values","sort","a","b","localeCompare","MAX_CHECKOUT_SHIPPING_OPTIONS","quotedPostalCode"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED,SACEA,wBAAwB,EACxBC,wBAAwB,QAEnB,oDAAmD;AAC1D,YAAYC,mBAAmB,oBAAU;AA6CzC,2EAA2E,GAC3E,OAAO,SAASC,4BAA4BC,KAAc;IACxD,IAAI,OAAOA,UAAU,UAAU,OAAOC;IACtC,MAAMC,OAAOF,MAAMG,IAAI,GAAGC,WAAW,GAAGC,KAAK,CAAC,GAAG;IACjD,OAAO,6BAA6BC,IAAI,CAACJ,QAAQA,OAAOD;AAC1D;AAYA,yDAAyD,GACzD,OAAO,MAAMM,8BAA8B,4CAA2C;AAEtF;;;;CAIC,GACD,OAAO,eAAeC,iCAAiCC,KAOtD;QAgCyBA,iBAcmDC,cAI5DD;IAjDf,MAAM,EAAEE,QAAQ,EAAED,IAAI,EAAE,GAAGD;IAC3B,MAAMG,YAAY,IAChBd,cAAce,oBAAoB,CAChCF,UACA;YAAEG,eAAeJ,KAAKI,aAAa;YAAEC,YAAYL,KAAKK,UAAU;QAAC,GACjEN,MAAMO,WAAW,CAACC,OAAO;IAE7B,IAAI,CAACnB,cAAcoB,eAAe,CAACP,WAAW,OAAOC;IACrD,MAAMO,SAASvB;IACf,IAAI,CAACuB,QAAQ,OAAOP;IACpB,MAAMQ,YAAY,MAAMD,OAAOC,SAAS,CAACX,MAAMY,MAAM,EAAEC,KAAK,CAAC,IAAM;IACnE,IAAI,CAACF,WAAW,OAAOR;IAEvB,MAAMK,UAAUnB,cAAcyB,gCAAgC,CAACd,MAAMO,WAAW,CAACC,OAAO;IACxF,IAAI,CAACA,SAAS;QACZ,sEAAsE;QACtE,oEAAoE;QACpE,OAAO;YAAEO,WAAW1B,cAAc2B,2BAA2B;YAAEC,SAAS,EAAE;YAAEC,SAAS;QAAuB;IAC9G;IACA,MAAMC,eAAe9B,cAAc+B,eAAe,CAAClB,UAAUM;IAC7D,IAAI,CAACW,aAAaE,MAAM,EAAE,OAAOlB;IACjC,MAAMmB,aAAahC,4BAA4BU,MAAMO,WAAW,CAACe,UAAU;IAC3E,IAAI,CAACA,YAAY;QACf,OAAO;YACLP,WAAW;gBAACP;aAAQ;YACpBS,SAAS,EAAE;YACXC,SAAS;YACTK,iBAAiB;QACnB;IACF;IAEA,MAAMC,WAAWC,QAAOzB,kBAAAA,MAAMwB,QAAQ,YAAdxB,kBAAkB,OAAO0B,WAAW;IAC5D,MAAMC,SAAS,MAAMvC,yBACnB;QACEwB,QAAQZ,MAAMY,MAAM;QACpBgB,IAAI;YACFpB;YACAc;WACI,OAAOtB,MAAMO,WAAW,CAACsB,KAAK,KAAK,YAAY7B,MAAMO,WAAW,CAACsB,KAAK,CAACnC,IAAI,KAC3E;YAAEmC,OAAO7B,MAAMO,WAAW,CAACsB,KAAK,CAACnC,IAAI,GAAGE,KAAK,CAAC,GAAG;QAAI,IACrD,CAAC,GACD,OAAOI,MAAMO,WAAW,CAACuB,IAAI,KAAK,YAAY9B,MAAMO,WAAW,CAACuB,IAAI,CAACpC,IAAI,KACzE;YAAEoC,MAAM9B,MAAMO,WAAW,CAACuB,IAAI,CAACpC,IAAI,GAAGE,KAAK,CAAC,GAAG;QAAI,IACnD,CAAC;QAEPmC,SAAS;YAAC;gBAAEC,aAAaC,KAAKC,GAAG,CAAC,GAAGD,KAAKE,KAAK,CAAClC,KAAKK,UAAU;gBAAQL,eAAAA,KAAKmC,MAAM,YAAXnC,eAAe,CAAC;SAAK;QAC5FuB;QACAa,YAAYJ,KAAKC,GAAG,CAAC,GAAGD,KAAKE,KAAK,CAAClC,KAAKI,aAAa;IACvD,GACA;QAAEiC,SAAS,GAAEtC,mBAAAA,MAAMsC,SAAS,YAAftC,mBAAmBX,cAAckD,wBAAwB;IAAC;IAEzE,IAAI,CAACZ,UAAU,CAACA,OAAON,MAAM,EAAE,OAAOlB;IAEtC,MAAMqC,SAA+C,EAAE;IACvD,MAAMC,SAAS,IAAIC;IACnB,KAAK,MAAMC,QAAQxB,aAAc;;YACbwB,eAKdA;QALJ,MAAMC,WAAW,UAACD,gBAAAA,KAAKE,OAAO,qBAAZF,cAAcC,QAAQ,mBAAI,EAAE,EAAEE,GAAG,CAAC,CAACC,MAAQA,IAAIrB,WAAW;QAC5E,MAAMsB,UAAUrB,OAAOsB,MAAM,CAC3B,CAACC,QAAUA,MAAM1B,QAAQ,KAAKA,YAAa,CAAA,CAACoB,SAASvB,MAAM,IAAIuB,SAASO,QAAQ,CAACD,MAAME,UAAU,CAAC1B,WAAW,GAAE;QAEjH,IAAI,CAACsB,QAAQ3B,MAAM,EAAE;QACrB,KAAIsB,iBAAAA,KAAKE,OAAO,qBAAZF,eAAcU,cAAc,EAAEZ,OAAOa,GAAG,CAACX,KAAKE,OAAO,CAACQ,cAAc;QACxE,KAAK,MAAMH,SAASF,QAAS;YAC3BR,OAAOe,IAAI,CAAC;gBACVC,QAAQnE,cAAcoE,mBAAmB,CAACd,KAAKe,EAAE,EAAER,MAAME,UAAU;gBACnEO,MAAM,AAACT,CAAAA,MAAMU,aAAa,GACtB,GAAGV,MAAMW,KAAK,CAAC,EAAE,EAAEX,MAAMU,aAAa,CAAC,aAAa,EAAEV,MAAMU,aAAa,KAAK,IAAI,KAAK,IAAI,CAAC,CAAC,GAC7FV,MAAMW,KAAK,AAAD,EACZjE,KAAK,CAAC,GAAG;gBACXkE,aAAazE,cAAc0E,wBAAwB,CAACb,MAAMY,WAAW,EAAEnB,KAAKE,OAAO;YACrF;QACF;IACF;IACA,IAAI,CAACL,OAAOnB,MAAM,EAAE,OAAOlB;IAE3B,sEAAsE;IACtE,sEAAsE;IACtE,gDAAgD;IAChD,MAAM6D,QAAQ3E,cAAc4E,8BAA8B,CACxD/D,UACA;QAACM;KAAQ,EACT;QAAEH,eAAeJ,KAAKI,aAAa;QAAEC,YAAYL,KAAKK,UAAU;IAAC,GACjE2C,MAAM,CAAC,CAACiB,SAAW,CAACzB,OAAO0B,GAAG,CAACD,OAAOV,MAAM;IAC9C,2EAA2E;IAC3E,2DAA2D;IAC3D,MAAMY,SAAS,IAAIC;IACnB,KAAK,MAAMH,UAAU;WAAIF;WAAUxB;KAAO,CAAE;QAC1C,MAAM8B,WAAWF,OAAOG,GAAG,CAACL,OAAOP,IAAI;QACvC,IAAI,CAACW,YAAYJ,OAAOJ,WAAW,GAAGQ,SAASR,WAAW,EAAEM,OAAOI,GAAG,CAACN,OAAOP,IAAI,EAAEO;IACtF;IACA,MAAMjD,UAAU;WAAImD,OAAOK,MAAM;KAAG,CACjCC,IAAI,CAAC,CAACC,GAAGC,IAAMD,EAAEb,WAAW,GAAGc,EAAEd,WAAW,IAAIa,EAAEnB,MAAM,CAACqB,aAAa,CAACD,EAAEpB,MAAM,GAC/E5D,KAAK,CAAC,GAAGP,cAAcyF,6BAA6B;IACvD,OAAO;QAAE/D,WAAW;YAACP;SAAQ;QAAES;QAAS8D,kBAAkBzD;IAAW;AACvE"}
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
import type { PluginApiHandler } from '@aglyn/aglyn/server';
|
|
18
|
+
/** An option the buyer ticked is no longer offered (AGL-3635). */
|
|
19
|
+
export declare const CHECKOUT_EXTRA_UNAVAILABLE_MESSAGE = "An option you picked is no longer available. Review your cart and try again.";
|
|
18
20
|
/**
|
|
19
21
|
* Cart checkout (AGL-293): the whole cart in one Stripe Checkout
|
|
20
22
|
* session on the merchant's account. Every line re-prices from its
|