@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
|
@@ -0,0 +1,285 @@
|
|
|
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 { resolveSiteTimeZone } from "@aglyn/aglyn/app-utils/collection-entry-date";
|
|
18
|
+
import { isHostPluginEnabled } from "@aglyn/aglyn/server";
|
|
19
|
+
import { zonedDayKey } from "@aglyn/shared-util-timestamp/zoned-time";
|
|
20
|
+
import { logHostActivity } from "@aglyn/tenant-data-admin";
|
|
21
|
+
import { BUNDLE_ID } from "../constants/bundle-common.js";
|
|
22
|
+
import { changedCheckInCustomerFields, checkInDayLabel, dueCheckInsForReservation, newCheckInDocument, reservationCheckInId, STAY_CHECK_IN_SETTINGS_DOC, stayCheckInPlan, storedStayCheckIns } from "../model/commerce-check-in.js";
|
|
23
|
+
import { readStayCheckInMode, reservationGuests, reservationGuestsProblem, stayChecksInPerGuest } from "../model/commerce-reservations.js";
|
|
24
|
+
import { reservationsOnPlan } from "./reservation-availability-query.js";
|
|
25
|
+
import { bodyOf, gate, resolved, validId } from "./products-write.js";
|
|
26
|
+
import { WALK_IN_PERMISSION, WALK_IN_PLAN_REFUSAL, WALK_IN_PLUGIN_OFF } from "./reservation-walk-in.js";
|
|
27
|
+
/*
|
|
28
|
+
* `POST /api/commerce/reservations/guests` (AGL-4043): staff change how many
|
|
29
|
+
* guests a stay is for after it is booked — a family arrives with one more,
|
|
30
|
+
* or one fewer.
|
|
31
|
+
*
|
|
32
|
+
* Body: { hostId, reservationId, guests }
|
|
33
|
+
*
|
|
34
|
+
* `guests` is a whole number from 1 up to what the resource sleeps
|
|
35
|
+
* (`resourceGuestCeiling`). Who may ask is who may book a walk-in: the same
|
|
36
|
+
* gate (`products-write.ts`'s), asking "Book walk-ins and change guests"
|
|
37
|
+
* (`commerce.walkIns`, AGL-4047) on the site, or staff, while nothing is
|
|
38
|
+
* frozen; the commerce plugin on for the site; and the store's plan taking
|
|
39
|
+
* reservations. A stay that is pending, confirmed or
|
|
40
|
+
* checked in can change; one cancelled, a no-show or checked out cannot.
|
|
41
|
+
*
|
|
42
|
+
* WHEN THE STAY IS CHECKED IN ONE GUEST AT A TIME, its check-ins follow in
|
|
43
|
+
* the same transaction, on today and every later day that already has them
|
|
44
|
+
* (`stayCheckInPlan`): added guests get new waiting check-ins; removed guests
|
|
45
|
+
* take away only waiting ones, never one already checked in. A count below
|
|
46
|
+
* how many are checked in on one of those days is refused, and nothing is
|
|
47
|
+
* written. A day with no check-ins yet is left to its own reconcile, which
|
|
48
|
+
* reads the new count.
|
|
49
|
+
*
|
|
50
|
+
* Every change stamps who made it and when on the stay, and writes a line to
|
|
51
|
+
* the site's activity log. Asking for the count the stay already has answers
|
|
52
|
+
* `unchanged` and writes nothing, so a retried tap is harmless.
|
|
53
|
+
*/ export const RESERVATION_GUESTS_GONE = 'That stay is gone.';
|
|
54
|
+
export const RESERVATION_GUESTS_CLOSED = 'Guests can change only on a stay that is booked or checked in';
|
|
55
|
+
/** A member who does not hold the key a guests change asks: the walk-in's refusal, naming it. */ export const RESERVATION_GUESTS_PERMISSION_REFUSAL = WALK_IN_PERMISSION.refusal;
|
|
56
|
+
/** The most check-ins of one stay, from today on, the route reads in its transaction. */ export const RESERVATION_GUESTS_CHECK_IN_ROWS = 500;
|
|
57
|
+
/** The statuses whose guests can change. */ const OPEN_STATUSES = [
|
|
58
|
+
'pending',
|
|
59
|
+
'confirmed',
|
|
60
|
+
'checked_in'
|
|
61
|
+
];
|
|
62
|
+
/** The refusal for a count below how many are already checked in on a day. */ export function guestsBelowCheckedInMessage(checkedIn, dayKey, todayKey) {
|
|
63
|
+
const when = dayKey === todayKey ? 'today' : `on ${checkInDayLabel(dayKey)}`;
|
|
64
|
+
return `${checkedIn} of this stay’s guests are already checked in ${when}. Undo a check-in first, or keep ${checkedIn} or more.`;
|
|
65
|
+
}
|
|
66
|
+
export function createReservationGuestsHandler(options = {}) {
|
|
67
|
+
return async (req, res)=>{
|
|
68
|
+
var _options_logActivity;
|
|
69
|
+
if (req.method !== 'POST') {
|
|
70
|
+
return res.status(405).json({
|
|
71
|
+
error: 'Method not allowed'
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
const deps = resolved(options);
|
|
75
|
+
const logActivity = (_options_logActivity = options.logActivity) != null ? _options_logActivity : logHostActivity;
|
|
76
|
+
const body = bodyOf(req);
|
|
77
|
+
const hostId = body['hostId'];
|
|
78
|
+
const reservationId = body['reservationId'];
|
|
79
|
+
const rawGuests = body['guests'];
|
|
80
|
+
const guests = typeof rawGuests === 'number' || typeof rawGuests === 'string' ? Number(rawGuests) : NaN;
|
|
81
|
+
if (!validId(hostId) || !validId(reservationId) || rawGuests === undefined || rawGuests === null || rawGuests === '') {
|
|
82
|
+
return res.status(400).json({
|
|
83
|
+
error: 'Missing guest details'
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
var _door_host_data;
|
|
88
|
+
const door = await gate(req, res, hostId, deps, {
|
|
89
|
+
permission: WALK_IN_PERMISSION
|
|
90
|
+
});
|
|
91
|
+
if (!door) return;
|
|
92
|
+
if (!isHostPluginEnabled(door.org, door.host.data(), BUNDLE_ID)) {
|
|
93
|
+
return res.status(403).json({
|
|
94
|
+
error: WALK_IN_PLUGIN_OFF
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
if (!reservationsOnPlan(door.org)) {
|
|
98
|
+
return res.status(403).json({
|
|
99
|
+
error: WALK_IN_PLAN_REFUSAL
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
const db = deps.firestore();
|
|
103
|
+
const hostRef = db.collection('hosts').doc(hostId);
|
|
104
|
+
const reservationRef = hostRef.collection('reservations').doc(reservationId);
|
|
105
|
+
const checkIns = hostRef.collection('checkIns');
|
|
106
|
+
// Today on the store's calendar: earlier days are history, and stay
|
|
107
|
+
// as they were checked in.
|
|
108
|
+
const timeZone = resolveSiteTimeZone(door.org, (_door_host_data = door.host.data()) != null ? _door_host_data : null);
|
|
109
|
+
const todayKey = zonedDayKey(deps.now(), timeZone);
|
|
110
|
+
const outcome = await db.runTransaction(async (transaction)=>{
|
|
111
|
+
var _reservation_resourceId, _ref;
|
|
112
|
+
const stay = await transaction.get(reservationRef);
|
|
113
|
+
if (!stay.exists) return {
|
|
114
|
+
status: 404,
|
|
115
|
+
body: {
|
|
116
|
+
error: RESERVATION_GUESTS_GONE
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
const reservation = stay.data();
|
|
120
|
+
if (!OPEN_STATUSES.includes(reservation.status)) {
|
|
121
|
+
return {
|
|
122
|
+
status: 409,
|
|
123
|
+
body: {
|
|
124
|
+
error: RESERVATION_GUESTS_CLOSED
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
const resourceId = String((_reservation_resourceId = reservation.resourceId) != null ? _reservation_resourceId : '');
|
|
129
|
+
const [resourceSnapshot, settings, stored] = await Promise.all([
|
|
130
|
+
validId(resourceId) ? transaction.get(hostRef.collection('resources').doc(resourceId)) : null,
|
|
131
|
+
transaction.get(hostRef.collection('settings').doc(STAY_CHECK_IN_SETTINGS_DOC)),
|
|
132
|
+
transaction.get(checkIns.where('reservationId', '==', reservationId).where('dayKey', '>=', todayKey).limit(RESERVATION_GUESTS_CHECK_IN_ROWS))
|
|
133
|
+
]);
|
|
134
|
+
const resource = (resourceSnapshot == null ? void 0 : resourceSnapshot.exists) ? resourceSnapshot.data() : null;
|
|
135
|
+
const problem = reservationGuestsProblem(guests, resource);
|
|
136
|
+
if (problem) return {
|
|
137
|
+
status: 400,
|
|
138
|
+
body: {
|
|
139
|
+
error: problem
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
const previousGuests = reservationGuests(reservation);
|
|
143
|
+
if (previousGuests === guests) {
|
|
144
|
+
return {
|
|
145
|
+
status: 200,
|
|
146
|
+
body: {
|
|
147
|
+
reservationId,
|
|
148
|
+
guests,
|
|
149
|
+
previousGuests,
|
|
150
|
+
unchanged: true
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
// How the stay is checked in: the store's control, else the
|
|
155
|
+
// resource's own setting; a resource gone since, once per stay.
|
|
156
|
+
const mode = readStayCheckInMode(settings.exists ? settings.get('stays') : undefined);
|
|
157
|
+
const perGuest = resource ? stayChecksInPerGuest(resource, mode) : mode === 'guest';
|
|
158
|
+
const changed = _extends({}, reservation, {
|
|
159
|
+
guests
|
|
160
|
+
});
|
|
161
|
+
const nowMs = deps.now();
|
|
162
|
+
const byDay = new Map();
|
|
163
|
+
for (const doc of stored.docs){
|
|
164
|
+
var _doc_get, _byDay_get;
|
|
165
|
+
const dayKey = String((_doc_get = doc.get('dayKey')) != null ? _doc_get : '');
|
|
166
|
+
if (dayKey < todayKey) continue;
|
|
167
|
+
byDay.set(dayKey, [
|
|
168
|
+
...(_byDay_get = byDay.get(dayKey)) != null ? _byDay_get : [],
|
|
169
|
+
doc
|
|
170
|
+
]);
|
|
171
|
+
}
|
|
172
|
+
const creates = [];
|
|
173
|
+
const drops = [];
|
|
174
|
+
const patches = [];
|
|
175
|
+
for (const dayKey of [
|
|
176
|
+
...byDay.keys()
|
|
177
|
+
].sort()){
|
|
178
|
+
var _storedStayCheckIns_get, _ref1;
|
|
179
|
+
const docs = byDay.get(dayKey);
|
|
180
|
+
const existing = (_storedStayCheckIns_get = storedStayCheckIns(docs).get(reservationId)) != null ? _storedStayCheckIns_get : [];
|
|
181
|
+
const due = dueCheckInsForReservation({
|
|
182
|
+
reservationId,
|
|
183
|
+
reservation: changed,
|
|
184
|
+
resourceName: (_ref1 = resource == null ? void 0 : resource.name) != null ? _ref1 : null,
|
|
185
|
+
dayKey,
|
|
186
|
+
perGuest,
|
|
187
|
+
existing
|
|
188
|
+
});
|
|
189
|
+
// A day the stay no longer covers is its own reconcile's to settle.
|
|
190
|
+
if (!due.size) continue;
|
|
191
|
+
const plan = stayCheckInPlan({
|
|
192
|
+
unitCount: perGuest ? guests : 1,
|
|
193
|
+
existing
|
|
194
|
+
});
|
|
195
|
+
if (perGuest && plan.checkedIn > guests) {
|
|
196
|
+
return {
|
|
197
|
+
status: 409,
|
|
198
|
+
body: {
|
|
199
|
+
error: guestsBelowCheckedInMessage(plan.checkedIn, dayKey, todayKey)
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
for (const place of plan.create){
|
|
204
|
+
const id = reservationCheckInId(reservationId, dayKey, place);
|
|
205
|
+
const entry = due.get(id);
|
|
206
|
+
if (entry) creates.push({
|
|
207
|
+
ref: checkIns.doc(id),
|
|
208
|
+
data: newCheckInDocument(entry, nowMs)
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
const dropped = new Set(plan.drop);
|
|
212
|
+
for (const doc of docs){
|
|
213
|
+
if (dropped.has(doc.id)) {
|
|
214
|
+
drops.push(doc.ref);
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
const entry = due.get(doc.id);
|
|
218
|
+
if (!entry) continue;
|
|
219
|
+
const storedRow = doc.data();
|
|
220
|
+
// A guest already checked in keeps everything but the count of
|
|
221
|
+
// the stay's check-ins, which the list reads as "2 of 3".
|
|
222
|
+
const patch = storedRow.status === 'checked_in' ? storedRow.unitCount !== entry.unitCount ? {
|
|
223
|
+
unitCount: entry.unitCount
|
|
224
|
+
} : null : changedCheckInCustomerFields(storedRow, entry);
|
|
225
|
+
if (patch) patches.push({
|
|
226
|
+
ref: doc.ref,
|
|
227
|
+
patch: _extends({}, patch, {
|
|
228
|
+
updatedAtMs: nowMs
|
|
229
|
+
})
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
transaction.update(reservationRef, {
|
|
234
|
+
guests,
|
|
235
|
+
guestsChangedAtMs: nowMs,
|
|
236
|
+
guestsChangedBy: door.uid
|
|
237
|
+
});
|
|
238
|
+
for (const write of creates)transaction.create(write.ref, write.data);
|
|
239
|
+
for (const ref of drops)transaction.delete(ref);
|
|
240
|
+
for (const write of patches)transaction.update(write.ref, write.patch);
|
|
241
|
+
return {
|
|
242
|
+
status: 200,
|
|
243
|
+
body: {
|
|
244
|
+
reservationId,
|
|
245
|
+
guests,
|
|
246
|
+
previousGuests,
|
|
247
|
+
checkIns: {
|
|
248
|
+
added: creates.length,
|
|
249
|
+
removed: drops.length
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
activity: {
|
|
253
|
+
previous: previousGuests,
|
|
254
|
+
resourceName: (_ref = resource == null ? void 0 : resource.name) != null ? _ref : '',
|
|
255
|
+
arrivalDayMs: Number(reservation.checkInDayMs) || 0
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
});
|
|
259
|
+
if (outcome.status === 200 && 'activity' in outcome && outcome.activity) {
|
|
260
|
+
const { previous, resourceName, arrivalDayMs } = outcome.activity;
|
|
261
|
+
const arrival = arrivalDayMs ? new Date(arrivalDayMs).toISOString().slice(0, 10) : '';
|
|
262
|
+
await logActivity(hostId, {
|
|
263
|
+
uid: door.uid,
|
|
264
|
+
email: door.email
|
|
265
|
+
}, `Changed a stay’s guests from ${previous} to ${guests}`, {
|
|
266
|
+
type: 'commerce:reservation',
|
|
267
|
+
id: reservationId,
|
|
268
|
+
name: [
|
|
269
|
+
resourceName || 'Stay',
|
|
270
|
+
arrival
|
|
271
|
+
].filter(Boolean).join(' · ')
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
return res.status(outcome.status).json(outcome.body);
|
|
275
|
+
} catch (error) {
|
|
276
|
+
console.error('Changing a stay’s guests failed', error);
|
|
277
|
+
return res.status(500).json({
|
|
278
|
+
error: 'The guests could not be changed. Try again.'
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
export const reservationGuestsHandler = createReservationGuestsHandler();
|
|
284
|
+
|
|
285
|
+
//# sourceMappingURL=reservation-guests.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/reservation-guests.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 { resolveSiteTimeZone } from '@aglyn/aglyn/app-utils/collection-entry-date'\nimport { isHostPluginEnabled, type PluginApiHandler } from '@aglyn/aglyn/server'\nimport { zonedDayKey } from '@aglyn/shared-util-timestamp/zoned-time'\nimport { logHostActivity } from '@aglyn/tenant-data-admin'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport {\n changedCheckInCustomerFields,\n checkInDayLabel,\n dueCheckInsForReservation,\n newCheckInDocument,\n reservationCheckInId,\n STAY_CHECK_IN_SETTINGS_DOC,\n stayCheckInPlan,\n storedStayCheckIns,\n type HostCheckIn,\n} from '../model/commerce-check-in'\nimport {\n readStayCheckInMode,\n reservationGuests,\n reservationGuestsProblem,\n stayChecksInPerGuest,\n type HostReservation,\n type HostResource,\n} from '../model/commerce-reservations'\nimport { reservationsOnPlan } from './reservation-availability-query'\nimport { bodyOf, gate, resolved, validId, type ProductsWriteDeps } from './products-write'\nimport { WALK_IN_PERMISSION, WALK_IN_PLAN_REFUSAL, WALK_IN_PLUGIN_OFF } from './reservation-walk-in'\n\n/*\n * `POST /api/commerce/reservations/guests` (AGL-4043): staff change how many\n * guests a stay is for after it is booked — a family arrives with one more,\n * or one fewer.\n *\n * Body: { hostId, reservationId, guests }\n *\n * `guests` is a whole number from 1 up to what the resource sleeps\n * (`resourceGuestCeiling`). Who may ask is who may book a walk-in: the same\n * gate (`products-write.ts`'s), asking \"Book walk-ins and change guests\"\n * (`commerce.walkIns`, AGL-4047) on the site, or staff, while nothing is\n * frozen; the commerce plugin on for the site; and the store's plan taking\n * reservations. A stay that is pending, confirmed or\n * checked in can change; one cancelled, a no-show or checked out cannot.\n *\n * WHEN THE STAY IS CHECKED IN ONE GUEST AT A TIME, its check-ins follow in\n * the same transaction, on today and every later day that already has them\n * (`stayCheckInPlan`): added guests get new waiting check-ins; removed guests\n * take away only waiting ones, never one already checked in. A count below\n * how many are checked in on one of those days is refused, and nothing is\n * written. A day with no check-ins yet is left to its own reconcile, which\n * reads the new count.\n *\n * Every change stamps who made it and when on the stay, and writes a line to\n * the site's activity log. Asking for the count the stay already has answers\n * `unchanged` and writes nothing, so a retried tap is harmless.\n */\n\nexport const RESERVATION_GUESTS_GONE = 'That stay is gone.'\nexport const RESERVATION_GUESTS_CLOSED =\n 'Guests can change only on a stay that is booked or checked in'\n/** A member who does not hold the key a guests change asks: the walk-in's refusal, naming it. */\nexport const RESERVATION_GUESTS_PERMISSION_REFUSAL = WALK_IN_PERMISSION.refusal\n\n/** The most check-ins of one stay, from today on, the route reads in its transaction. */\nexport const RESERVATION_GUESTS_CHECK_IN_ROWS = 500\n\n/** The statuses whose guests can change. */\nconst OPEN_STATUSES: ReadonlyArray<HostReservation['status']> = ['pending', 'confirmed', 'checked_in']\n\n/** The refusal for a count below how many are already checked in on a day. */\nexport function guestsBelowCheckedInMessage(checkedIn: number, dayKey: string, todayKey: string): string {\n const when = dayKey === todayKey ? 'today' : `on ${checkInDayLabel(dayKey)}`\n return `${checkedIn} of this stay’s guests are already checked in ${when}. Undo a check-in first, or keep ${checkedIn} or more.`\n}\n\nexport interface ReservationGuestsDeps extends ProductsWriteDeps {\n logActivity?: typeof logHostActivity\n}\n\ntype Outcome =\n | {\n status: 200\n body: {\n reservationId: string\n guests: number\n previousGuests: number\n unchanged?: true\n checkIns?: { added: number; removed: number }\n }\n activity?: { previous: number; resourceName: string; arrivalDayMs: number }\n }\n | { status: 400 | 404 | 409; body: { error: string } }\n\nexport function createReservationGuestsHandler(options: ReservationGuestsDeps = {}): PluginApiHandler {\n return async (req, res) => {\n if (req.method !== 'POST') {\n return res.status(405).json({ error: 'Method not allowed' })\n }\n const deps = resolved(options)\n const logActivity = options.logActivity ?? logHostActivity\n const body = bodyOf(req)\n const hostId = body['hostId']\n const reservationId = body['reservationId']\n const rawGuests = body['guests']\n const guests = typeof rawGuests === 'number' || typeof rawGuests === 'string' ? Number(rawGuests) : NaN\n if (!validId(hostId) || !validId(reservationId) || rawGuests === undefined || rawGuests === null || rawGuests === '') {\n return res.status(400).json({ error: 'Missing guest details' })\n }\n try {\n const door = await gate(req, res, hostId, deps, { permission: WALK_IN_PERMISSION })\n if (!door) return\n if (!isHostPluginEnabled(door.org as never, door.host.data() as never, BUNDLE_ID)) {\n return res.status(403).json({ error: WALK_IN_PLUGIN_OFF })\n }\n if (!reservationsOnPlan(door.org)) {\n return res.status(403).json({ error: WALK_IN_PLAN_REFUSAL })\n }\n const db = deps.firestore()\n const hostRef = db.collection('hosts').doc(hostId)\n const reservationRef = hostRef.collection('reservations').doc(reservationId)\n const checkIns = hostRef.collection('checkIns')\n // Today on the store's calendar: earlier days are history, and stay\n // as they were checked in.\n const timeZone = resolveSiteTimeZone(\n door.org as { timeZone?: string },\n (door.host.data() ?? null) as { timeZone?: string } | null,\n )\n const todayKey = zonedDayKey(deps.now(), timeZone)\n\n const outcome: Outcome = await db.runTransaction(async (transaction) => {\n const stay = await transaction.get(reservationRef)\n if (!stay.exists) return { status: 404, body: { error: RESERVATION_GUESTS_GONE } }\n const reservation = stay.data() as HostReservation\n if (!OPEN_STATUSES.includes(reservation.status)) {\n return { status: 409, body: { error: RESERVATION_GUESTS_CLOSED } }\n }\n const resourceId = String(reservation.resourceId ?? '')\n const [resourceSnapshot, settings, stored] = await Promise.all([\n validId(resourceId) ? transaction.get(hostRef.collection('resources').doc(resourceId)) : null,\n transaction.get(hostRef.collection('settings').doc(STAY_CHECK_IN_SETTINGS_DOC)),\n transaction.get(\n checkIns\n .where('reservationId', '==', reservationId)\n .where('dayKey', '>=', todayKey)\n .limit(RESERVATION_GUESTS_CHECK_IN_ROWS),\n ),\n ])\n const resource = resourceSnapshot?.exists ? (resourceSnapshot.data() as HostResource) : null\n const problem = reservationGuestsProblem(guests, resource)\n if (problem) return { status: 400, body: { error: problem } }\n const previousGuests = reservationGuests(reservation)\n if (previousGuests === guests) {\n return { status: 200, body: { reservationId, guests, previousGuests, unchanged: true } }\n }\n\n // How the stay is checked in: the store's control, else the\n // resource's own setting; a resource gone since, once per stay.\n const mode = readStayCheckInMode(settings.exists ? settings.get('stays') : undefined)\n const perGuest = resource ? stayChecksInPerGuest(resource, mode) : mode === 'guest'\n const changed: HostReservation = { ...reservation, guests }\n const nowMs = deps.now()\n const byDay = new Map<string, FirebaseFirestore.QueryDocumentSnapshot[]>()\n for (const doc of stored.docs) {\n const dayKey = String(doc.get('dayKey') ?? '')\n if (dayKey < todayKey) continue\n byDay.set(dayKey, [...(byDay.get(dayKey) ?? []), doc])\n }\n const creates: Array<{ ref: FirebaseFirestore.DocumentReference; data: HostCheckIn }> = []\n const drops: FirebaseFirestore.DocumentReference[] = []\n const patches: Array<{ ref: FirebaseFirestore.DocumentReference; patch: Record<string, unknown> }> = []\n for (const dayKey of [...byDay.keys()].sort()) {\n const docs = byDay.get(dayKey)!\n const existing = storedStayCheckIns(docs).get(reservationId) ?? []\n const due = dueCheckInsForReservation({\n reservationId,\n reservation: changed,\n resourceName: resource?.name ?? null,\n dayKey,\n perGuest,\n existing,\n })\n // A day the stay no longer covers is its own reconcile's to settle.\n if (!due.size) continue\n const plan = stayCheckInPlan({ unitCount: perGuest ? guests : 1, existing })\n if (perGuest && plan.checkedIn > guests) {\n return { status: 409, body: { error: guestsBelowCheckedInMessage(plan.checkedIn, dayKey, todayKey) } }\n }\n for (const place of plan.create) {\n const id = reservationCheckInId(reservationId, dayKey, place)\n const entry = due.get(id)\n if (entry) creates.push({ ref: checkIns.doc(id), data: newCheckInDocument(entry, nowMs) })\n }\n const dropped = new Set(plan.drop)\n for (const doc of docs) {\n if (dropped.has(doc.id)) {\n drops.push(doc.ref)\n continue\n }\n const entry = due.get(doc.id)\n if (!entry) continue\n const storedRow = doc.data() as Partial<HostCheckIn>\n // A guest already checked in keeps everything but the count of\n // the stay's check-ins, which the list reads as \"2 of 3\".\n const patch =\n storedRow.status === 'checked_in'\n ? storedRow.unitCount !== entry.unitCount\n ? { unitCount: entry.unitCount }\n : null\n : changedCheckInCustomerFields(storedRow, entry)\n if (patch) patches.push({ ref: doc.ref, patch: { ...patch, updatedAtMs: nowMs } })\n }\n }\n transaction.update(reservationRef, {\n guests,\n guestsChangedAtMs: nowMs,\n guestsChangedBy: door.uid,\n })\n for (const write of creates) transaction.create(write.ref, write.data)\n for (const ref of drops) transaction.delete(ref)\n for (const write of patches) transaction.update(write.ref, write.patch)\n return {\n status: 200,\n body: {\n reservationId,\n guests,\n previousGuests,\n checkIns: { added: creates.length, removed: drops.length },\n },\n activity: {\n previous: previousGuests,\n resourceName: resource?.name ?? '',\n arrivalDayMs: Number(reservation.checkInDayMs) || 0,\n },\n }\n })\n\n if (outcome.status === 200 && 'activity' in outcome && outcome.activity) {\n const { previous, resourceName, arrivalDayMs } = outcome.activity\n const arrival = arrivalDayMs ? new Date(arrivalDayMs).toISOString().slice(0, 10) : ''\n await logActivity(\n hostId,\n { uid: door.uid, email: door.email },\n `Changed a stay’s guests from ${previous} to ${guests}`,\n {\n type: 'commerce:reservation',\n id: reservationId,\n name: [resourceName || 'Stay', arrival].filter(Boolean).join(' · '),\n },\n )\n }\n return res.status(outcome.status).json(outcome.body)\n } catch (error) {\n console.error('Changing a stay’s guests failed', error)\n return res.status(500).json({ error: 'The guests could not be changed. Try again.' })\n }\n }\n}\n\nexport const reservationGuestsHandler = createReservationGuestsHandler()\n"],"names":["resolveSiteTimeZone","isHostPluginEnabled","zonedDayKey","logHostActivity","BUNDLE_ID","changedCheckInCustomerFields","checkInDayLabel","dueCheckInsForReservation","newCheckInDocument","reservationCheckInId","STAY_CHECK_IN_SETTINGS_DOC","stayCheckInPlan","storedStayCheckIns","readStayCheckInMode","reservationGuests","reservationGuestsProblem","stayChecksInPerGuest","reservationsOnPlan","bodyOf","gate","resolved","validId","WALK_IN_PERMISSION","WALK_IN_PLAN_REFUSAL","WALK_IN_PLUGIN_OFF","RESERVATION_GUESTS_GONE","RESERVATION_GUESTS_CLOSED","RESERVATION_GUESTS_PERMISSION_REFUSAL","refusal","RESERVATION_GUESTS_CHECK_IN_ROWS","OPEN_STATUSES","guestsBelowCheckedInMessage","checkedIn","dayKey","todayKey","when","createReservationGuestsHandler","options","req","res","method","status","json","error","deps","logActivity","body","hostId","reservationId","rawGuests","guests","Number","NaN","undefined","door","permission","org","host","data","db","firestore","hostRef","collection","doc","reservationRef","checkIns","timeZone","now","outcome","runTransaction","transaction","reservation","stay","get","exists","includes","resourceId","String","resourceSnapshot","settings","stored","Promise","all","where","limit","resource","problem","previousGuests","unchanged","mode","perGuest","changed","nowMs","byDay","Map","docs","set","creates","drops","patches","keys","sort","existing","due","resourceName","name","size","plan","unitCount","place","create","id","entry","push","ref","dropped","Set","drop","has","storedRow","patch","updatedAtMs","update","guestsChangedAtMs","guestsChangedBy","uid","write","delete","added","length","removed","activity","previous","arrivalDayMs","checkInDayMs","arrival","Date","toISOString","slice","email","type","filter","Boolean","join","console","reservationGuestsHandler"],"mappings":"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"}
|
|
@@ -16,12 +16,22 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import { type PluginApiHandler } from '@aglyn/aglyn/server';
|
|
18
18
|
import * as CommerceModel from '../model';
|
|
19
|
-
import { type ProductsWriteDeps } from './products-write';
|
|
19
|
+
import { type GatePermission, type ProductsWriteDeps } from './products-write';
|
|
20
20
|
export declare const WALK_IN_GONE = "That resource is gone.";
|
|
21
21
|
export declare const WALK_IN_TAKEN_ONE_UNIT = "Those dates are taken";
|
|
22
22
|
export declare const WALK_IN_TAKEN_EVERY_UNIT = "Every unit is taken on at least one of those nights";
|
|
23
23
|
export declare const WALK_IN_PLUGIN_OFF = "Reservations are not turned on for this site";
|
|
24
24
|
export declare const WALK_IN_ID_CONFLICT = "That walk-in id belongs to another stay";
|
|
25
|
+
/**
|
|
26
|
+
* A member who does not hold "Book walk-ins and change guests" on the site
|
|
27
|
+
* (AGL-4047): the refusal names the permission and who can change it, never
|
|
28
|
+
* a role.
|
|
29
|
+
*/
|
|
30
|
+
export declare const WALK_IN_PERMISSION_REFUSAL: string;
|
|
31
|
+
/** The key a walk-in and a guests change check, read as the rules read it. */
|
|
32
|
+
export declare const WALK_IN_PERMISSION: GatePermission;
|
|
33
|
+
/** A store whose plan does not take reservations, worded as the plan refusals are. */
|
|
34
|
+
export declare const WALK_IN_PLAN_REFUSAL = "Reservations are not included in your plan \u2014 see Billing";
|
|
25
35
|
/** The refusal for dates with no free unit, worded for the resource. */
|
|
26
36
|
export declare function walkInTakenMessage(resource: CommerceModel.HostResource): string;
|
|
27
37
|
export declare function createReservationWalkInHandler(options?: ProductsWriteDeps): PluginApiHandler;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
1
2
|
/**
|
|
2
3
|
* @license
|
|
3
4
|
* Copyright 2026 Aglyn LLC
|
|
@@ -17,7 +18,8 @@
|
|
|
17
18
|
import { isHostPluginEnabled } from "@aglyn/aglyn/server";
|
|
18
19
|
import { BUNDLE_ID } from "../constants/bundle-common.js";
|
|
19
20
|
import * as CommerceModel from "../model/index.js";
|
|
20
|
-
import { readLiveReservations, reservationAvailabilityQuery } from "./reservation-availability-query.js";
|
|
21
|
+
import { readLiveReservations, reservationAvailabilityQuery, reservationsOnPlan } from "./reservation-availability-query.js";
|
|
22
|
+
import { RESERVATION_SITE_ROLE_PRESET, reservationPermissionRefusal } from "../model/plugin-permissions.js";
|
|
21
23
|
import { bodyOf, gate, resolved, validId } from "./products-write.js";
|
|
22
24
|
/*
|
|
23
25
|
* `POST /api/commerce/reservations/walk-in` (AGL-4046): a staff walk-in,
|
|
@@ -31,12 +33,17 @@ import { bodyOf, gate, resolved, validId } from "./products-write.js";
|
|
|
31
33
|
* storefront's `/api/commerce/reserve` uses, so the loser's transaction re-runs
|
|
32
34
|
* on the winner's write and is refused.
|
|
33
35
|
*
|
|
34
|
-
* Who may call it
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* the
|
|
36
|
+
* Who may call it: a verified member who holds "Book walk-ins and change
|
|
37
|
+
* guests" (`commerce.walkIns`, AGL-4047) on the site, or staff, while the
|
|
38
|
+
* site, its org and the platform are not frozen. The key's preset is the
|
|
39
|
+
* site role that wrote a reservation before it was a key (Admin, Editor,
|
|
40
|
+
* Author), and it follows "Manage reservations" unless a role or member sets
|
|
41
|
+
* it, so nobody's access moved; a custom role can now grant it to the
|
|
42
|
+
* window's staff. That is `products-write.ts`'s `gate`, reused rather than
|
|
43
|
+
* restated, reading the key as the rules do. The commerce plugin must
|
|
44
|
+
* also be on for the site, and the store's plan must take reservations: the
|
|
45
|
+
* same `commerce` entitlement `/api/commerce/reserve` asks
|
|
46
|
+
* (`reservationsOnPlan`), so a lapsed plan books through neither door.
|
|
40
47
|
*
|
|
41
48
|
* The stay is written with exactly the fields the card wrote: confirmed, no
|
|
42
49
|
* email, no deposit, nothing paid. Payment is collected at the register.
|
|
@@ -45,6 +52,17 @@ export const WALK_IN_TAKEN_ONE_UNIT = 'Those dates are taken';
|
|
|
45
52
|
export const WALK_IN_TAKEN_EVERY_UNIT = 'Every unit is taken on at least one of those nights';
|
|
46
53
|
export const WALK_IN_PLUGIN_OFF = 'Reservations are not turned on for this site';
|
|
47
54
|
export const WALK_IN_ID_CONFLICT = 'That walk-in id belongs to another stay';
|
|
55
|
+
/**
|
|
56
|
+
* A member who does not hold "Book walk-ins and change guests" on the site
|
|
57
|
+
* (AGL-4047): the refusal names the permission and who can change it, never
|
|
58
|
+
* a role.
|
|
59
|
+
*/ export const WALK_IN_PERMISSION_REFUSAL = reservationPermissionRefusal('commerce.walkIns');
|
|
60
|
+
/** The key a walk-in and a guests change check, read as the rules read it. */ export const WALK_IN_PERMISSION = {
|
|
61
|
+
key: 'commerce.walkIns',
|
|
62
|
+
presetFor: RESERVATION_SITE_ROLE_PRESET,
|
|
63
|
+
refusal: WALK_IN_PERMISSION_REFUSAL
|
|
64
|
+
};
|
|
65
|
+
/** A store whose plan does not take reservations, worded as the plan refusals are. */ export const WALK_IN_PLAN_REFUSAL = 'Reservations are not included in your plan — see Billing';
|
|
48
66
|
/** The refusal for dates with no free unit, worded for the resource. */ export function walkInTakenMessage(resource) {
|
|
49
67
|
return CommerceModel.resourceUnits(resource) > 1 ? WALK_IN_TAKEN_EVERY_UNIT : WALK_IN_TAKEN_ONE_UNIT;
|
|
50
68
|
}
|
|
@@ -52,7 +70,12 @@ const dayOf = (value)=>{
|
|
|
52
70
|
const ms = Number(value);
|
|
53
71
|
return Number.isFinite(ms) && ms > 0 ? CommerceModel.toDayMs(ms) : 0;
|
|
54
72
|
};
|
|
55
|
-
|
|
73
|
+
/*
|
|
74
|
+
* Body: `{ hostId, resourceId, checkInDayMs, checkOutDayMs, guestName?,
|
|
75
|
+
* guests?, reservationId? }`. `guests` (AGL-4043) is how many the stay is
|
|
76
|
+
* for, 1 up to what the resource sleeps; a stay checked in per guest makes a
|
|
77
|
+
* check-in for each.
|
|
78
|
+
*/ export function createReservationWalkInHandler(options = {}) {
|
|
56
79
|
return async (req, res)=>{
|
|
57
80
|
if (req.method !== 'POST') {
|
|
58
81
|
return res.status(405).json({
|
|
@@ -66,6 +89,10 @@ export function createReservationWalkInHandler(options = {}) {
|
|
|
66
89
|
const checkInDayMs = dayOf(body['checkInDayMs']);
|
|
67
90
|
const checkOutDayMs = dayOf(body['checkOutDayMs']);
|
|
68
91
|
const guestName = typeof body['guestName'] === 'string' ? body['guestName'].trim().slice(0, 120) : '';
|
|
92
|
+
// How many guests (AGL-4043): optional, checked against what the
|
|
93
|
+
// resource sleeps once it is read.
|
|
94
|
+
const rawGuests = body['guests'];
|
|
95
|
+
const guestsAsked = rawGuests === undefined || rawGuests === null || rawGuests === '' ? undefined : Number(rawGuests);
|
|
69
96
|
// Optional, client-minted: a retry of the same walk-in (a dropped
|
|
70
97
|
// response on a weak signal) finds its own stay instead of booking a
|
|
71
98
|
// second unit.
|
|
@@ -76,13 +103,23 @@ export function createReservationWalkInHandler(options = {}) {
|
|
|
76
103
|
});
|
|
77
104
|
}
|
|
78
105
|
try {
|
|
79
|
-
const door = await gate(req, res, hostId, deps
|
|
106
|
+
const door = await gate(req, res, hostId, deps, {
|
|
107
|
+
permission: WALK_IN_PERMISSION
|
|
108
|
+
});
|
|
80
109
|
if (!door) return;
|
|
81
110
|
if (!isHostPluginEnabled(door.org, door.host.data(), BUNDLE_ID)) {
|
|
82
111
|
return res.status(403).json({
|
|
83
112
|
error: WALK_IN_PLUGIN_OFF
|
|
84
113
|
});
|
|
85
114
|
}
|
|
115
|
+
// The plan question every reservation door asks (AGL-1873), before
|
|
116
|
+
// anything is read or written. Staff impersonating a store still meet
|
|
117
|
+
// it: the walk-in books for the store, on the store's plan.
|
|
118
|
+
if (!reservationsOnPlan(door.org)) {
|
|
119
|
+
return res.status(403).json({
|
|
120
|
+
error: WALK_IN_PLAN_REFUSAL
|
|
121
|
+
});
|
|
122
|
+
}
|
|
86
123
|
const db = deps.firestore();
|
|
87
124
|
const hostRef = db.collection('hosts').doc(hostId);
|
|
88
125
|
const resourceSnapshot = await hostRef.collection('resources').doc(resourceId).get();
|
|
@@ -98,6 +135,10 @@ export function createReservationWalkInHandler(options = {}) {
|
|
|
98
135
|
if (quote.problem) return res.status(400).json({
|
|
99
136
|
error: quote.problem
|
|
100
137
|
});
|
|
138
|
+
const guestsProblem = CommerceModel.reservationGuestsProblem(guestsAsked, resource);
|
|
139
|
+
if (guestsProblem) return res.status(400).json({
|
|
140
|
+
error: guestsProblem
|
|
141
|
+
});
|
|
101
142
|
const reservations = hostRef.collection('reservations');
|
|
102
143
|
const availability = reservationAvailabilityQuery(reservations, resourceId, checkInDayMs);
|
|
103
144
|
const reservationRef = reservations.doc(typeof requestedId === 'string' ? requestedId : createResourceUid());
|
|
@@ -132,19 +173,22 @@ export function createReservationWalkInHandler(options = {}) {
|
|
|
132
173
|
}
|
|
133
174
|
};
|
|
134
175
|
}
|
|
135
|
-
transaction.set(reservationRef, {
|
|
176
|
+
transaction.set(reservationRef, _extends({
|
|
136
177
|
resourceId,
|
|
137
178
|
status: 'confirmed',
|
|
138
179
|
checkInDayMs,
|
|
139
180
|
checkOutDayMs,
|
|
140
181
|
guestName: guestName || null,
|
|
141
|
-
guestEmail: null
|
|
182
|
+
guestEmail: null
|
|
183
|
+
}, guestsAsked !== undefined ? {
|
|
184
|
+
guests: guestsAsked
|
|
185
|
+
} : {}, {
|
|
142
186
|
nights: quote.nights,
|
|
143
187
|
totalCents: quote.totalCents,
|
|
144
188
|
depositCents: 0,
|
|
145
189
|
paidCents: 0,
|
|
146
190
|
createdAtMs: nowMs
|
|
147
|
-
});
|
|
191
|
+
}));
|
|
148
192
|
return {
|
|
149
193
|
status: 200,
|
|
150
194
|
body: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/reservation-walk-in.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 { createResourceUid } from '@aglyn/aglyn/app-utils/create-resource-uid'\nimport { isHostPluginEnabled, type PluginApiHandler } from '@aglyn/aglyn/server'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport * as CommerceModel from '../model'\nimport {\n readLiveReservations,\n reservationAvailabilityQuery,\n} from './reservation-availability-query'\nimport { bodyOf, gate, resolved, validId, type ProductsWriteDeps } from './products-write'\n\n/*\n * `POST /api/commerce/reservations/walk-in` (AGL-4046): a staff walk-in,\n * race-safe.\n *\n * The console Reservations card and the native apps used to write a walk-in\n * straight from the client after their own availability read. Two staff on two\n * devices could both read the last free unit (the last RV hookup) and both\n * write a stay into it. This route re-asks availability INSIDE the transaction\n * that writes, on the same query and the same `isRangeAvailable` rule the\n * storefront's `/api/commerce/reserve` uses, so the loser's transaction re-runs\n * on the winner's write and is refused.\n *\n * Who may call it is who the Firestore rules let write a reservation from the\n * console: a verified member with a content-write role on the site\n * (`canWriteHostContent`: admin, editor, author), or staff, while the site,\n * its org and the platform are not frozen. That is `products-write.ts`'s\n * `gate`, reused rather than restated. The commerce plugin must also be on for\n * the site.\n *\n * The stay is written with exactly the fields the card wrote: confirmed, no\n * email, no deposit, nothing paid. Payment is collected at the register.\n */\n\nexport const WALK_IN_GONE = 'That resource is gone.'\nexport const WALK_IN_TAKEN_ONE_UNIT = 'Those dates are taken'\nexport const WALK_IN_TAKEN_EVERY_UNIT =\n 'Every unit is taken on at least one of those nights'\nexport const WALK_IN_PLUGIN_OFF = 'Reservations are not turned on for this site'\nexport const WALK_IN_ID_CONFLICT = 'That walk-in id belongs to another stay'\n\n/** The refusal for dates with no free unit, worded for the resource. */\nexport function walkInTakenMessage(resource: CommerceModel.HostResource): string {\n return CommerceModel.resourceUnits(resource) > 1\n ? WALK_IN_TAKEN_EVERY_UNIT\n : WALK_IN_TAKEN_ONE_UNIT\n}\n\nconst dayOf = (value: unknown): number => {\n const ms = Number(value)\n return Number.isFinite(ms) && ms > 0 ? CommerceModel.toDayMs(ms) : 0\n}\n\ntype Outcome =\n | { status: 200; body: { reservationId: string; replayed?: true } }\n | { status: 409; body: { error: string } }\n\nexport function createReservationWalkInHandler(\n options: ProductsWriteDeps = {},\n): PluginApiHandler {\n return async (req, res) => {\n if (req.method !== 'POST') {\n return res.status(405).json({ error: 'Method not allowed' })\n }\n const deps = resolved(options)\n const body = bodyOf(req)\n const hostId = body['hostId']\n const resourceId = body['resourceId']\n const checkInDayMs = dayOf(body['checkInDayMs'])\n const checkOutDayMs = dayOf(body['checkOutDayMs'])\n const guestName =\n typeof body['guestName'] === 'string'\n ? body['guestName'].trim().slice(0, 120)\n : ''\n // Optional, client-minted: a retry of the same walk-in (a dropped\n // response on a weak signal) finds its own stay instead of booking a\n // second unit.\n const requestedId = body['reservationId']\n if (\n !validId(hostId) ||\n !validId(resourceId) ||\n !checkInDayMs ||\n !checkOutDayMs ||\n (requestedId !== undefined && requestedId !== null && !validId(requestedId))\n ) {\n return res.status(400).json({ error: 'Missing walk-in details' })\n }\n try {\n const door = await gate(req, res, hostId, deps)\n if (!door) return\n if (!isHostPluginEnabled(door.org as never, door.host.data() as never, BUNDLE_ID)) {\n return res.status(403).json({ error: WALK_IN_PLUGIN_OFF })\n }\n const db = deps.firestore()\n const hostRef = db.collection('hosts').doc(hostId)\n const resourceSnapshot = await hostRef.collection('resources').doc(resourceId).get()\n const resource = resourceSnapshot.data() as CommerceModel.HostResource | undefined\n if (!resourceSnapshot.exists || !resource) {\n return res.status(404).json({ error: WALK_IN_GONE })\n }\n // The one rule for what can be booked (no nights, under the minimum\n // stay), shared with the card, the widget and both native apps.\n const quote = CommerceModel.computeReservationQuote(resource, checkInDayMs, checkOutDayMs)\n if (quote.problem) return res.status(400).json({ error: quote.problem })\n\n const reservations = hostRef.collection('reservations')\n const availability = reservationAvailabilityQuery(reservations, resourceId, checkInDayMs)\n const reservationRef = reservations.doc(\n typeof requestedId === 'string' ? requestedId : createResourceUid(),\n )\n const outcome: Outcome = await db.runTransaction(async (transaction) => {\n const [existing, fresh] = await Promise.all([\n transaction.get(reservationRef),\n transaction.get(availability),\n ])\n if (existing.exists) {\n const same =\n existing.get('resourceId') === resourceId &&\n Number(existing.get('checkInDayMs')) === checkInDayMs &&\n Number(existing.get('checkOutDayMs')) === checkOutDayMs\n return same\n ? { status: 200, body: { reservationId: reservationRef.id, replayed: true } }\n : { status: 409, body: { error: WALK_IN_ID_CONFLICT } }\n }\n // Re-timed inside the transaction: a retry under contention runs\n // later, and a pending hold's 30-minute lapse is measured from now.\n const nowMs = deps.now()\n if (\n !CommerceModel.isRangeAvailable(\n resource,\n readLiveReservations(fresh),\n checkInDayMs,\n checkOutDayMs,\n nowMs,\n )\n ) {\n return { status: 409, body: { error: walkInTakenMessage(resource) } }\n }\n transaction.set(reservationRef, {\n resourceId,\n status: 'confirmed',\n checkInDayMs,\n checkOutDayMs,\n guestName: guestName || null,\n guestEmail: null,\n nights: quote.nights,\n totalCents: quote.totalCents,\n depositCents: 0,\n paidCents: 0,\n createdAtMs: nowMs,\n } satisfies CommerceModel.HostReservation)\n return { status: 200, body: { reservationId: reservationRef.id } }\n })\n return res.status(outcome.status).json(outcome.body)\n } catch (error) {\n console.error('Walk-in reservation failed', error)\n return res.status(500).json({ error: 'Walk-in failed' })\n }\n }\n}\n\nexport const reservationWalkInHandler = createReservationWalkInHandler()\n"],"names":["createResourceUid","isHostPluginEnabled","BUNDLE_ID","CommerceModel","readLiveReservations","reservationAvailabilityQuery","bodyOf","gate","resolved","validId","WALK_IN_GONE","WALK_IN_TAKEN_ONE_UNIT","WALK_IN_TAKEN_EVERY_UNIT","WALK_IN_PLUGIN_OFF","WALK_IN_ID_CONFLICT","walkInTakenMessage","resource","resourceUnits","dayOf","value","ms","Number","isFinite","toDayMs","createReservationWalkInHandler","options","req","res","method","status","json","error","deps","body","hostId","resourceId","checkInDayMs","checkOutDayMs","guestName","trim","slice","requestedId","undefined","door","org","host","data","db","firestore","hostRef","collection","doc","resourceSnapshot","get","exists","quote","computeReservationQuote","problem","reservations","availability","reservationRef","outcome","runTransaction","transaction","existing","fresh","Promise","all","same","reservationId","id","replayed","nowMs","now","isRangeAvailable","set","guestEmail","nights","totalCents","depositCents","paidCents","createdAtMs","console","reservationWalkInHandler"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/reservation-walk-in.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 { createResourceUid } from '@aglyn/aglyn/app-utils/create-resource-uid'\nimport { isHostPluginEnabled, type PluginApiHandler } from '@aglyn/aglyn/server'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport * as CommerceModel from '../model'\nimport {\n readLiveReservations,\n reservationAvailabilityQuery,\n reservationsOnPlan,\n} from './reservation-availability-query'\nimport {\n RESERVATION_SITE_ROLE_PRESET,\n reservationPermissionRefusal,\n} from '../model/plugin-permissions'\nimport { bodyOf, gate, resolved, validId, type GatePermission, type ProductsWriteDeps } from './products-write'\n\n/*\n * `POST /api/commerce/reservations/walk-in` (AGL-4046): a staff walk-in,\n * race-safe.\n *\n * The console Reservations card and the native apps used to write a walk-in\n * straight from the client after their own availability read. Two staff on two\n * devices could both read the last free unit (the last RV hookup) and both\n * write a stay into it. This route re-asks availability INSIDE the transaction\n * that writes, on the same query and the same `isRangeAvailable` rule the\n * storefront's `/api/commerce/reserve` uses, so the loser's transaction re-runs\n * on the winner's write and is refused.\n *\n * Who may call it: a verified member who holds \"Book walk-ins and change\n * guests\" (`commerce.walkIns`, AGL-4047) on the site, or staff, while the\n * site, its org and the platform are not frozen. The key's preset is the\n * site role that wrote a reservation before it was a key (Admin, Editor,\n * Author), and it follows \"Manage reservations\" unless a role or member sets\n * it, so nobody's access moved; a custom role can now grant it to the\n * window's staff. That is `products-write.ts`'s `gate`, reused rather than\n * restated, reading the key as the rules do. The commerce plugin must\n * also be on for the site, and the store's plan must take reservations: the\n * same `commerce` entitlement `/api/commerce/reserve` asks\n * (`reservationsOnPlan`), so a lapsed plan books through neither door.\n *\n * The stay is written with exactly the fields the card wrote: confirmed, no\n * email, no deposit, nothing paid. Payment is collected at the register.\n */\n\nexport const WALK_IN_GONE = 'That resource is gone.'\nexport const WALK_IN_TAKEN_ONE_UNIT = 'Those dates are taken'\nexport const WALK_IN_TAKEN_EVERY_UNIT =\n 'Every unit is taken on at least one of those nights'\nexport const WALK_IN_PLUGIN_OFF = 'Reservations are not turned on for this site'\nexport const WALK_IN_ID_CONFLICT = 'That walk-in id belongs to another stay'\n/**\n * A member who does not hold \"Book walk-ins and change guests\" on the site\n * (AGL-4047): the refusal names the permission and who can change it, never\n * a role.\n */\nexport const WALK_IN_PERMISSION_REFUSAL = reservationPermissionRefusal('commerce.walkIns')\n\n/** The key a walk-in and a guests change check, read as the rules read it. */\nexport const WALK_IN_PERMISSION: GatePermission = {\n key: 'commerce.walkIns',\n presetFor: RESERVATION_SITE_ROLE_PRESET,\n refusal: WALK_IN_PERMISSION_REFUSAL,\n}\n/** A store whose plan does not take reservations, worded as the plan refusals are. */\nexport const WALK_IN_PLAN_REFUSAL = 'Reservations are not included in your plan — see Billing'\n\n/** The refusal for dates with no free unit, worded for the resource. */\nexport function walkInTakenMessage(resource: CommerceModel.HostResource): string {\n return CommerceModel.resourceUnits(resource) > 1\n ? WALK_IN_TAKEN_EVERY_UNIT\n : WALK_IN_TAKEN_ONE_UNIT\n}\n\nconst dayOf = (value: unknown): number => {\n const ms = Number(value)\n return Number.isFinite(ms) && ms > 0 ? CommerceModel.toDayMs(ms) : 0\n}\n\ntype Outcome =\n | { status: 200; body: { reservationId: string; replayed?: true } }\n | { status: 409; body: { error: string } }\n\n/*\n * Body: `{ hostId, resourceId, checkInDayMs, checkOutDayMs, guestName?,\n * guests?, reservationId? }`. `guests` (AGL-4043) is how many the stay is\n * for, 1 up to what the resource sleeps; a stay checked in per guest makes a\n * check-in for each.\n */\nexport function createReservationWalkInHandler(\n options: ProductsWriteDeps = {},\n): PluginApiHandler {\n return async (req, res) => {\n if (req.method !== 'POST') {\n return res.status(405).json({ error: 'Method not allowed' })\n }\n const deps = resolved(options)\n const body = bodyOf(req)\n const hostId = body['hostId']\n const resourceId = body['resourceId']\n const checkInDayMs = dayOf(body['checkInDayMs'])\n const checkOutDayMs = dayOf(body['checkOutDayMs'])\n const guestName =\n typeof body['guestName'] === 'string'\n ? body['guestName'].trim().slice(0, 120)\n : ''\n // How many guests (AGL-4043): optional, checked against what the\n // resource sleeps once it is read.\n const rawGuests = body['guests']\n const guestsAsked =\n rawGuests === undefined || rawGuests === null || rawGuests === '' ? undefined : Number(rawGuests)\n // Optional, client-minted: a retry of the same walk-in (a dropped\n // response on a weak signal) finds its own stay instead of booking a\n // second unit.\n const requestedId = body['reservationId']\n if (\n !validId(hostId) ||\n !validId(resourceId) ||\n !checkInDayMs ||\n !checkOutDayMs ||\n (requestedId !== undefined && requestedId !== null && !validId(requestedId))\n ) {\n return res.status(400).json({ error: 'Missing walk-in details' })\n }\n try {\n const door = await gate(req, res, hostId, deps, { permission: WALK_IN_PERMISSION })\n if (!door) return\n if (!isHostPluginEnabled(door.org as never, door.host.data() as never, BUNDLE_ID)) {\n return res.status(403).json({ error: WALK_IN_PLUGIN_OFF })\n }\n // The plan question every reservation door asks (AGL-1873), before\n // anything is read or written. Staff impersonating a store still meet\n // it: the walk-in books for the store, on the store's plan.\n if (!reservationsOnPlan(door.org)) {\n return res.status(403).json({ error: WALK_IN_PLAN_REFUSAL })\n }\n const db = deps.firestore()\n const hostRef = db.collection('hosts').doc(hostId)\n const resourceSnapshot = await hostRef.collection('resources').doc(resourceId).get()\n const resource = resourceSnapshot.data() as CommerceModel.HostResource | undefined\n if (!resourceSnapshot.exists || !resource) {\n return res.status(404).json({ error: WALK_IN_GONE })\n }\n // The one rule for what can be booked (no nights, under the minimum\n // stay), shared with the card, the widget and both native apps.\n const quote = CommerceModel.computeReservationQuote(resource, checkInDayMs, checkOutDayMs)\n if (quote.problem) return res.status(400).json({ error: quote.problem })\n const guestsProblem = CommerceModel.reservationGuestsProblem(guestsAsked, resource)\n if (guestsProblem) return res.status(400).json({ error: guestsProblem })\n\n const reservations = hostRef.collection('reservations')\n const availability = reservationAvailabilityQuery(reservations, resourceId, checkInDayMs)\n const reservationRef = reservations.doc(\n typeof requestedId === 'string' ? requestedId : createResourceUid(),\n )\n const outcome: Outcome = await db.runTransaction(async (transaction) => {\n const [existing, fresh] = await Promise.all([\n transaction.get(reservationRef),\n transaction.get(availability),\n ])\n if (existing.exists) {\n const same =\n existing.get('resourceId') === resourceId &&\n Number(existing.get('checkInDayMs')) === checkInDayMs &&\n Number(existing.get('checkOutDayMs')) === checkOutDayMs\n return same\n ? { status: 200, body: { reservationId: reservationRef.id, replayed: true } }\n : { status: 409, body: { error: WALK_IN_ID_CONFLICT } }\n }\n // Re-timed inside the transaction: a retry under contention runs\n // later, and a pending hold's 30-minute lapse is measured from now.\n const nowMs = deps.now()\n if (\n !CommerceModel.isRangeAvailable(\n resource,\n readLiveReservations(fresh),\n checkInDayMs,\n checkOutDayMs,\n nowMs,\n )\n ) {\n return { status: 409, body: { error: walkInTakenMessage(resource) } }\n }\n transaction.set(reservationRef, {\n resourceId,\n status: 'confirmed',\n checkInDayMs,\n checkOutDayMs,\n guestName: guestName || null,\n guestEmail: null,\n ...(guestsAsked !== undefined ? { guests: guestsAsked } : {}),\n nights: quote.nights,\n totalCents: quote.totalCents,\n depositCents: 0,\n paidCents: 0,\n createdAtMs: nowMs,\n } satisfies CommerceModel.HostReservation)\n return { status: 200, body: { reservationId: reservationRef.id } }\n })\n return res.status(outcome.status).json(outcome.body)\n } catch (error) {\n console.error('Walk-in reservation failed', error)\n return res.status(500).json({ error: 'Walk-in failed' })\n }\n }\n}\n\nexport const reservationWalkInHandler = createReservationWalkInHandler()\n"],"names":["createResourceUid","isHostPluginEnabled","BUNDLE_ID","CommerceModel","readLiveReservations","reservationAvailabilityQuery","reservationsOnPlan","RESERVATION_SITE_ROLE_PRESET","reservationPermissionRefusal","bodyOf","gate","resolved","validId","WALK_IN_GONE","WALK_IN_TAKEN_ONE_UNIT","WALK_IN_TAKEN_EVERY_UNIT","WALK_IN_PLUGIN_OFF","WALK_IN_ID_CONFLICT","WALK_IN_PERMISSION_REFUSAL","WALK_IN_PERMISSION","key","presetFor","refusal","WALK_IN_PLAN_REFUSAL","walkInTakenMessage","resource","resourceUnits","dayOf","value","ms","Number","isFinite","toDayMs","createReservationWalkInHandler","options","req","res","method","status","json","error","deps","body","hostId","resourceId","checkInDayMs","checkOutDayMs","guestName","trim","slice","rawGuests","guestsAsked","undefined","requestedId","door","permission","org","host","data","db","firestore","hostRef","collection","doc","resourceSnapshot","get","exists","quote","computeReservationQuote","problem","guestsProblem","reservationGuestsProblem","reservations","availability","reservationRef","outcome","runTransaction","transaction","existing","fresh","Promise","all","same","reservationId","id","replayed","nowMs","now","isRangeAvailable","set","guestEmail","guests","nights","totalCents","depositCents","paidCents","createdAtMs","console","reservationWalkInHandler"],"mappings":"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"}
|