@aglyn/plugins-commerce 1.0.0-beta.285 → 1.0.0-beta.287
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/README.md +1 -1
- package/package.json +13 -13
- package/src/lib/components/cart.js +25 -12
- package/src/lib/components/cart.js.map +1 -1
- package/src/lib/components/commerce-console-page.js +70 -13
- package/src/lib/components/commerce-console-page.js.map +1 -1
- package/src/lib/components/console/order-detail-dialog.component.js +2 -1
- package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
- package/src/lib/components/console/payment-methods-card.component.js +1 -1
- package/src/lib/components/console/payment-methods-card.component.js.map +1 -1
- package/src/lib/components/console/pos/pos-cart-panel.component.d.ts +5 -0
- package/src/lib/components/console/pos/pos-cart-panel.component.js +18 -12
- package/src/lib/components/console/pos/pos-cart-panel.component.js.map +1 -1
- package/src/lib/components/console/pos/pos-hardware-api.d.ts +76 -5
- package/src/lib/components/console/pos/pos-hardware-api.js +53 -11
- package/src/lib/components/console/pos/pos-hardware-api.js.map +1 -1
- package/src/lib/components/console/pos/pos-hardware-buyer.component.d.ts +18 -0
- package/src/lib/components/console/pos/pos-hardware-buyer.component.js +629 -0
- package/src/lib/components/console/pos/pos-hardware-buyer.component.js.map +1 -0
- package/src/lib/components/console/pos/pos-hardware-sale-api.d.ts +162 -0
- package/src/lib/components/console/pos/pos-hardware-sale-api.js +122 -0
- package/src/lib/components/console/pos/pos-hardware-sale-api.js.map +1 -0
- package/src/lib/components/console/pos/pos-hardware-sale-terms.component.d.ts +39 -0
- package/src/lib/components/console/pos/pos-hardware-sale-terms.component.js +251 -0
- package/src/lib/components/console/pos/pos-hardware-sale-terms.component.js.map +1 -0
- package/src/lib/components/console/pos/use-pos-display.js +50 -0
- package/src/lib/components/console/pos/use-pos-display.js.map +1 -1
- package/src/lib/components/console/pos-cellular-control.component.d.ts +41 -0
- package/src/lib/components/console/pos-cellular-control.component.js +211 -0
- package/src/lib/components/console/pos-cellular-control.component.js.map +1 -0
- package/src/lib/components/console/pos-devices-card.component.d.ts +9 -1
- package/src/lib/components/console/pos-devices-card.component.js +47 -15
- package/src/lib/components/console/pos-devices-card.component.js.map +1 -1
- package/src/lib/components/console/pos-display/pos-display-api.d.ts +6 -0
- package/src/lib/components/console/pos-display/pos-display-api.js +8 -1
- package/src/lib/components/console/pos-display/pos-display-api.js.map +1 -1
- package/src/lib/components/console/pos-display-page.component.d.ts +13 -0
- package/src/lib/components/console/pos-display-page.component.js +44 -2
- package/src/lib/components/console/pos-display-page.component.js.map +1 -1
- package/src/lib/components/console/pos-hardware-card.component.d.ts +12 -4
- package/src/lib/components/console/pos-hardware-card.component.js +157 -36
- package/src/lib/components/console/pos-hardware-card.component.js.map +1 -1
- package/src/lib/components/console/pos-hardware-orders-staff-page.component.js +360 -80
- package/src/lib/components/console/pos-hardware-orders-staff-page.component.js.map +1 -1
- package/src/lib/components/console/pos-hardware-terms-page.component.d.ts +34 -0
- package/src/lib/components/console/pos-hardware-terms-page.component.js +257 -0
- package/src/lib/components/console/pos-hardware-terms-page.component.js.map +1 -0
- package/src/lib/components/console/pos-hardware-terms-sign-page.component.d.ts +27 -0
- package/src/lib/components/console/pos-hardware-terms-sign-page.component.js +104 -0
- package/src/lib/components/console/pos-hardware-terms-sign-page.component.js.map +1 -0
- package/src/lib/components/console/pos-hardware-waiting-card.component.d.ts +24 -0
- package/src/lib/components/console/pos-hardware-waiting-card.component.js +205 -0
- package/src/lib/components/console/pos-hardware-waiting-card.component.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-check-in-dialog.component.js +297 -201
- package/src/lib/components/console/pos-ops/pos-check-in-dialog.component.js.map +1 -1
- package/src/lib/components/console/pos-ops/pos-check-ins-card.component.d.ts +3 -0
- package/src/lib/components/console/pos-ops/pos-check-ins-card.component.js +260 -92
- package/src/lib/components/console/pos-ops/pos-check-ins-card.component.js.map +1 -1
- package/src/lib/components/console/pos-ops/pos-operations-bar.component.d.ts +9 -0
- package/src/lib/components/console/pos-ops/pos-operations-bar.component.js +15 -6
- package/src/lib/components/console/pos-ops/pos-operations-bar.component.js.map +1 -1
- package/src/lib/components/console/pos-ops/pos-rain-check-dialog.component.d.ts +25 -0
- package/src/lib/components/console/pos-ops/pos-rain-check-dialog.component.js +136 -0
- package/src/lib/components/console/pos-ops/pos-rain-check-dialog.component.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-shift-panel.component.d.ts +6 -0
- package/src/lib/components/console/pos-ops/pos-shift-panel.component.js +48 -31
- package/src/lib/components/console/pos-ops/pos-shift-panel.component.js.map +1 -1
- package/src/lib/components/console/pos-page.component.d.ts +1 -1
- package/src/lib/components/console/pos-page.component.js +63 -12
- package/src/lib/components/console/pos-page.component.js.map +1 -1
- package/src/lib/components/console/pos-reader-splash-setting.component.js +1 -1
- package/src/lib/components/console/pos-reader-splash-setting.component.js.map +1 -1
- package/src/lib/components/console/product-check-in-fields.component.d.ts +4 -2
- package/src/lib/components/console/product-check-in-fields.component.js +60 -14
- package/src/lib/components/console/product-check-in-fields.component.js.map +1 -1
- package/src/lib/components/console/product-editor-dialog.component.js +44 -1
- package/src/lib/components/console/product-editor-dialog.component.js.map +1 -1
- package/src/lib/components/console/product-hardware-sku-field.component.d.ts +19 -0
- package/src/lib/components/console/product-hardware-sku-field.component.js +92 -0
- package/src/lib/components/console/product-hardware-sku-field.component.js.map +1 -0
- package/src/lib/components/console/product-kiosk-offer-field.component.d.ts +22 -0
- package/src/lib/components/console/product-kiosk-offer-field.component.js +94 -0
- package/src/lib/components/console/product-kiosk-offer-field.component.js.map +1 -0
- package/src/lib/components/console/product-register-fields.component.d.ts +4 -0
- package/src/lib/components/console/product-register-fields.component.js +31 -2
- package/src/lib/components/console/product-register-fields.component.js.map +1 -1
- package/src/lib/components/console/products-hub-card.component.js +11 -2
- package/src/lib/components/console/products-hub-card.component.js.map +1 -1
- package/src/lib/components/console/register-hardware-card.component.d.ts +11 -0
- package/src/lib/components/console/register-hardware-card.component.js +56 -27
- package/src/lib/components/console/register-hardware-card.component.js.map +1 -1
- package/src/lib/components/console/reservation-guests-dialog.component.d.ts +28 -0
- package/src/lib/components/console/reservation-guests-dialog.component.js +189 -0
- package/src/lib/components/console/reservation-guests-dialog.component.js.map +1 -0
- package/src/lib/components/console/reservations-card.component.d.ts +9 -0
- package/src/lib/components/console/reservations-card.component.js +158 -23
- package/src/lib/components/console/reservations-card.component.js.map +1 -1
- package/src/lib/components/console/shippingeasy-card.component.js +1 -1
- package/src/lib/components/console/shippingeasy-card.component.js.map +1 -1
- package/src/lib/components/console/shipstation-card.component.d.ts +1 -1
- package/src/lib/components/console/shipstation-card.component.js +3 -3
- package/src/lib/components/console/shipstation-card.component.js.map +1 -1
- package/src/lib/components/product-detail.d.ts +4 -0
- package/src/lib/components/product-detail.js +40 -5
- package/src/lib/components/product-detail.js.map +1 -1
- package/src/lib/components/product-reviews.js +28 -11
- package/src/lib/components/product-reviews.js.map +1 -1
- package/src/lib/components/reservation-widget.js +28 -5
- package/src/lib/components/reservation-widget.js.map +1 -1
- package/src/lib/components/use-day-picker.d.ts +25 -0
- package/src/lib/components/use-day-picker.js +57 -0
- package/src/lib/components/use-day-picker.js.map +1 -0
- package/src/lib/constants/operator-alerts.d.ts +55 -0
- package/src/lib/constants/operator-alerts.js +156 -1
- package/src/lib/constants/operator-alerts.js.map +1 -1
- package/src/lib/declarations.console-server.js +54 -1
- package/src/lib/declarations.console-server.js.map +1 -1
- package/src/lib/declarations.d.ts +4 -2
- package/src/lib/declarations.js +11 -4
- package/src/lib/declarations.js.map +1 -1
- package/src/lib/declarations.server.js +9 -0
- package/src/lib/declarations.server.js.map +1 -1
- package/src/lib/model/commerce-cart.d.ts +9 -1
- package/src/lib/model/commerce-cart.js +4 -3
- package/src/lib/model/commerce-cart.js.map +1 -1
- package/src/lib/model/commerce-check-in-product.d.ts +26 -0
- package/src/lib/model/commerce-check-in-product.js +64 -2
- package/src/lib/model/commerce-check-in-product.js.map +1 -1
- package/src/lib/model/commerce-check-in-record.d.ts +127 -0
- package/src/lib/model/commerce-check-in-record.js +36 -0
- package/src/lib/model/commerce-check-in-record.js.map +1 -0
- package/src/lib/model/commerce-check-in.d.ts +91 -87
- package/src/lib/model/commerce-check-in.js +186 -62
- package/src/lib/model/commerce-check-in.js.map +1 -1
- package/src/lib/model/commerce-kiosk-offer.d.ts +31 -0
- package/src/lib/model/commerce-kiosk-offer.js +35 -0
- package/src/lib/model/commerce-kiosk-offer.js.map +1 -0
- package/src/lib/model/commerce-orders.d.ts +76 -0
- package/src/lib/model/commerce-orders.js +6 -0
- package/src/lib/model/commerce-orders.js.map +1 -1
- package/src/lib/model/commerce-pos-day-report.d.ts +54 -1
- package/src/lib/model/commerce-pos-day-report.js +39 -2
- package/src/lib/model/commerce-pos-day-report.js.map +1 -1
- package/src/lib/model/commerce-pos-offline.d.ts +1 -1
- package/src/lib/model/commerce-pos-offline.js +6 -1
- package/src/lib/model/commerce-pos-offline.js.map +1 -1
- package/src/lib/model/commerce-pos-ops.js +3 -2
- package/src/lib/model/commerce-pos-ops.js.map +1 -1
- package/src/lib/model/commerce-pos.d.ts +36 -3
- package/src/lib/model/commerce-pos.js +14 -6
- package/src/lib/model/commerce-pos.js.map +1 -1
- package/src/lib/model/commerce-receipt.js +3 -2
- package/src/lib/model/commerce-receipt.js.map +1 -1
- package/src/lib/model/commerce-reservations.d.ts +69 -4
- package/src/lib/model/commerce-reservations.js +57 -5
- package/src/lib/model/commerce-reservations.js.map +1 -1
- package/src/lib/model/commerce.d.ts +66 -0
- package/src/lib/model/commerce.js +15 -0
- package/src/lib/model/commerce.js.map +1 -1
- package/src/lib/model/order-list-fields.d.ts +11 -0
- package/src/lib/model/order-list-fields.js +17 -1
- package/src/lib/model/order-list-fields.js.map +1 -1
- package/src/lib/model/own-store-tax-summary.d.ts +152 -0
- package/src/lib/model/own-store-tax-summary.js +288 -0
- package/src/lib/model/own-store-tax-summary.js.map +1 -0
- package/src/lib/model/plugin-permissions.d.ts +67 -0
- package/src/lib/model/plugin-permissions.js +224 -7
- package/src/lib/model/plugin-permissions.js.map +1 -1
- package/src/lib/model/pos-cellular.d.ts +223 -0
- package/src/lib/model/pos-cellular.js +293 -0
- package/src/lib/model/pos-cellular.js.map +1 -0
- package/src/lib/model/pos-hardware-in-person.d.ts +98 -0
- package/src/lib/model/pos-hardware-in-person.js +224 -0
- package/src/lib/model/pos-hardware-in-person.js.map +1 -0
- package/src/lib/model/pos-hardware-tax-summary.d.ts +166 -0
- package/src/lib/model/pos-hardware-tax-summary.js +225 -0
- package/src/lib/model/pos-hardware-tax-summary.js.map +1 -0
- package/src/lib/model/pos-hardware-terms.d.ts +74 -0
- package/src/lib/model/pos-hardware-terms.js +115 -0
- package/src/lib/model/pos-hardware-terms.js.map +1 -0
- package/src/lib/model/pos-hardware.d.ts +349 -7
- package/src/lib/model/pos-hardware.js +291 -20
- package/src/lib/model/pos-hardware.js.map +1 -1
- package/src/lib/model/product-write.d.ts +10 -0
- package/src/lib/model/product-write.js +4 -2
- package/src/lib/model/product-write.js.map +1 -1
- package/src/lib/plugin.js +16 -0
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/server/billing-webhook.js +25 -1
- package/src/lib/server/billing-webhook.js.map +1 -1
- package/src/lib/server/cancel-order.js +7 -5
- package/src/lib/server/cancel-order.js.map +1 -1
- package/src/lib/server/cart-checkout.js +20 -8
- package/src/lib/server/cart-checkout.js.map +1 -1
- package/src/lib/server/cart.js +29 -0
- package/src/lib/server/cart.js.map +1 -1
- package/src/lib/server/checkout.js +42 -13
- package/src/lib/server/checkout.js.map +1 -1
- package/src/lib/server/collection-membership.d.ts +4 -0
- package/src/lib/server/collection-membership.js +5 -10
- package/src/lib/server/collection-membership.js.map +1 -1
- package/src/lib/server/commerce-site-keys.d.ts +29 -0
- package/src/lib/server/commerce-site-keys.js +40 -0
- package/src/lib/server/commerce-site-keys.js.map +1 -0
- package/src/lib/server/draft-order.js +8 -5
- package/src/lib/server/draft-order.js.map +1 -1
- package/src/lib/server/fulfill-order.js +7 -5
- package/src/lib/server/fulfill-order.js.map +1 -1
- package/src/lib/server/gift-cards.js +8 -5
- package/src/lib/server/gift-cards.js.map +1 -1
- package/src/lib/server/local-fulfillment-status.js +9 -6
- package/src/lib/server/local-fulfillment-status.js.map +1 -1
- package/src/lib/server/member-post.js +6 -5
- package/src/lib/server/member-post.js.map +1 -1
- package/src/lib/server/membership-admin-password.d.ts +4 -2
- package/src/lib/server/membership-admin-password.js +10 -8
- package/src/lib/server/membership-admin-password.js.map +1 -1
- package/src/lib/server/membership-admin-remove.d.ts +7 -5
- package/src/lib/server/membership-admin-remove.js +9 -9
- package/src/lib/server/membership-admin-remove.js.map +1 -1
- package/src/lib/server/order-notifications.js +5 -2
- package/src/lib/server/order-notifications.js.map +1 -1
- package/src/lib/server/order-print.js +7 -5
- package/src/lib/server/order-print.js.map +1 -1
- package/src/lib/server/order-receipt-send.js +8 -5
- package/src/lib/server/order-receipt-send.js.map +1 -1
- package/src/lib/server/orders-shipping-prepare.js +9 -6
- package/src/lib/server/orders-shipping-prepare.js.map +1 -1
- package/src/lib/server/own-store-tax-return-source.d.ts +47 -0
- package/src/lib/server/own-store-tax-return-source.js +312 -0
- package/src/lib/server/own-store-tax-return-source.js.map +1 -0
- package/src/lib/server/payment-methods.js +13 -9
- package/src/lib/server/payment-methods.js.map +1 -1
- package/src/lib/server/pos-auth.d.ts +37 -6
- package/src/lib/server/pos-auth.js +40 -15
- package/src/lib/server/pos-auth.js.map +1 -1
- package/src/lib/server/pos-cellular-billing.d.ts +81 -0
- package/src/lib/server/pos-cellular-billing.js +711 -0
- package/src/lib/server/pos-cellular-billing.js.map +1 -0
- package/src/lib/server/pos-cellular-notify.d.ts +47 -0
- package/src/lib/server/pos-cellular-notify.js +150 -0
- package/src/lib/server/pos-cellular-notify.js.map +1 -0
- package/src/lib/server/pos-cellular.d.ts +88 -0
- package/src/lib/server/pos-cellular.js +339 -0
- package/src/lib/server/pos-cellular.js.map +1 -0
- package/src/lib/server/pos-check-in.d.ts +5 -1
- package/src/lib/server/pos-check-in.js +296 -28
- package/src/lib/server/pos-check-in.js.map +1 -1
- package/src/lib/server/pos-day-report.js +29 -3
- package/src/lib/server/pos-day-report.js.map +1 -1
- package/src/lib/server/pos-display.d.ts +16 -0
- package/src/lib/server/pos-display.js +129 -2
- package/src/lib/server/pos-display.js.map +1 -1
- package/src/lib/server/pos-hardware-admin.d.ts +10 -1
- package/src/lib/server/pos-hardware-admin.js +250 -84
- package/src/lib/server/pos-hardware-admin.js.map +1 -1
- package/src/lib/server/pos-hardware-attach.d.ts +105 -0
- package/src/lib/server/pos-hardware-attach.js +443 -0
- package/src/lib/server/pos-hardware-attach.js.map +1 -0
- package/src/lib/server/pos-hardware-buyer-lookup.d.ts +58 -0
- package/src/lib/server/pos-hardware-buyer-lookup.js +180 -0
- package/src/lib/server/pos-hardware-buyer-lookup.js.map +1 -0
- package/src/lib/server/pos-hardware-buyer-record.d.ts +29 -0
- package/src/lib/server/pos-hardware-buyer-record.js +86 -0
- package/src/lib/server/pos-hardware-buyer-record.js.map +1 -0
- package/src/lib/server/pos-hardware-cancel.d.ts +58 -0
- package/src/lib/server/pos-hardware-cancel.js +147 -0
- package/src/lib/server/pos-hardware-cancel.js.map +1 -0
- package/src/lib/server/pos-hardware-closure-notices.d.ts +27 -0
- package/src/lib/server/pos-hardware-closure-notices.js +85 -0
- package/src/lib/server/pos-hardware-closure-notices.js.map +1 -0
- package/src/lib/server/pos-hardware-closure.d.ts +60 -0
- package/src/lib/server/pos-hardware-closure.js +153 -0
- package/src/lib/server/pos-hardware-closure.js.map +1 -0
- package/src/lib/server/pos-hardware-in-person.d.ts +61 -0
- package/src/lib/server/pos-hardware-in-person.js +236 -0
- package/src/lib/server/pos-hardware-in-person.js.map +1 -0
- package/src/lib/server/pos-hardware-notify.d.ts +40 -2
- package/src/lib/server/pos-hardware-notify.js +195 -14
- package/src/lib/server/pos-hardware-notify.js.map +1 -1
- package/src/lib/server/pos-hardware-readers.d.ts +115 -0
- package/src/lib/server/pos-hardware-readers.js +430 -0
- package/src/lib/server/pos-hardware-readers.js.map +1 -0
- package/src/lib/server/pos-hardware-returns.d.ts +116 -0
- package/src/lib/server/pos-hardware-returns.js +502 -0
- package/src/lib/server/pos-hardware-returns.js.map +1 -0
- package/src/lib/server/pos-hardware-sale-fields.d.ts +28 -0
- package/src/lib/server/pos-hardware-sale-fields.js +44 -0
- package/src/lib/server/pos-hardware-sale-fields.js.map +1 -0
- package/src/lib/server/pos-hardware-sale.d.ts +54 -0
- package/src/lib/server/pos-hardware-sale.js +369 -0
- package/src/lib/server/pos-hardware-sale.js.map +1 -0
- package/src/lib/server/pos-hardware-tax-return-source.d.ts +99 -0
- package/src/lib/server/pos-hardware-tax-return-source.js +462 -0
- package/src/lib/server/pos-hardware-tax-return-source.js.map +1 -0
- package/src/lib/server/pos-hardware-terms.d.ts +64 -0
- package/src/lib/server/pos-hardware-terms.js +154 -0
- package/src/lib/server/pos-hardware-terms.js.map +1 -0
- package/src/lib/server/pos-hardware-user-eraser.d.ts +3 -0
- package/src/lib/server/pos-hardware-user-eraser.js +31 -7
- package/src/lib/server/pos-hardware-user-eraser.js.map +1 -1
- package/src/lib/server/pos-hardware-webhook.d.ts +5 -0
- package/src/lib/server/pos-hardware-webhook.js +51 -6
- package/src/lib/server/pos-hardware-webhook.js.map +1 -1
- package/src/lib/server/pos-hardware.d.ts +74 -1
- package/src/lib/server/pos-hardware.js +175 -10
- package/src/lib/server/pos-hardware.js.map +1 -1
- package/src/lib/server/pos-kiosk.d.ts +2 -0
- package/src/lib/server/pos-kiosk.js +17 -12
- package/src/lib/server/pos-kiosk.js.map +1 -1
- package/src/lib/server/pos-offline-card-order.d.ts +64 -0
- package/src/lib/server/pos-offline-card-order.js +102 -0
- package/src/lib/server/pos-offline-card-order.js.map +1 -0
- package/src/lib/server/pos-offline-card-reconcile.d.ts +67 -1
- package/src/lib/server/pos-offline-card-reconcile.js +215 -18
- package/src/lib/server/pos-offline-card-reconcile.js.map +1 -1
- package/src/lib/server/pos-offline-sync.d.ts +39 -0
- package/src/lib/server/pos-offline-sync.js +190 -55
- package/src/lib/server/pos-offline-sync.js.map +1 -1
- package/src/lib/server/pos-ops-gate.d.ts +15 -4
- package/src/lib/server/pos-ops-gate.js +42 -9
- package/src/lib/server/pos-ops-gate.js.map +1 -1
- package/src/lib/server/pos-ops-routes.js +24 -0
- package/src/lib/server/pos-ops-routes.js.map +1 -1
- package/src/lib/server/pos-order-refund-ids.d.ts +28 -0
- package/src/lib/server/pos-order-refund-ids.js +31 -0
- package/src/lib/server/pos-order-refund-ids.js.map +1 -0
- package/src/lib/server/pos-order.js +52 -49
- package/src/lib/server/pos-order.js.map +1 -1
- package/src/lib/server/pos-payment.js +1 -1
- package/src/lib/server/pos-payment.js.map +1 -1
- package/src/lib/server/pos-reader-splash-admin.js +30 -32
- package/src/lib/server/pos-reader-splash-admin.js.map +1 -1
- package/src/lib/server/pos-reader-splash-images-route.d.ts +17 -0
- package/src/lib/server/pos-reader-splash-images-route.js +113 -0
- package/src/lib/server/pos-reader-splash-images-route.js.map +1 -0
- package/src/lib/server/pos-reader-splash-images.d.ts +51 -0
- package/src/lib/server/pos-reader-splash-images.js +123 -0
- package/src/lib/server/pos-reader-splash-images.js.map +1 -0
- package/src/lib/server/pos-reader-splash.d.ts +68 -1
- package/src/lib/server/pos-reader-splash.js +182 -11
- package/src/lib/server/pos-reader-splash.js.map +1 -1
- package/src/lib/server/pos-readers.d.ts +29 -0
- package/src/lib/server/pos-readers.js +134 -35
- package/src/lib/server/pos-readers.js.map +1 -1
- package/src/lib/server/pos-return.d.ts +10 -0
- package/src/lib/server/pos-return.js +26 -1
- package/src/lib/server/pos-return.js.map +1 -1
- package/src/lib/server/pos-sale.js +6 -1
- package/src/lib/server/pos-sale.js.map +1 -1
- package/src/lib/server/pos-shift.js +11 -0
- package/src/lib/server/pos-shift.js.map +1 -1
- package/src/lib/server/pos-staff-pin.js +25 -20
- package/src/lib/server/pos-staff-pin.js.map +1 -1
- package/src/lib/server/pos-terminal.d.ts +14 -4
- package/src/lib/server/pos-terminal.js +34 -38
- package/src/lib/server/pos-terminal.js.map +1 -1
- package/src/lib/server/printers.d.ts +7 -3
- package/src/lib/server/printers.js +18 -12
- package/src/lib/server/printers.js.map +1 -1
- package/src/lib/server/product-drafts.d.ts +11 -1
- package/src/lib/server/product-drafts.js +12 -8
- package/src/lib/server/product-drafts.js.map +1 -1
- package/src/lib/server/product.d.ts +15 -1
- package/src/lib/server/product.js +16 -3
- package/src/lib/server/product.js.map +1 -1
- package/src/lib/server/products-write.d.ts +26 -2
- package/src/lib/server/products-write.js +19 -7
- package/src/lib/server/products-write.js.map +1 -1
- package/src/lib/server/refund.js +34 -11
- package/src/lib/server/refund.js.map +1 -1
- package/src/lib/server/reservation-availability-query.d.ts +8 -0
- package/src/lib/server/reservation-availability-query.js +11 -1
- package/src/lib/server/reservation-availability-query.js.map +1 -1
- package/src/lib/server/reservation-availability.d.ts +1 -1
- package/src/lib/server/reservation-availability.js +7 -2
- package/src/lib/server/reservation-availability.js.map +1 -1
- package/src/lib/server/reservation-guests.d.ts +32 -0
- package/src/lib/server/reservation-guests.js +285 -0
- package/src/lib/server/reservation-guests.js.map +1 -0
- package/src/lib/server/reservation-walk-in.d.ts +11 -1
- package/src/lib/server/reservation-walk-in.js +56 -12
- package/src/lib/server/reservation-walk-in.js.map +1 -1
- package/src/lib/server/reserve.js +18 -5
- package/src/lib/server/reserve.js.map +1 -1
- package/src/lib/server/returns.js +9 -6
- package/src/lib/server/returns.js.map +1 -1
- package/src/lib/server/reviews.d.ts +22 -2
- package/src/lib/server/reviews.js +88 -20
- package/src/lib/server/reviews.js.map +1 -1
- package/src/lib/server/shipping-connectors.js +10 -11
- package/src/lib/server/shipping-connectors.js.map +1 -1
- package/src/lib/server/site-page-resolver.js +20 -3
- package/src/lib/server/site-page-resolver.js.map +1 -1
- package/src/lib/server/store-day.d.ts +33 -0
- package/src/lib/server/store-day.js +46 -0
- package/src/lib/server/store-day.js.map +1 -0
- package/src/lib/server/store-setup-ai-writer.d.ts +2 -1
- package/src/lib/server/store-setup-ai-writer.js +5 -6
- package/src/lib/server/store-setup-ai-writer.js.map +1 -1
- package/src/lib/server/storefront-tax.d.ts +13 -0
- package/src/lib/server/storefront-tax.js +8 -1
- package/src/lib/server/storefront-tax.js.map +1 -1
- package/src/lib/server/tax-return-source.d.ts +32 -3
- package/src/lib/server/tax-return-source.js +99 -20
- package/src/lib/server/tax-return-source.js.map +1 -1
- package/src/lib/server.js +100 -2
- package/src/lib/server.js.map +1 -1
- package/src/lib/testing/fake-firestore.js +58 -16
- package/src/lib/testing/fake-firestore.js.map +1 -1
- package/src/lib/testing/pos-ops-memory-firestore.js +18 -4
- package/src/lib/testing/pos-ops-memory-firestore.js.map +1 -1
- package/src/lib/testing/site-register-permissions.d.ts +29 -0
- package/src/lib/testing/site-register-permissions.js +38 -0
- package/src/lib/testing/site-register-permissions.js.map +1 -0
- package/src/lib/transfer/tracking.server.js +8 -5
- package/src/lib/transfer/tracking.server.js.map +1 -1
- package/src/lib/utils/add-to-cart.d.ts +2 -0
- package/src/lib/utils/add-to-cart.js +6 -3
- package/src/lib/utils/add-to-cart.js.map +1 -1
|
@@ -15,9 +15,11 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
|
15
15
|
* See the License for the specific language governing permissions and
|
|
16
16
|
* limitations under the License.
|
|
17
17
|
*/ import { createHash } from "crypto";
|
|
18
|
+
import * as Aglyn from "@aglyn/aglyn/server";
|
|
18
19
|
import { firebaseAdmin, readOrgBilling } from "@aglyn/tenant-data-admin";
|
|
19
20
|
import { hostConsoleUrl } from "@aglyn/tenant-data-admin/server/host-console-link";
|
|
20
|
-
import { encodePosHardwareLines, isPosHardwareShippingMethod, POS_HARDWARE_ANCHOR, parsePosHardwareConfig, POS_HARDWARE_CURRENCY, POS_HARDWARE_METADATA_TYPE, POS_HARDWARE_ORDERS_COLLECTION, POS_HARDWARE_SALES_COLLECTION, POS_HARDWARE_SHIP_COUNTRIES, POS_HARDWARE_SHIPPING_LABELS, posHardwareOffers, posHardwareSku, pricePosHardwareCart } from "../model/pos-hardware.js";
|
|
21
|
+
import { encodePosHardwareLines, isPosHardwareShippingMethod, POS_HARDWARE_ANCHOR, parsePosHardwareConfig, parsePosHardwareInPersonConfig, POS_HARDWARE_CURRENCY, POS_HARDWARE_METADATA_TYPE, POS_HARDWARE_ORDERS_COLLECTION, POS_HARDWARE_SALES_COLLECTION, POS_HARDWARE_SHIP_COUNTRIES, POS_HARDWARE_SHIPPING_LABELS, posHardwareOffers, posHardwareOrderSource, posHardwareSku, pricePosHardwareCart } from "../model/pos-hardware.js";
|
|
22
|
+
import { mayVisitPosHardwareShop } from "../model/plugin-permissions.js";
|
|
21
23
|
import { authorizePosStaff, posIdempotencyKey, posRequestBody } from "./pos-auth.js";
|
|
22
24
|
import { posStripe, posTerminalAvailable } from "./pos-stripe.js";
|
|
23
25
|
/*==========================================
|
|
@@ -28,9 +30,12 @@ import { posStripe, posTerminalAvailable } from "./pos-stripe.js";
|
|
|
28
30
|
* checkout a Stripe Checkout Session for the basket, on the PLATFORM
|
|
29
31
|
* orders this site's hardware orders, newest first
|
|
30
32
|
*
|
|
31
|
-
* Gated like the register (`authorizePosStaff
|
|
32
|
-
*
|
|
33
|
-
*
|
|
33
|
+
* Gated like the register (`authorizePosStaff`, on a plan with POS), because
|
|
34
|
+
* the readers it sells are the register's, with one difference (AGL-4047):
|
|
35
|
+
* the shop admits whoever works the register (`managePos`) AND whoever may
|
|
36
|
+
* buy hardware (`posBuyHardware`), which stands on its own — a bookkeeper
|
|
37
|
+
* with no register orders the store's readers. A checkout needs
|
|
38
|
+
* `posBuyHardware`; seeing the catalog and the site's orders needs either.
|
|
34
39
|
*
|
|
35
40
|
* THE SALE IS THE PLATFORM'S. The session is created with the platform key
|
|
36
41
|
* and NO connected account, `transfer_data` or application fee: the merchant
|
|
@@ -43,6 +48,23 @@ import { posStripe, posTerminalAvailable } from "./pos-stripe.js";
|
|
|
43
48
|
if (!posTerminalAvailable()) return null;
|
|
44
49
|
return parsePosHardwareConfig(env);
|
|
45
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* The platform's own store that sells hardware in person (AGL-4038), or
|
|
53
|
+
* `null` while that is off. Read like the shop's other figures; a store is
|
|
54
|
+
* the seller only when BOTH its id and its workspace's match, so a site moved
|
|
55
|
+
* to another workspace stops selling hardware rather than selling it for them.
|
|
56
|
+
*/ export function posHardwareInPersonConfig(env = process.env) {
|
|
57
|
+
return parsePosHardwareInPersonConfig(env);
|
|
58
|
+
}
|
|
59
|
+
/** Whether a store, owned by `orgId`, is the platform's own hardware seller. */ export function isPosHardwareSellerStore(config, hostId, orgId) {
|
|
60
|
+
return Boolean(config) && (config == null ? void 0 : config.sellerHostId) === hostId && (config == null ? void 0 : config.sellerOrgId) === orgId;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* An in-person order's id, from the register sale it came from: one register
|
|
64
|
+
* sale is one hardware order however often its completion is told.
|
|
65
|
+
*/ export function posHardwareInPersonOrderId(hostId, registerOrderId) {
|
|
66
|
+
return `hw_${createHash('sha256').update(`pos:${hostId}:${registerOrderId}`).digest('hex').slice(0, 20)}`;
|
|
67
|
+
}
|
|
46
68
|
/** The order's id, derived from the attempt so a repeated press is one order. */ export function posHardwareOrderId(orgId, hostId, attemptKey) {
|
|
47
69
|
return `hw_${createHash('sha256').update(`${orgId}:${hostId}:${attemptKey}`).digest('hex').slice(0, 20)}`;
|
|
48
70
|
}
|
|
@@ -60,7 +82,7 @@ export function hardwareOrdersRef(orgId) {
|
|
|
60
82
|
return firebaseAdmin.app().firestore().collection(POS_HARDWARE_SALES_COLLECTION).doc(orderId);
|
|
61
83
|
}
|
|
62
84
|
/** An order as the merchant's card shows it: no Stripe ids, no staff notes. */ export function merchantHardwareOrderView(id, order) {
|
|
63
|
-
var _order_lines, _order_subtotalCents, _ref, _ref1, _order_taxCents, _order_totalCents, _order_tracking, _order_createdAtMs, _ref2, _order_updatedAtMs;
|
|
85
|
+
var _order_lines, _order_subtotalCents, _ref, _ref1, _order_taxCents, _order_totalCents, _order_tracking, _order_createdAtMs, _ref2, _order_updatedAtMs, _order_discountCents, _order_units, _order_refundedCents;
|
|
64
86
|
var _order_shipping, _order_shipping1;
|
|
65
87
|
return {
|
|
66
88
|
id,
|
|
@@ -80,7 +102,17 @@ export function hardwareOrdersRef(orgId) {
|
|
|
80
102
|
totalCents: (_order_totalCents = order.totalCents) != null ? _order_totalCents : 0,
|
|
81
103
|
tracking: (_order_tracking = order.tracking) != null ? _order_tracking : null,
|
|
82
104
|
createdAtMs: (_order_createdAtMs = order.createdAtMs) != null ? _order_createdAtMs : 0,
|
|
83
|
-
updatedAtMs: (_ref2 = (_order_updatedAtMs = order.updatedAtMs) != null ? _order_updatedAtMs : order.createdAtMs) != null ? _ref2 : 0
|
|
105
|
+
updatedAtMs: (_ref2 = (_order_updatedAtMs = order.updatedAtMs) != null ? _order_updatedAtMs : order.createdAtMs) != null ? _ref2 : 0,
|
|
106
|
+
// Bought in person (AGL-4038): handed over at the sale, no parcel.
|
|
107
|
+
source: posHardwareOrderSource(order),
|
|
108
|
+
discountCents: (_order_discountCents = order.discountCents) != null ? _order_discountCents : 0,
|
|
109
|
+
/** Readers still to set up, for an in-person order that took serials. */ readersToSetUp: ((_order_units = order.units) != null ? _order_units : []).filter((unit)=>!unit.readerId).length,
|
|
110
|
+
refundedCents: (_order_refundedCents = order.refundedCents) != null ? _order_refundedCents : 0,
|
|
111
|
+
/** The buyer's return request and what was decided, without who asked. */ returnRequest: order.returnRequest ? {
|
|
112
|
+
state: order.returnRequest.state,
|
|
113
|
+
requestedAtMs: order.returnRequest.requestedAtMs,
|
|
114
|
+
note: order.returnRequest.note
|
|
115
|
+
} : null
|
|
84
116
|
};
|
|
85
117
|
}
|
|
86
118
|
/** The POS settings page of a site, as an absolute console URL. */ export async function posSettingsUrl(hostId) {
|
|
@@ -91,6 +123,59 @@ export function hardwareOrdersRef(orgId) {
|
|
|
91
123
|
const joiner = path.includes('?') ? '&' : '?';
|
|
92
124
|
return `${path}${joiner}${query}#${hash}`;
|
|
93
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* The readers this workspace bought in person that are not set up yet
|
|
128
|
+
* (AGL-4038): whether its plan includes the point of sale, its stores and
|
|
129
|
+
* whether each can take a reader, and each order with what it waits for.
|
|
130
|
+
* Nothing at all while the in-person sale is off.
|
|
131
|
+
*/ export async function waitingInPersonReaders(orgId, hostId) {
|
|
132
|
+
if (!posHardwareInPersonConfig() || !orgId) return {
|
|
133
|
+
posPlan: false,
|
|
134
|
+
stores: [],
|
|
135
|
+
orders: []
|
|
136
|
+
};
|
|
137
|
+
const firestore = firebaseAdmin.app().firestore();
|
|
138
|
+
const [orders, org, hosts] = await Promise.all([
|
|
139
|
+
hardwareOrdersRef(orgId).where('attachment.state', '==', 'attached').where('status', '==', 'delivered').limit(20).get(),
|
|
140
|
+
firestore.collection('orgs').doc(orgId).get(),
|
|
141
|
+
firestore.collection('hosts').where('orgId', '==', orgId).limit(20).get()
|
|
142
|
+
]);
|
|
143
|
+
if (!orders.docs.length) return {
|
|
144
|
+
posPlan: false,
|
|
145
|
+
stores: [],
|
|
146
|
+
orders: []
|
|
147
|
+
};
|
|
148
|
+
const stores = await Promise.all(hosts.docs.map(async (doc)=>{
|
|
149
|
+
var _ref, _doc_get;
|
|
150
|
+
const id = String(doc.id);
|
|
151
|
+
const [terminal, setupUrl] = await Promise.all([
|
|
152
|
+
firestore.collection('hosts').doc(id).collection('terminal').doc('config').get(),
|
|
153
|
+
posSettingsUrl(id)
|
|
154
|
+
]);
|
|
155
|
+
return {
|
|
156
|
+
hostId: id,
|
|
157
|
+
name: String((_ref = (_doc_get = doc.get('name')) != null ? _doc_get : doc.get('title')) != null ? _ref : id),
|
|
158
|
+
hasLocation: Boolean(terminal.exists && terminal.get('stripeLocationId')),
|
|
159
|
+
setupUrl: `${setupUrl.split('#')[0]}#pos-devices`
|
|
160
|
+
};
|
|
161
|
+
}));
|
|
162
|
+
return {
|
|
163
|
+
posPlan: Aglyn.checkEntitlement(org.data(), 'pos'),
|
|
164
|
+
stores,
|
|
165
|
+
// Every store's, this store's first: a reader waits wherever the
|
|
166
|
+
// workspace's people look.
|
|
167
|
+
orders: orders.docs.map((doc)=>({
|
|
168
|
+
id: String(doc.id),
|
|
169
|
+
order: doc.data()
|
|
170
|
+
})).filter(({ order })=>order.source === 'in_person').sort((a, b)=>Number(b.order.hostId === hostId) - Number(a.order.hostId === hostId)).map(({ id, order })=>{
|
|
171
|
+
var _order_units;
|
|
172
|
+
return _extends({}, merchantHardwareOrderView(id, order), {
|
|
173
|
+
hostId: order.hostId,
|
|
174
|
+
serialsTaken: ((_order_units = order.units) != null ? _order_units : []).filter((unit)=>unit.serialNumber && !unit.readerId).length
|
|
175
|
+
});
|
|
176
|
+
})
|
|
177
|
+
};
|
|
178
|
+
}
|
|
94
179
|
export const posHardwareHandler = async (req, res)=>{
|
|
95
180
|
var _body_hostId, _body_action;
|
|
96
181
|
if (req.method !== 'POST') return res.status(405).json({
|
|
@@ -98,15 +183,85 @@ export const posHardwareHandler = async (req, res)=>{
|
|
|
98
183
|
});
|
|
99
184
|
const body = posRequestBody(req);
|
|
100
185
|
const hostId = String((_body_hostId = body['hostId']) != null ? _body_hostId : '');
|
|
101
|
-
const
|
|
186
|
+
const action = String((_body_action = body['action']) != null ? _body_action : '');
|
|
187
|
+
// BUYING IS ITS OWN KEY (AGL-4047): anyone who works the register or may
|
|
188
|
+
// buy hardware sees what the shop offers and what this site ordered, and
|
|
189
|
+
// only a member holding "Buy point of sale hardware" — which follows
|
|
190
|
+
// `managePos` until a role or the member sets it, and may be granted
|
|
191
|
+
// without it — starts a checkout that the workspace pays for.
|
|
192
|
+
//
|
|
193
|
+
// A READER BOUGHT IN PERSON (AGL-4038): `waiting` is read without the
|
|
194
|
+
// point of sale plan, because a workspace without it is exactly the one
|
|
195
|
+
// that must be told to add it first; choosing its store and marking it set
|
|
196
|
+
// up are setting up devices (`posDevices`) on the store named.
|
|
197
|
+
const settingUp = action === 'choose-store' || action === 'mark-set-up';
|
|
198
|
+
const gate = await authorizePosStaff(req, hostId, action === 'checkout' ? 'posBuyHardware' : settingUp ? 'posDevices' : undefined, mayVisitPosHardwareShop, // A workspace whose plan lost the point of sale still sees what it bought
|
|
199
|
+
// and may ask to return a reader bought in person.
|
|
200
|
+
action === 'waiting' || action === 'orders' || action === 'request-return' ? {
|
|
201
|
+
planRequired: false
|
|
202
|
+
} : {});
|
|
102
203
|
if ('error' in gate) return res.status(gate.status).json({
|
|
103
204
|
error: gate.error
|
|
104
205
|
});
|
|
105
206
|
const staff = gate.staff;
|
|
106
207
|
const config = posHardwareConfig();
|
|
107
|
-
const action = String((_body_action = body['action']) != null ? _body_action : '');
|
|
108
208
|
try {
|
|
109
209
|
switch(action){
|
|
210
|
+
case 'waiting':
|
|
211
|
+
return res.status(200).json(await waitingInPersonReaders(staff.orgId, staff.hostId));
|
|
212
|
+
case 'request-return':
|
|
213
|
+
{
|
|
214
|
+
var _body_orderId;
|
|
215
|
+
const returns = await import("./pos-hardware-returns.js");
|
|
216
|
+
const orderId = String((_body_orderId = body['orderId']) != null ? _body_orderId : '');
|
|
217
|
+
try {
|
|
218
|
+
const order = await returns.requestPosHardwareReturn({
|
|
219
|
+
orgId: staff.orgId,
|
|
220
|
+
orderId,
|
|
221
|
+
uid: staff.uid,
|
|
222
|
+
reason: body['reason']
|
|
223
|
+
});
|
|
224
|
+
return res.status(200).json({
|
|
225
|
+
ok: true,
|
|
226
|
+
order: merchantHardwareOrderView(orderId, order)
|
|
227
|
+
});
|
|
228
|
+
} catch (error) {
|
|
229
|
+
if (error instanceof returns.PosHardwareReturnRefusal) {
|
|
230
|
+
return res.status(error.status).json({
|
|
231
|
+
error: error.message
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
throw error;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
case 'choose-store':
|
|
238
|
+
case 'mark-set-up':
|
|
239
|
+
{
|
|
240
|
+
var _body_orderId1;
|
|
241
|
+
const readers = await import("./pos-hardware-readers.js");
|
|
242
|
+
const orderId = String((_body_orderId1 = body['orderId']) != null ? _body_orderId1 : '');
|
|
243
|
+
try {
|
|
244
|
+
const order = action === 'choose-store' ? await readers.choosePosHardwareStore({
|
|
245
|
+
orgId: staff.orgId,
|
|
246
|
+
orderId,
|
|
247
|
+
hostId: staff.hostId
|
|
248
|
+
}) : await readers.markPosHardwareSetUp({
|
|
249
|
+
orgId: staff.orgId,
|
|
250
|
+
orderId
|
|
251
|
+
});
|
|
252
|
+
return res.status(200).json({
|
|
253
|
+
ok: true,
|
|
254
|
+
order: merchantHardwareOrderView(orderId, order)
|
|
255
|
+
});
|
|
256
|
+
} catch (error) {
|
|
257
|
+
if (error instanceof readers.PosHardwareReaderRefusal) {
|
|
258
|
+
return res.status(error.status).json({
|
|
259
|
+
error: error.message
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
throw error;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
110
265
|
case 'catalog':
|
|
111
266
|
if (!config) return res.status(200).json({
|
|
112
267
|
available: false
|
|
@@ -124,9 +279,19 @@ export const posHardwareHandler = async (req, res)=>{
|
|
|
124
279
|
});
|
|
125
280
|
case 'orders':
|
|
126
281
|
{
|
|
127
|
-
|
|
282
|
+
// This site's orders, and the readers bought in person for the
|
|
283
|
+
// workspace that wait for a store to be chosen at setup (AGL-4038).
|
|
284
|
+
// A sale on the selling workspace's own To attach list is never one.
|
|
285
|
+
const [site, workspace] = await Promise.all([
|
|
286
|
+
hardwareOrdersRef(staff.orgId).where('hostId', '==', staff.hostId).orderBy('createdAtMs', 'desc').limit(50).get(),
|
|
287
|
+
hardwareOrdersRef(staff.orgId).where('hostId', '==', '').where('attachment.state', '==', 'attached').orderBy('createdAtMs', 'desc').limit(50).get()
|
|
288
|
+
]);
|
|
289
|
+
const orders = [
|
|
290
|
+
...site.docs,
|
|
291
|
+
...workspace.docs
|
|
292
|
+
].map((doc)=>merchantHardwareOrderView(String(doc.id), doc.data())).sort((a, b)=>b.createdAtMs - a.createdAtMs).slice(0, 50);
|
|
128
293
|
return res.status(200).json({
|
|
129
|
-
orders
|
|
294
|
+
orders
|
|
130
295
|
});
|
|
131
296
|
}
|
|
132
297
|
case 'checkout':
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/pos-hardware.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 { createHash } from 'crypto'\nimport type { PluginApiHandler } from '@aglyn/aglyn/server'\nimport { firebaseAdmin, readOrgBilling } from '@aglyn/tenant-data-admin'\nimport { hostConsoleUrl } from '@aglyn/tenant-data-admin/server/host-console-link'\nimport {\n encodePosHardwareLines,\n isPosHardwareShippingMethod,\n POS_HARDWARE_ANCHOR,\n parsePosHardwareConfig,\n POS_HARDWARE_CURRENCY,\n POS_HARDWARE_METADATA_TYPE,\n POS_HARDWARE_ORDERS_COLLECTION,\n POS_HARDWARE_SALES_COLLECTION,\n POS_HARDWARE_SHIP_COUNTRIES,\n POS_HARDWARE_SHIPPING_LABELS,\n posHardwareOffers,\n posHardwareSku,\n pricePosHardwareCart,\n type PosHardwareConfig,\n type PosHardwareOrder,\n} from '../model/pos-hardware'\nimport { authorizePosStaff, posIdempotencyKey, posRequestBody } from './pos-auth'\nimport { posStripe, posTerminalAvailable } from './pos-stripe'\n\n/*==========================================\n * `POST /api/commerce/pos-hardware` (AGL-4038): the merchant's half of the\n * POS hardware shop, behind the Hardware card on Products → Point of sale.\n *\n * catalog what is on offer and at what price, or `available: false`\n * checkout a Stripe Checkout Session for the basket, on the PLATFORM\n * orders this site's hardware orders, newest first\n *\n * Gated like the register (`authorizePosStaff`: an admin or editor of the\n * site with `managePos`, on a plan with POS), because the readers it sells\n * are the register's.\n *\n * THE SALE IS THE PLATFORM'S. The session is created with the platform key\n * and NO connected account, `transfer_data` or application fee: the merchant\n * is the buyer here, and the platform is the seller of record that places\n * the order with Stripe. The order document is written by the webhook once\n * Stripe says the session is paid (`pos-hardware-webhook.ts`), never here.\n *=========================================*/\n\n/** The shop's config from this deployment, or `null` while it is hidden. */\nexport function posHardwareConfig(\n env: Record<string, string | undefined> = process.env,\n): PosHardwareConfig | null {\n // A reader the platform cannot yet take payments on is not for sale: the\n // shop opens only where the register offers card readers at all.\n if (!posTerminalAvailable()) return null\n return parsePosHardwareConfig(env)\n}\n\n/** The order's id, derived from the attempt so a repeated press is one order. */\nexport function posHardwareOrderId(orgId: string, hostId: string, attemptKey: string): string {\n return `hw_${createHash('sha256').update(`${orgId}:${hostId}:${attemptKey}`).digest('hex').slice(0, 20)}`\n}\n\n/** The number a person reads: `HW-` and six characters of the id. */\nexport function posHardwareOrderNumber(orderId: string): string {\n return `HW-${orderId.replace(/^hw_/, '').slice(0, 6).toUpperCase()}`\n}\n\nexport function hardwareOrdersRef(orgId: string) {\n return firebaseAdmin\n .app()\n .firestore()\n .collection('orgs')\n .doc(orgId)\n .collection(POS_HARDWARE_ORDERS_COLLECTION)\n}\n\n/**\n * `posHardwareSales/{orderId}`, the retained sale record beside each order\n * (see `PosHardwareSaleRecord`). Top-level on purpose: the workspace erasure\n * cannot reach it.\n */\nexport function posHardwareSaleRef(orderId: string) {\n return firebaseAdmin.app().firestore().collection(POS_HARDWARE_SALES_COLLECTION).doc(orderId)\n}\n\n/** An order as the merchant's card shows it: no Stripe ids, no staff notes. */\nexport function merchantHardwareOrderView(id: string, order: PosHardwareOrder) {\n return {\n id,\n number: posHardwareOrderNumber(id),\n status: order.status,\n lines: (order.lines ?? []).map((line) => ({\n sku: line.sku,\n name: line.name,\n quantity: line.quantity,\n unitCents: line.unitCents,\n lineCents: line.lineCents,\n })),\n subtotalCents: order.subtotalCents ?? 0,\n shippingCents: order.shipping?.cents ?? 0,\n shippingLabel: order.shipping?.label ?? '',\n taxCents: order.taxCents ?? 0,\n totalCents: order.totalCents ?? 0,\n tracking: order.tracking ?? null,\n createdAtMs: order.createdAtMs ?? 0,\n updatedAtMs: order.updatedAtMs ?? order.createdAtMs ?? 0,\n }\n}\n\nexport type MerchantHardwareOrderView = ReturnType<typeof merchantHardwareOrderView>\n\n/** The POS settings page of a site, as an absolute console URL. */\nexport async function posSettingsUrl(hostId: string): Promise<string> {\n return hostConsoleUrl(hostId, `/${hostId}/products/pos`)\n}\n\n/** `base` with `query` added before any `#fragment`, then `#hash`. */\nexport function withQueryAndHash(base: string, query: string, hash: string): string {\n const [path] = base.split('#')\n const joiner = path.includes('?') ? '&' : '?'\n return `${path}${joiner}${query}#${hash}`\n}\n\n\nexport const posHardwareHandler: PluginApiHandler = async (req, res) => {\n if (req.method !== 'POST') return res.status(405).json({ error: 'Method not allowed' })\n const body = posRequestBody(req)\n const hostId = String(body['hostId'] ?? '')\n const gate = await authorizePosStaff(req, hostId)\n if ('error' in gate) return res.status(gate.status).json({ error: gate.error })\n const staff = gate.staff\n const config = posHardwareConfig()\n const action = String(body['action'] ?? '')\n try {\n switch (action) {\n case 'catalog':\n if (!config) return res.status(200).json({ available: false })\n return res.status(200).json({\n available: true,\n offers: posHardwareOffers(config),\n shipping: config.shipping.map((option) => ({\n method: option.method,\n label: POS_HARDWARE_SHIPPING_LABELS[option.method],\n cents: option.cents,\n })),\n automaticTax: config.automaticTax,\n shipCountries: POS_HARDWARE_SHIP_COUNTRIES,\n })\n case 'orders': {\n const snapshot = await hardwareOrdersRef(staff.orgId)\n .where('hostId', '==', staff.hostId)\n .orderBy('createdAtMs', 'desc')\n .limit(50)\n .get()\n return res.status(200).json({\n orders: snapshot.docs.map((doc: any) =>\n merchantHardwareOrderView(String(doc.id), doc.data() as PosHardwareOrder),\n ),\n })\n }\n case 'checkout': {\n if (!config) return res.status(404).json({ error: 'The hardware shop is not available.' })\n const attemptKey = posIdempotencyKey(req)\n if (!attemptKey) return res.status(400).json({ error: 'Missing Idempotency-Key' })\n if (!staff.orgId) return res.status(409).json({ error: 'This site has no workspace.' })\n const priced = pricePosHardwareCart(config, body['lines'])\n if ('error' in priced) return res.status(400).json({ error: priced.error })\n const method = body['shippingMethod']\n const shipping = isPosHardwareShippingMethod(method)\n ? config.shipping.find((option) => option.method === method)\n : undefined\n if (!shipping) return res.status(400).json({ error: 'Choose a shipping speed.' })\n\n const orderId = posHardwareOrderId(staff.orgId, staff.hostId, attemptKey)\n const billing = await readOrgBilling(staff.orgId).catch(() => ({}))\n const customer = String((billing as { stripeCustomerId?: unknown }).stripeCustomerId ?? '').trim()\n const base = await posSettingsUrl(staff.hostId)\n const params: Record<string, string | number | boolean> = {\n mode: 'payment',\n client_reference_id: orderId,\n success_url: withQueryAndHash(base, 'hardwareOrder=placed', POS_HARDWARE_ANCHOR),\n cancel_url: withQueryAndHash(base, 'hardwareOrder=canceled', POS_HARDWARE_ANCHOR),\n 'payment_method_types[0]': 'card',\n 'shipping_address_collection[allowed_countries][0]': POS_HARDWARE_SHIP_COUNTRIES[0],\n 'phone_number_collection[enabled]': true,\n 'shipping_options[0][shipping_rate_data][type]': 'fixed_amount',\n 'shipping_options[0][shipping_rate_data][display_name]': POS_HARDWARE_SHIPPING_LABELS[shipping.method],\n 'shipping_options[0][shipping_rate_data][fixed_amount][amount]': shipping.cents,\n 'shipping_options[0][shipping_rate_data][fixed_amount][currency]': POS_HARDWARE_CURRENCY,\n 'metadata[type]': POS_HARDWARE_METADATA_TYPE,\n 'metadata[orderId]': orderId,\n 'metadata[orgId]': staff.orgId,\n 'metadata[hostId]': staff.hostId,\n 'metadata[uid]': staff.uid,\n 'metadata[lines]': encodePosHardwareLines(priced.lines),\n 'metadata[shippingMethod]': shipping.method,\n 'metadata[shippingCents]': shipping.cents,\n 'metadata[subtotalCents]': priced.subtotalCents,\n 'payment_intent_data[description]': `Card reader order ${posHardwareOrderNumber(orderId)}`,\n 'payment_intent_data[metadata][type]': POS_HARDWARE_METADATA_TYPE,\n 'payment_intent_data[metadata][orderId]': orderId,\n 'payment_intent_data[metadata][orgId]': staff.orgId,\n ...(customer ? { customer } : {}),\n ...(config.automaticTax\n ? {\n 'automatic_tax[enabled]': true,\n 'shipping_options[0][shipping_rate_data][tax_behavior]': 'exclusive',\n // A returning workspace's saved address is kept up to date\n // from what Checkout collects, which automatic tax requires.\n ...(customer ? { 'customer_update[shipping]': 'auto' } : {}),\n }\n : {}),\n }\n priced.lines.forEach((line, index) => {\n const sku = posHardwareSku(line.sku)\n params[`line_items[${index}][quantity]`] = line.quantity\n // A literal, not POS_HARDWARE_CURRENCY: check:facilitator-charge-shape\n // reads Stripe Tax beside a usd line item only when it says so (AGL-1956).\n params[`line_items[${index}][price_data][currency]`] = 'usd'\n params[`line_items[${index}][price_data][unit_amount]`] = line.unitCents\n params[`line_items[${index}][price_data][product_data][name]`] = line.name\n if (sku) params[`line_items[${index}][price_data][product_data][description]`] = sku.use\n params[`line_items[${index}][price_data][product_data][metadata][sku]`] = line.sku\n if (config.automaticTax) params[`line_items[${index}][price_data][tax_behavior]`] = 'exclusive'\n })\n const created = await posStripe('POST', 'checkout/sessions', {\n params,\n idempotencyKey: `pos-hw-checkout-${orderId}`,\n })\n const url = String(created.body?.url ?? '')\n if (!created.ok || !url) {\n console.error('[pos-hardware] checkout refused', created.status, created.body?.error?.code)\n return res.status(502).json({ error: 'Checkout could not be started. Try again in a moment.' })\n }\n return res.status(200).json({ url, orderId })\n }\n default:\n return res.status(400).json({ error: 'Unknown action' })\n }\n } catch (error) {\n console.error('[pos-hardware]', action, error)\n return res.status(500).json({ error: 'The hardware shop could not answer' })\n }\n}\n"],"names":["createHash","firebaseAdmin","readOrgBilling","hostConsoleUrl","encodePosHardwareLines","isPosHardwareShippingMethod","POS_HARDWARE_ANCHOR","parsePosHardwareConfig","POS_HARDWARE_CURRENCY","POS_HARDWARE_METADATA_TYPE","POS_HARDWARE_ORDERS_COLLECTION","POS_HARDWARE_SALES_COLLECTION","POS_HARDWARE_SHIP_COUNTRIES","POS_HARDWARE_SHIPPING_LABELS","posHardwareOffers","posHardwareSku","pricePosHardwareCart","authorizePosStaff","posIdempotencyKey","posRequestBody","posStripe","posTerminalAvailable","posHardwareConfig","env","process","posHardwareOrderId","orgId","hostId","attemptKey","update","digest","slice","posHardwareOrderNumber","orderId","replace","toUpperCase","hardwareOrdersRef","app","firestore","collection","doc","posHardwareSaleRef","merchantHardwareOrderView","id","order","number","status","lines","map","line","sku","name","quantity","unitCents","lineCents","subtotalCents","shippingCents","shipping","cents","shippingLabel","label","taxCents","totalCents","tracking","createdAtMs","updatedAtMs","posSettingsUrl","withQueryAndHash","base","query","hash","path","split","joiner","includes","posHardwareHandler","req","res","body","method","json","error","String","gate","staff","config","action","available","offers","option","automaticTax","shipCountries","snapshot","where","orderBy","limit","get","orders","docs","data","created","priced","find","undefined","billing","catch","customer","stripeCustomerId","trim","params","mode","client_reference_id","success_url","cancel_url","uid","forEach","index","use","idempotencyKey","url","ok","console","code"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/pos-hardware.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 { createHash } from 'crypto'\nimport * as Aglyn from '@aglyn/aglyn/server'\nimport type { PluginApiHandler } from '@aglyn/aglyn/server'\nimport { firebaseAdmin, readOrgBilling } from '@aglyn/tenant-data-admin'\nimport { hostConsoleUrl } from '@aglyn/tenant-data-admin/server/host-console-link'\nimport {\n encodePosHardwareLines,\n isPosHardwareShippingMethod,\n POS_HARDWARE_ANCHOR,\n parsePosHardwareConfig,\n parsePosHardwareInPersonConfig,\n POS_HARDWARE_CURRENCY,\n POS_HARDWARE_METADATA_TYPE,\n POS_HARDWARE_ORDERS_COLLECTION,\n POS_HARDWARE_SALES_COLLECTION,\n POS_HARDWARE_SHIP_COUNTRIES,\n POS_HARDWARE_SHIPPING_LABELS,\n posHardwareOffers,\n posHardwareOrderSource,\n posHardwareSku,\n pricePosHardwareCart,\n type PosHardwareConfig,\n type PosHardwareInPersonConfig,\n type PosHardwareOrder,\n} from '../model/pos-hardware'\nimport { mayVisitPosHardwareShop } from '../model/plugin-permissions'\nimport { authorizePosStaff, posIdempotencyKey, posRequestBody } from './pos-auth'\nimport { posStripe, posTerminalAvailable } from './pos-stripe'\n\n/*==========================================\n * `POST /api/commerce/pos-hardware` (AGL-4038): the merchant's half of the\n * POS hardware shop, behind the Hardware card on Products → Point of sale.\n *\n * catalog what is on offer and at what price, or `available: false`\n * checkout a Stripe Checkout Session for the basket, on the PLATFORM\n * orders this site's hardware orders, newest first\n *\n * Gated like the register (`authorizePosStaff`, on a plan with POS), because\n * the readers it sells are the register's, with one difference (AGL-4047):\n * the shop admits whoever works the register (`managePos`) AND whoever may\n * buy hardware (`posBuyHardware`), which stands on its own — a bookkeeper\n * with no register orders the store's readers. A checkout needs\n * `posBuyHardware`; seeing the catalog and the site's orders needs either.\n *\n * THE SALE IS THE PLATFORM'S. The session is created with the platform key\n * and NO connected account, `transfer_data` or application fee: the merchant\n * is the buyer here, and the platform is the seller of record that places\n * the order with Stripe. The order document is written by the webhook once\n * Stripe says the session is paid (`pos-hardware-webhook.ts`), never here.\n *=========================================*/\n\n/** The shop's config from this deployment, or `null` while it is hidden. */\nexport function posHardwareConfig(\n env: Record<string, string | undefined> = process.env,\n): PosHardwareConfig | null {\n // A reader the platform cannot yet take payments on is not for sale: the\n // shop opens only where the register offers card readers at all.\n if (!posTerminalAvailable()) return null\n return parsePosHardwareConfig(env)\n}\n\n/**\n * The platform's own store that sells hardware in person (AGL-4038), or\n * `null` while that is off. Read like the shop's other figures; a store is\n * the seller only when BOTH its id and its workspace's match, so a site moved\n * to another workspace stops selling hardware rather than selling it for them.\n */\nexport function posHardwareInPersonConfig(\n env: Record<string, string | undefined> = process.env,\n): PosHardwareInPersonConfig | null {\n return parsePosHardwareInPersonConfig(env)\n}\n\n/** Whether a store, owned by `orgId`, is the platform's own hardware seller. */\nexport function isPosHardwareSellerStore(\n config: PosHardwareInPersonConfig | null,\n hostId: string,\n orgId: string,\n): config is PosHardwareInPersonConfig {\n return Boolean(config) && config?.sellerHostId === hostId && config?.sellerOrgId === orgId\n}\n\n/**\n * An in-person order's id, from the register sale it came from: one register\n * sale is one hardware order however often its completion is told.\n */\nexport function posHardwareInPersonOrderId(hostId: string, registerOrderId: string): string {\n return `hw_${createHash('sha256').update(`pos:${hostId}:${registerOrderId}`).digest('hex').slice(0, 20)}`\n}\n\n/** The order's id, derived from the attempt so a repeated press is one order. */\nexport function posHardwareOrderId(orgId: string, hostId: string, attemptKey: string): string {\n return `hw_${createHash('sha256').update(`${orgId}:${hostId}:${attemptKey}`).digest('hex').slice(0, 20)}`\n}\n\n/** The number a person reads: `HW-` and six characters of the id. */\nexport function posHardwareOrderNumber(orderId: string): string {\n return `HW-${orderId.replace(/^hw_/, '').slice(0, 6).toUpperCase()}`\n}\n\nexport function hardwareOrdersRef(orgId: string) {\n return firebaseAdmin\n .app()\n .firestore()\n .collection('orgs')\n .doc(orgId)\n .collection(POS_HARDWARE_ORDERS_COLLECTION)\n}\n\n/**\n * `posHardwareSales/{orderId}`, the retained sale record beside each order\n * (see `PosHardwareSaleRecord`). Top-level on purpose: the workspace erasure\n * cannot reach it.\n */\nexport function posHardwareSaleRef(orderId: string) {\n return firebaseAdmin.app().firestore().collection(POS_HARDWARE_SALES_COLLECTION).doc(orderId)\n}\n\n/** An order as the merchant's card shows it: no Stripe ids, no staff notes. */\nexport function merchantHardwareOrderView(id: string, order: PosHardwareOrder) {\n return {\n id,\n number: posHardwareOrderNumber(id),\n status: order.status,\n lines: (order.lines ?? []).map((line) => ({\n sku: line.sku,\n name: line.name,\n quantity: line.quantity,\n unitCents: line.unitCents,\n lineCents: line.lineCents,\n })),\n subtotalCents: order.subtotalCents ?? 0,\n shippingCents: order.shipping?.cents ?? 0,\n shippingLabel: order.shipping?.label ?? '',\n taxCents: order.taxCents ?? 0,\n totalCents: order.totalCents ?? 0,\n tracking: order.tracking ?? null,\n createdAtMs: order.createdAtMs ?? 0,\n updatedAtMs: order.updatedAtMs ?? order.createdAtMs ?? 0,\n // Bought in person (AGL-4038): handed over at the sale, no parcel.\n source: posHardwareOrderSource(order),\n discountCents: order.discountCents ?? 0,\n /** Readers still to set up, for an in-person order that took serials. */\n readersToSetUp: (order.units ?? []).filter((unit) => !unit.readerId).length,\n refundedCents: order.refundedCents ?? 0,\n /** The buyer's return request and what was decided, without who asked. */\n returnRequest: order.returnRequest\n ? { state: order.returnRequest.state, requestedAtMs: order.returnRequest.requestedAtMs, note: order.returnRequest.note }\n : null,\n }\n}\n\nexport type MerchantHardwareOrderView = ReturnType<typeof merchantHardwareOrderView>\n\n/** The POS settings page of a site, as an absolute console URL. */\nexport async function posSettingsUrl(hostId: string): Promise<string> {\n return hostConsoleUrl(hostId, `/${hostId}/products/pos`)\n}\n\n/** `base` with `query` added before any `#fragment`, then `#hash`. */\nexport function withQueryAndHash(base: string, query: string, hash: string): string {\n const [path] = base.split('#')\n const joiner = path.includes('?') ? '&' : '?'\n return `${path}${joiner}${query}#${hash}`\n}\n\n\n/**\n * The readers this workspace bought in person that are not set up yet\n * (AGL-4038): whether its plan includes the point of sale, its stores and\n * whether each can take a reader, and each order with what it waits for.\n * Nothing at all while the in-person sale is off.\n */\nexport async function waitingInPersonReaders(orgId: string, hostId: string) {\n if (!posHardwareInPersonConfig() || !orgId) return { posPlan: false, stores: [], orders: [] }\n const firestore = firebaseAdmin.app().firestore()\n const [orders, org, hosts] = await Promise.all([\n hardwareOrdersRef(orgId)\n .where('attachment.state', '==', 'attached')\n .where('status', '==', 'delivered')\n .limit(20)\n .get(),\n firestore.collection('orgs').doc(orgId).get(),\n firestore.collection('hosts').where('orgId', '==', orgId).limit(20).get(),\n ])\n if (!orders.docs.length) return { posPlan: false, stores: [], orders: [] }\n const stores = await Promise.all(\n hosts.docs.map(async (doc: any) => {\n const id = String(doc.id)\n const [terminal, setupUrl] = await Promise.all([\n firestore.collection('hosts').doc(id).collection('terminal').doc('config').get(),\n posSettingsUrl(id),\n ])\n return {\n hostId: id,\n name: String(doc.get('name') ?? doc.get('title') ?? id),\n hasLocation: Boolean(terminal.exists && terminal.get('stripeLocationId')),\n setupUrl: `${setupUrl.split('#')[0]}#pos-devices`,\n }\n }),\n )\n return {\n posPlan: Aglyn.checkEntitlement(org.data() as never, 'pos'),\n stores,\n // Every store's, this store's first: a reader waits wherever the\n // workspace's people look.\n orders: orders.docs\n .map((doc: any) => ({ id: String(doc.id), order: doc.data() as PosHardwareOrder }))\n .filter(({ order }) => order.source === 'in_person')\n .sort((a, b) => Number(b.order.hostId === hostId) - Number(a.order.hostId === hostId))\n .map(({ id, order }) => ({\n ...merchantHardwareOrderView(id, order),\n hostId: order.hostId,\n serialsTaken: (order.units ?? []).filter((unit) => unit.serialNumber && !unit.readerId).length,\n })),\n }\n}\n\nexport const posHardwareHandler: PluginApiHandler = async (req, res) => {\n if (req.method !== 'POST') return res.status(405).json({ error: 'Method not allowed' })\n const body = posRequestBody(req)\n const hostId = String(body['hostId'] ?? '')\n const action = String(body['action'] ?? '')\n // BUYING IS ITS OWN KEY (AGL-4047): anyone who works the register or may\n // buy hardware sees what the shop offers and what this site ordered, and\n // only a member holding \"Buy point of sale hardware\" — which follows\n // `managePos` until a role or the member sets it, and may be granted\n // without it — starts a checkout that the workspace pays for.\n //\n // A READER BOUGHT IN PERSON (AGL-4038): `waiting` is read without the\n // point of sale plan, because a workspace without it is exactly the one\n // that must be told to add it first; choosing its store and marking it set\n // up are setting up devices (`posDevices`) on the store named.\n const settingUp = action === 'choose-store' || action === 'mark-set-up'\n const gate = await authorizePosStaff(\n req,\n hostId,\n action === 'checkout' ? 'posBuyHardware' : settingUp ? 'posDevices' : undefined,\n mayVisitPosHardwareShop,\n // A workspace whose plan lost the point of sale still sees what it bought\n // and may ask to return a reader bought in person.\n action === 'waiting' || action === 'orders' || action === 'request-return' ? { planRequired: false } : {},\n )\n if ('error' in gate) return res.status(gate.status).json({ error: gate.error })\n const staff = gate.staff\n const config = posHardwareConfig()\n try {\n switch (action) {\n case 'waiting':\n return res.status(200).json(await waitingInPersonReaders(staff.orgId, staff.hostId))\n case 'request-return': {\n const returns = await import('./pos-hardware-returns')\n const orderId = String(body['orderId'] ?? '')\n try {\n const order = await returns.requestPosHardwareReturn({\n orgId: staff.orgId,\n orderId,\n uid: staff.uid,\n reason: body['reason'],\n })\n return res.status(200).json({ ok: true, order: merchantHardwareOrderView(orderId, order) })\n } catch (error) {\n if (error instanceof returns.PosHardwareReturnRefusal) {\n return res.status(error.status).json({ error: error.message })\n }\n throw error\n }\n }\n case 'choose-store':\n case 'mark-set-up': {\n const readers = await import('./pos-hardware-readers')\n const orderId = String(body['orderId'] ?? '')\n try {\n const order =\n action === 'choose-store'\n ? await readers.choosePosHardwareStore({ orgId: staff.orgId, orderId, hostId: staff.hostId })\n : await readers.markPosHardwareSetUp({ orgId: staff.orgId, orderId })\n return res.status(200).json({ ok: true, order: merchantHardwareOrderView(orderId, order) })\n } catch (error) {\n if (error instanceof readers.PosHardwareReaderRefusal) {\n return res.status(error.status).json({ error: error.message })\n }\n throw error\n }\n }\n case 'catalog':\n if (!config) return res.status(200).json({ available: false })\n return res.status(200).json({\n available: true,\n offers: posHardwareOffers(config),\n shipping: config.shipping.map((option) => ({\n method: option.method,\n label: POS_HARDWARE_SHIPPING_LABELS[option.method],\n cents: option.cents,\n })),\n automaticTax: config.automaticTax,\n shipCountries: POS_HARDWARE_SHIP_COUNTRIES,\n })\n case 'orders': {\n // This site's orders, and the readers bought in person for the\n // workspace that wait for a store to be chosen at setup (AGL-4038).\n // A sale on the selling workspace's own To attach list is never one.\n const [site, workspace] = await Promise.all([\n hardwareOrdersRef(staff.orgId).where('hostId', '==', staff.hostId).orderBy('createdAtMs', 'desc').limit(50).get(),\n hardwareOrdersRef(staff.orgId)\n .where('hostId', '==', '')\n .where('attachment.state', '==', 'attached')\n .orderBy('createdAtMs', 'desc')\n .limit(50)\n .get(),\n ])\n const orders = [...site.docs, ...workspace.docs]\n .map((doc: any) => merchantHardwareOrderView(String(doc.id), doc.data() as PosHardwareOrder))\n .sort((a, b) => b.createdAtMs - a.createdAtMs)\n .slice(0, 50)\n return res.status(200).json({ orders })\n }\n case 'checkout': {\n if (!config) return res.status(404).json({ error: 'The hardware shop is not available.' })\n const attemptKey = posIdempotencyKey(req)\n if (!attemptKey) return res.status(400).json({ error: 'Missing Idempotency-Key' })\n if (!staff.orgId) return res.status(409).json({ error: 'This site has no workspace.' })\n const priced = pricePosHardwareCart(config, body['lines'])\n if ('error' in priced) return res.status(400).json({ error: priced.error })\n const method = body['shippingMethod']\n const shipping = isPosHardwareShippingMethod(method)\n ? config.shipping.find((option) => option.method === method)\n : undefined\n if (!shipping) return res.status(400).json({ error: 'Choose a shipping speed.' })\n\n const orderId = posHardwareOrderId(staff.orgId, staff.hostId, attemptKey)\n const billing = await readOrgBilling(staff.orgId).catch(() => ({}))\n const customer = String((billing as { stripeCustomerId?: unknown }).stripeCustomerId ?? '').trim()\n const base = await posSettingsUrl(staff.hostId)\n const params: Record<string, string | number | boolean> = {\n mode: 'payment',\n client_reference_id: orderId,\n success_url: withQueryAndHash(base, 'hardwareOrder=placed', POS_HARDWARE_ANCHOR),\n cancel_url: withQueryAndHash(base, 'hardwareOrder=canceled', POS_HARDWARE_ANCHOR),\n 'payment_method_types[0]': 'card',\n 'shipping_address_collection[allowed_countries][0]': POS_HARDWARE_SHIP_COUNTRIES[0],\n 'phone_number_collection[enabled]': true,\n 'shipping_options[0][shipping_rate_data][type]': 'fixed_amount',\n 'shipping_options[0][shipping_rate_data][display_name]': POS_HARDWARE_SHIPPING_LABELS[shipping.method],\n 'shipping_options[0][shipping_rate_data][fixed_amount][amount]': shipping.cents,\n 'shipping_options[0][shipping_rate_data][fixed_amount][currency]': POS_HARDWARE_CURRENCY,\n 'metadata[type]': POS_HARDWARE_METADATA_TYPE,\n 'metadata[orderId]': orderId,\n 'metadata[orgId]': staff.orgId,\n 'metadata[hostId]': staff.hostId,\n 'metadata[uid]': staff.uid,\n 'metadata[lines]': encodePosHardwareLines(priced.lines),\n 'metadata[shippingMethod]': shipping.method,\n 'metadata[shippingCents]': shipping.cents,\n 'metadata[subtotalCents]': priced.subtotalCents,\n 'payment_intent_data[description]': `Card reader order ${posHardwareOrderNumber(orderId)}`,\n 'payment_intent_data[metadata][type]': POS_HARDWARE_METADATA_TYPE,\n 'payment_intent_data[metadata][orderId]': orderId,\n 'payment_intent_data[metadata][orgId]': staff.orgId,\n ...(customer ? { customer } : {}),\n ...(config.automaticTax\n ? {\n 'automatic_tax[enabled]': true,\n 'shipping_options[0][shipping_rate_data][tax_behavior]': 'exclusive',\n // A returning workspace's saved address is kept up to date\n // from what Checkout collects, which automatic tax requires.\n ...(customer ? { 'customer_update[shipping]': 'auto' } : {}),\n }\n : {}),\n }\n priced.lines.forEach((line, index) => {\n const sku = posHardwareSku(line.sku)\n params[`line_items[${index}][quantity]`] = line.quantity\n // A literal, not POS_HARDWARE_CURRENCY: check:facilitator-charge-shape\n // reads Stripe Tax beside a usd line item only when it says so (AGL-1956).\n params[`line_items[${index}][price_data][currency]`] = 'usd'\n params[`line_items[${index}][price_data][unit_amount]`] = line.unitCents\n params[`line_items[${index}][price_data][product_data][name]`] = line.name\n if (sku) params[`line_items[${index}][price_data][product_data][description]`] = sku.use\n params[`line_items[${index}][price_data][product_data][metadata][sku]`] = line.sku\n if (config.automaticTax) params[`line_items[${index}][price_data][tax_behavior]`] = 'exclusive'\n })\n const created = await posStripe('POST', 'checkout/sessions', {\n params,\n idempotencyKey: `pos-hw-checkout-${orderId}`,\n })\n const url = String(created.body?.url ?? '')\n if (!created.ok || !url) {\n console.error('[pos-hardware] checkout refused', created.status, created.body?.error?.code)\n return res.status(502).json({ error: 'Checkout could not be started. Try again in a moment.' })\n }\n return res.status(200).json({ url, orderId })\n }\n default:\n return res.status(400).json({ error: 'Unknown action' })\n }\n } catch (error) {\n console.error('[pos-hardware]', action, error)\n return res.status(500).json({ error: 'The hardware shop could not answer' })\n }\n}\n"],"names":["createHash","Aglyn","firebaseAdmin","readOrgBilling","hostConsoleUrl","encodePosHardwareLines","isPosHardwareShippingMethod","POS_HARDWARE_ANCHOR","parsePosHardwareConfig","parsePosHardwareInPersonConfig","POS_HARDWARE_CURRENCY","POS_HARDWARE_METADATA_TYPE","POS_HARDWARE_ORDERS_COLLECTION","POS_HARDWARE_SALES_COLLECTION","POS_HARDWARE_SHIP_COUNTRIES","POS_HARDWARE_SHIPPING_LABELS","posHardwareOffers","posHardwareOrderSource","posHardwareSku","pricePosHardwareCart","mayVisitPosHardwareShop","authorizePosStaff","posIdempotencyKey","posRequestBody","posStripe","posTerminalAvailable","posHardwareConfig","env","process","posHardwareInPersonConfig","isPosHardwareSellerStore","config","hostId","orgId","Boolean","sellerHostId","sellerOrgId","posHardwareInPersonOrderId","registerOrderId","update","digest","slice","posHardwareOrderId","attemptKey","posHardwareOrderNumber","orderId","replace","toUpperCase","hardwareOrdersRef","app","firestore","collection","doc","posHardwareSaleRef","merchantHardwareOrderView","id","order","number","status","lines","map","line","sku","name","quantity","unitCents","lineCents","subtotalCents","shippingCents","shipping","cents","shippingLabel","label","taxCents","totalCents","tracking","createdAtMs","updatedAtMs","source","discountCents","readersToSetUp","units","filter","unit","readerId","length","refundedCents","returnRequest","state","requestedAtMs","note","posSettingsUrl","withQueryAndHash","base","query","hash","path","split","joiner","includes","waitingInPersonReaders","posPlan","stores","orders","org","hosts","Promise","all","where","limit","get","docs","String","terminal","setupUrl","hasLocation","exists","checkEntitlement","data","sort","a","b","Number","serialsTaken","serialNumber","posHardwareHandler","req","res","body","method","json","error","action","settingUp","gate","undefined","planRequired","staff","returns","requestPosHardwareReturn","uid","reason","ok","PosHardwareReturnRefusal","message","readers","choosePosHardwareStore","markPosHardwareSetUp","PosHardwareReaderRefusal","available","offers","option","automaticTax","shipCountries","site","workspace","orderBy","created","priced","find","billing","catch","customer","stripeCustomerId","trim","params","mode","client_reference_id","success_url","cancel_url","forEach","index","use","idempotencyKey","url","console","code"],"mappings":"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"}
|
|
@@ -30,6 +30,8 @@ export declare function posKioskDeviceId(device: PosDeviceToken): string;
|
|
|
30
30
|
* product, a gift card whose code needs issuing, and a digital download.
|
|
31
31
|
*/
|
|
32
32
|
export declare function posKioskSellable(product: CommerceModel.HostProduct): boolean;
|
|
33
|
+
/** A variant the kiosk may sell: priced, and offered by the merchant's choice (AGL-4038). */
|
|
34
|
+
export declare function posKioskVariantOffered(product: CommerceModel.HostProduct, variant: CommerceModel.ProductVariant): boolean;
|
|
33
35
|
/** A product as the kiosk may show it: names, prices and choices, nothing else. */
|
|
34
36
|
export declare function posKioskProduct(id: string, product: CommerceModel.HostProduct, hostId: string): CommerceModel.PosKioskProduct;
|
|
35
37
|
/** An order as its kiosk reads it back; null for any order this kiosk did not open. */
|
|
@@ -21,6 +21,7 @@ import { pluginSmsAvailable } from "@aglyn/aglyn/plugin-manager/plugin-sms-messa
|
|
|
21
21
|
import { consumeRateLimit, firebaseAdmin, getLockdownVerdict, getOrgForHost, getPluginConfig } from "@aglyn/tenant-data-admin";
|
|
22
22
|
import { resolveOrgPermissions } from "@aglyn/tenant-runtime/org-permissions";
|
|
23
23
|
import * as CommerceModel from "../model/index.js";
|
|
24
|
+
import { productOfferedOnKiosk } from "../model/commerce-kiosk-offer.js";
|
|
24
25
|
import { posRegisterSettings } from "../plugin-config.js";
|
|
25
26
|
import { posKioskSettings } from "../pos-kiosk-config.js";
|
|
26
27
|
import { verifyMemberPassword } from "./membership.js";
|
|
@@ -54,7 +55,7 @@ function refuse(status, error) {
|
|
|
54
55
|
};
|
|
55
56
|
}
|
|
56
57
|
/** The kiosk's gate, asked again on every call. */ async function authorizeKiosk(req, body, write) {
|
|
57
|
-
var
|
|
58
|
+
var _ref, _ref1, _ref2, _register_data;
|
|
58
59
|
var _membership_permissions, _owner_org;
|
|
59
60
|
const device = await resolveDisplayToken(displayToken(req, body));
|
|
60
61
|
if (!device) return refuse(401, 'This kiosk is not paired.');
|
|
@@ -66,11 +67,12 @@ function refuse(status, error) {
|
|
|
66
67
|
hostRef.collection('registers').doc(device.registerId).get()
|
|
67
68
|
]);
|
|
68
69
|
if (!host.exists || !register.exists) return refuse(401, 'This kiosk is not paired.');
|
|
69
|
-
|
|
70
|
+
// The member who paired it must still work the register here: the key
|
|
71
|
+
// decides, not the site role (AGL-4047).
|
|
70
72
|
const membership = device.createdBy ? await resolveOrgPermissions(device.createdBy, {
|
|
71
73
|
hostId: device.hostId
|
|
72
74
|
}) : null;
|
|
73
|
-
if (
|
|
75
|
+
if (!(membership == null ? void 0 : (_membership_permissions = membership.permissions) == null ? void 0 : _membership_permissions.managePos)) {
|
|
74
76
|
return refuse(403, 'This kiosk needs a staff member to pair it again.');
|
|
75
77
|
}
|
|
76
78
|
const owner = await getOrgForHost(device.hostId);
|
|
@@ -183,10 +185,16 @@ async function context(gate) {
|
|
|
183
185
|
*/ export function posKioskSellable(product) {
|
|
184
186
|
var _product_variants;
|
|
185
187
|
if (product.status !== 'active') return false;
|
|
188
|
+
// The merchant's own choice of what the kiosk offers (AGL-4038), for any
|
|
189
|
+
// product: "Offer on the kiosk" in the product editor.
|
|
190
|
+
if (!productOfferedOnKiosk(product)) return false;
|
|
186
191
|
if (product.subscription && !product.subscriptionOptional) return false;
|
|
187
192
|
if (product.giftCard) return false;
|
|
188
193
|
if (product.type === 'digital') return false;
|
|
189
|
-
return ((_product_variants = product.variants) != null ? _product_variants : []).some((variant)=>
|
|
194
|
+
return ((_product_variants = product.variants) != null ? _product_variants : []).some((variant)=>posKioskVariantOffered(product, variant));
|
|
195
|
+
}
|
|
196
|
+
/** A variant the kiosk may sell: priced, and offered by the merchant's choice (AGL-4038). */ export function posKioskVariantOffered(product, variant) {
|
|
197
|
+
return CommerceModel.variantHasPrice(variant) && productOfferedOnKiosk(product, variant.id);
|
|
190
198
|
}
|
|
191
199
|
/** A product as the kiosk may show it: names, prices and choices, nothing else. */ export function posKioskProduct(id, product, hostId) {
|
|
192
200
|
var _product_description, _product_name, _product_categoryIds, _product_options, _product_variants;
|
|
@@ -210,7 +218,7 @@ async function context(gate) {
|
|
|
210
218
|
...option.values
|
|
211
219
|
]
|
|
212
220
|
})),
|
|
213
|
-
variants: ((_product_variants = product.variants) != null ? _product_variants : []).filter((variant)=>
|
|
221
|
+
variants: ((_product_variants = product.variants) != null ? _product_variants : []).filter((variant)=>posKioskVariantOffered(product, variant)).map((variant)=>{
|
|
214
222
|
var _variant_options;
|
|
215
223
|
return {
|
|
216
224
|
id: variant.id,
|
|
@@ -349,7 +357,7 @@ async function checkout(gate, req, body) {
|
|
|
349
357
|
return refuse(409, 'An item in your cart is no longer available. Remove it and try again.');
|
|
350
358
|
}
|
|
351
359
|
const variant = line.variantId ? product.variants.find((candidate)=>candidate.id === line.variantId) : product.variants[0];
|
|
352
|
-
if (!variant || !
|
|
360
|
+
if (!variant || !posKioskVariantOffered(product, variant)) {
|
|
353
361
|
return refuse(409, `${product.name} is no longer available. Remove it and try again.`);
|
|
354
362
|
}
|
|
355
363
|
const wanted = cart.lines.filter((other)=>{
|
|
@@ -662,12 +670,8 @@ function signUnlock(payload) {
|
|
|
662
670
|
return null;
|
|
663
671
|
}
|
|
664
672
|
}
|
|
665
|
-
/** Whether a member may still unlock:
|
|
666
|
-
var _host_get;
|
|
673
|
+
/** Whether a member may still unlock: `managePos` here today, whatever their site role (AGL-4047). */ async function mayUnlock(gate, memberUid) {
|
|
667
674
|
var _membership_permissions;
|
|
668
|
-
const host = await gate.hostRef.get();
|
|
669
|
-
const role = ((_host_get = host.get('memberRoles')) != null ? _host_get : {})[memberUid];
|
|
670
|
-
if (role !== 'admin' && role !== 'editor') return false;
|
|
671
675
|
const membership = await resolveOrgPermissions(memberUid, {
|
|
672
676
|
hostId: gate.hostId
|
|
673
677
|
});
|
|
@@ -733,6 +737,7 @@ async function unlock(gate, req, body) {
|
|
|
733
737
|
}
|
|
734
738
|
};
|
|
735
739
|
}
|
|
740
|
+
// Members of this site only, any role: `mayUnlock` below asks the key.
|
|
736
741
|
const host = await gate.hostRef.get();
|
|
737
742
|
const roles = (_host_get = host.get('memberRoles')) != null ? _host_get : {};
|
|
738
743
|
const pins = await gate.hostRef.collection('posStaffPins').limit(50).get();
|
|
@@ -740,7 +745,7 @@ async function unlock(gate, req, body) {
|
|
|
740
745
|
for (const doc of pins.docs){
|
|
741
746
|
var _doc_get, _doc_get1;
|
|
742
747
|
const uid = String(doc.id);
|
|
743
|
-
if (roles[uid]
|
|
748
|
+
if (!roles[uid]) continue;
|
|
744
749
|
if (Number((_doc_get = doc.get('lockedUntilMs')) != null ? _doc_get : 0) > now) continue;
|
|
745
750
|
const hash = String((_doc_get1 = doc.get('pinScrypt')) != null ? _doc_get1 : '');
|
|
746
751
|
if (hash && verifyMemberPassword(pin, hash)) {
|