@aglyn/plugins-commerce 1.0.0-beta.285 → 1.0.0-beta.288
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/order-webhooks-card.component.js +1 -1
- package/src/lib/components/console/order-webhooks-card.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 +15 -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 +74 -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/model/workspace-site-permissions.d.ts +26 -0
- package/src/lib/model/workspace-site-permissions.js +81 -0
- package/src/lib/model/workspace-site-permissions.js.map +1 -0
- 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 +48 -0
- package/src/lib/server/commerce-site-keys.js +61 -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/order-webhooks.js +8 -8
- package/src/lib/server/order-webhooks.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 +28 -9
- package/src/lib/server/pos-ops-gate.js +50 -19
- 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-refund-authority.d.ts +3 -1
- package/src/lib/server/pos-refund-authority.js +3 -2
- package/src/lib/server/pos-refund-authority.js.map +1 -1
- package/src/lib/server/pos-return.d.ts +10 -0
- package/src/lib/server/pos-return.js +29 -7
- 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 +29 -24
- 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 +55 -42
- 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 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/pos-cellular-billing.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 { normalizeOrgLockdown } from '@aglyn/aglyn/app-utils/lockdown'\nimport { formatOperatorAlertAmount } from '@aglyn/aglyn/app-utils/operator-alerts'\nimport type { PluginOrgEraser } from '@aglyn/aglyn/plugin-manager/plugin-org-erasure'\nimport type { PluginJobHostGate } from '@aglyn/aglyn/server'\nimport { firebaseAdmin, raiseOperatorAlert, readOrgBilling } from '@aglyn/tenant-data-admin'\nimport {\n chargeOrgUsageInvoice,\n USAGE_INVOICE_MIN_CHARGE_CENTS,\n type OrgUsageInvoiceRequest,\n type OrgUsageInvoiceResult,\n} from '@aglyn/tenant-data-admin/server/usage-invoice'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport {\n COMMERCE_POS_CELLULAR_CHARGE_FAILED,\n COMMERCE_POS_CELLULAR_TURN_OFF_FAILED,\n COMMERCE_POS_CELLULAR_TURNED_OFF_UNPAID,\n} from '../constants/operator-alerts'\nimport {\n closePosCellularPeriod,\n parsePosCellularConfig,\n posCellularChargeCents,\n posCellularGraceEndsAtMs,\n posCellularMonthBounds,\n posCellularMonthKey,\n posCellularMonthLabel,\n posCellularOverdue,\n posCellularPreviousMonthKey,\n posCellularReadersByWorkspace,\n posCellularWarningDue,\n POS_CELLULAR_CHARGE_KIND,\n POS_CELLULAR_CHARGES_COLLECTION,\n POS_CELLULAR_READERS_COLLECTION,\n POS_CELLULAR_SETTLED_STATES,\n type PosCellularCharge,\n type PosCellularChargeState,\n type PosCellularConfig,\n type PosCellularReaderRecord,\n type PosCellularSuspension,\n} from '../model/pos-cellular'\nimport {\n posCellularInvoiceStatus,\n settleSuspendedPosCellularCharge,\n turnOffPosCellularConfiguration,\n} from './pos-cellular'\n\n/*==========================================\n * THE MONTHLY 4G CHARGE (AGL-4038).\n *\n * Once a day, for the calendar month that has just ended, each workspace\n * whose Stripe Reader S710s had 4G at any time in it is charged once: Stripe's\n * price per reader, plus what collecting it costs (`posCellularChargeCents`),\n * on a one-off invoice to its card through core's usage-invoice charge, the\n * path domains and AI overages take. That is the month Stripe bills the\n * platform for, in arrears, so a reader turned off on the 3rd is charged for\n * that month and not the next.\n *\n * Once per workspace per month: `posCellularCharges/{orgId}_{month}` is\n * claimed in a transaction before Stripe is called, and the invoice's\n * idempotency key is the same pair, so a run that died mid-charge and the\n * next day's run land on the same invoice. A charge that did not collect is\n * left open on the workspace's Billing page (nothing retries it) and staff\n * are alerted; a workspace with no one to bill is recorded and alerted, and\n * never charged later for that month.\n *\n * Daily rather than monthly: a month whose charge failed to START (Stripe\n * unreachable) is retried the next day; one that settled costs a read.\n *\n * A STORE THAT IS GONE stops costing the platform: a reader record whose\n * store no longer exists has its period closed and the store's Configuration\n * told to turn cellular off; a workspace being erased does the same for all\n * of its stores first ({@link posCellularOrgEraser}).\n *\n * WARN, THEN TURN OFF. A charge left open is asked about each day: paid\n * since, it is settled as paid; voided by staff, as voided. The first time\n * Stripe says it is still unpaid (the same run that left it open, unless\n * Stripe could not be asked), the members who manage the workspace's billing\n * are warned, once (`warnedAtMs`), of the amount and of the day 4G turns off\n * unless it is paid; paid before then, nothing else is sent. Still unpaid\n * once the grace period (`POS_CELLULAR_GRACE_DAYS`, 14 by default) has run\n * from the day it was left open, 4G is turned off at Stripe for every store\n * of the workspace, the members who manage its billing are emailed and\n * notified again, and staff are alerted. Stripe that cannot be asked is never\n * read as unpaid.\n * Paying does not turn 4G back on: the merchant does, once it is paid\n * (`pos-cellular.ts` refuses it until then). Each step is idempotent, so a run\n * that dies half-way is finished by the next.\n *\n * A WORKSPACE DELETED MID-MONTH is charged for that final month as it is\n * erased, before its data goes, through the same claim as the monthly run\n * (and last month too, if the run had not charged it yet), so the two never\n * charge one month twice. A failure there alerts staff and never holds the\n * erasure.\n *=========================================*/\n\nconst LABEL = '[pos-cellular] billing'\n\n/** A charge claimed this long ago and not settled was abandoned by its run. */\nconst CLAIM_STALE_MS = 30 * 60 * 1000\n\n/** How many times a charge that never reached Stripe is tried before staff hear of it. */\nconst ALERT_AFTER_ATTEMPTS = 3\n\ntype Charge = (request: OrgUsageInvoiceRequest) => Promise<OrgUsageInvoiceResult>\n\ntype InvoiceStatus = (invoiceId: string) => Promise<{ status: string; amountPaidCents: number } | null>\n\nexport interface PosCellularBillingDeps {\n now?: () => number\n config?: PosCellularConfig | null\n charge?: Charge\n readBilling?: (orgId: string) => Promise<{ stripeCustomerId?: unknown }>\n turnOff?: (configurationId: string) => Promise<boolean>\n alert?: typeof raiseOperatorAlert\n /** Stripe's word on a charge's invoice now, or null when it cannot be asked. */\n invoiceStatus?: InvoiceStatus\n /** Tells the workspace 4G was turned off; true once told (or there is nobody to tell). */\n notify?: (notice: import('./pos-cellular-notify').PosCellularTurnedOffNotice) => Promise<boolean>\n /** Warns the workspace 4G turns off unless the charge is paid; true once told (or there is nobody to tell). */\n warn?: (notice: import('./pos-cellular-notify').PosCellularPaymentDueNotice) => Promise<boolean>\n}\n\nexport interface PosCellularBillingReport {\n month: string | null\n workspaces: number\n paid: number\n open: number\n failed: number\n unbillable: number\n deferred: number\n storesGone: number\n /** Open charges paid since, found by asking Stripe. */\n paidLate: number\n /** Workspaces warned that 4G turns off unless a charge left open is paid. */\n warned: number\n /** Workspaces whose 4G was turned off for a month unpaid past its grace. */\n turnedOff: number\n}\n\nfunction firestore() {\n return firebaseAdmin.app().firestore()\n}\n\nfunction recordsRef() {\n return firestore().collection(POS_CELLULAR_READERS_COLLECTION)\n}\n\nfunction chargesRef() {\n return firestore().collection(POS_CELLULAR_CHARGES_COLLECTION)\n}\n\n/** A workspace's charge for one month, `{orgId}_{month}`: one per pair, so a rerun finds it. */\nfunction posCellularChargeId(orgId: string, month: string): string {\n return `${orgId}_${month}`\n}\n\n/** The reader records that may count for a month: on now, or turned off since it began. */\nasync function recordsForMonth(startMs: number): Promise<Array<{ id: string; record: PosCellularReaderRecord }>> {\n const [on, off] = await Promise.all([\n recordsRef().where('enabled', '==', true).limit(1_000).get(),\n recordsRef().where('disabledAtMs', '>=', startMs).limit(1_000).get(),\n ])\n const byId = new Map<string, PosCellularReaderRecord>()\n for (const doc of [...on.docs, ...off.docs] as unknown as Array<{ id: string; data: () => PosCellularReaderRecord }>) {\n byId.set(String(doc.id), doc.data())\n }\n return [...byId].map(([id, record]) => ({ id, record }))\n}\n\n/**\n * Closes the records of stores that no longer exist and turns cellular off\n * on their Configuration, alerting staff when Stripe refuses. Returns how\n * many stores it found gone.\n */\nasync function closeGoneStores(\n records: ReadonlyArray<{ id: string; record: PosCellularReaderRecord }>,\n deps: Required<Pick<PosCellularBillingDeps, 'turnOff' | 'alert'>>,\n now: number,\n): Promise<number> {\n const open = records.filter(({ record }) => record.enabled)\n const hostIds = [...new Set(open.map(({ record }) => record.hostId))]\n let gone = 0\n for (const hostId of hostIds) {\n const host = await firestore().collection('hosts').doc(hostId).get()\n if (host.exists) continue\n gone += 1\n const mine = open.filter(({ record }) => record.hostId === hostId)\n await turnOffConfigurations(mine.map(({ record }) => record), deps)\n for (const { id, record } of mine) await recordsRef().doc(id).set(closePosCellularPeriod(record, now))\n }\n return gone\n}\n\n/** Turns cellular off on each distinct Configuration the records name, alerting a refusal. */\nasync function turnOffConfigurations(\n records: ReadonlyArray<PosCellularReaderRecord>,\n deps: Required<Pick<PosCellularBillingDeps, 'turnOff' | 'alert'>>,\n): Promise<{ off: number; failed: number }> {\n const configurations = new Map<string, PosCellularReaderRecord>()\n for (const record of records) {\n if (record.stripeConfigurationId) configurations.set(record.stripeConfigurationId, record)\n }\n let off = 0\n let failed = 0\n for (const [configurationId, record] of configurations) {\n const done = await deps.turnOff(configurationId).catch(() => false)\n if (done) {\n off += 1\n continue\n }\n failed += 1\n await deps\n .alert(COMMERCE_POS_CELLULAR_TURN_OFF_FAILED, {\n dedupeKey: configurationId,\n orgId: record.orgId,\n hostId: record.hostId,\n context: { configurationId, hostId: record.hostId, orgId: record.orgId },\n })\n .catch((error: unknown) => console.error(`${LABEL}: the turn-off alert was not raised`, configurationId, error))\n }\n return { off, failed }\n}\n\n/**\n * Claims a workspace's month for this run, or says it is not this run's:\n * settled already, or claimed by a run still within its window. The claim\n * counts the attempt.\n */\nasync function claimMonth(\n orgId: string,\n month: string,\n readers: number,\n amountCents: number,\n now: number,\n): Promise<{ attempts: number } | null> {\n const ref = chargesRef().doc(posCellularChargeId(orgId, month))\n return firestore().runTransaction(async (transaction: any) => {\n const snapshot = await transaction.get(ref)\n const existing = snapshot.exists ? (snapshot.data() as PosCellularCharge) : null\n if (existing && POS_CELLULAR_SETTLED_STATES.includes(existing.state)) return null\n if (existing?.state === 'charging' && now - existing.updatedAtMs < CLAIM_STALE_MS) return null\n const attempts = (existing?.attempts ?? 0) + 1\n const claim: PosCellularCharge = {\n orgId,\n month,\n // The figures of the FIRST attempt stand: the invoice's key is the\n // month's, and Stripe refuses a key reused with other parameters.\n readers: existing?.readers ?? readers,\n amountCents: existing?.amountCents ?? amountCents,\n state: 'charging',\n invoiceId: existing?.invoiceId ?? null,\n paidCents: 0,\n attempts,\n createdAtMs: existing?.createdAtMs ?? now,\n updatedAtMs: now,\n }\n transaction.set(ref, claim)\n return { attempts }\n })\n}\n\nasync function settleMonth(\n orgId: string,\n month: string,\n patch: {\n state: PosCellularChargeState\n invoiceId?: string | null\n paidCents?: number\n openedAtMs?: number\n final?: boolean\n },\n now: number,\n): Promise<void> {\n await chargesRef()\n .doc(posCellularChargeId(orgId, month))\n .set({ ...patch, updatedAtMs: now }, { merge: true })\n}\n\ntype ChargeOutcome = 'paid' | 'open' | 'failed' | 'unbillable' | 'settled'\n\n/**\n * Charges one workspace's month once: claimed in a transaction first, so the\n * monthly run and a workspace erasure never both charge it, and keyed by the\n * month so a retried run lands on the same invoice. `final` marks the charge\n * an erasure made, which alerts staff at once on a failure, since nothing\n * retries it.\n */\nasync function chargeWorkspaceMonth(\n input: { orgId: string; month: string; readers: number; final?: boolean },\n context: {\n config: PosCellularConfig\n now: number\n charge: Charge\n readBilling: NonNullable<PosCellularBillingDeps['readBilling']>\n alert: typeof raiseOperatorAlert\n },\n): Promise<ChargeOutcome> {\n const { orgId, month, readers } = input\n const { config, now, alert } = context\n const amountCents = posCellularChargeCents(readers, config)\n const claim = await claimMonth(orgId, month, readers, amountCents, now)\n if (!claim) return 'settled'\n const stored = (await chargesRef().doc(posCellularChargeId(orgId, month)).get()).data() as PosCellularCharge\n const final = input.final ? { final: true } : {}\n const raise = (reason: string) =>\n alert(COMMERCE_POS_CELLULAR_CHARGE_FAILED, {\n dedupeKey: posCellularChargeId(orgId, month),\n orgId,\n context: {\n orgId,\n month: posCellularMonthLabel(month),\n readers: String(stored.readers),\n amount: formatOperatorAlertAmount(stored.amountCents),\n reason: input.final ? `${reason} (charged as the workspace was deleted)` : reason,\n },\n }).catch((error: unknown) => console.error(`${LABEL}: the alert was not raised`, orgId, error))\n\n const org = await firestore().collection('orgs').doc(orgId).get()\n if (!org.exists) {\n await settleMonth(orgId, month, { state: 'no-workspace', ...final }, now)\n if (input.final) await raise('the workspace was already gone')\n return 'unbillable'\n }\n if (stored.amountCents < USAGE_INVOICE_MIN_CHARGE_CENTS) {\n await settleMonth(orgId, month, { state: 'below-minimum', ...final }, now)\n return 'unbillable'\n }\n const billing = await context.readBilling(orgId).catch(() => ({}) as { stripeCustomerId?: unknown })\n const stripeCustomerId = String(billing.stripeCustomerId ?? '')\n if (!stripeCustomerId) {\n await settleMonth(orgId, month, { state: 'no-customer', ...final }, now)\n await raise('the workspace has no payment method on file')\n return 'unbillable'\n }\n const label = posCellularMonthLabel(month)\n const result = await context\n .charge({\n orgId,\n stripeCustomerId,\n productId: config.productId,\n amountCents: stored.amountCents,\n currency: 'usd',\n description: `4G for ${stored.readers} Stripe Reader S710 card reader${stored.readers === 1 ? '' : 's'}, ${label}`,\n metadata: {\n orgId,\n pluginId: BUNDLE_ID,\n kind: POS_CELLULAR_CHARGE_KIND,\n month,\n readers: String(stored.readers),\n },\n idempotencyKey: `pos-cellular-${orgId}-${month}`,\n })\n .catch(\n (error: unknown): OrgUsageInvoiceResult => ({\n ok: false,\n invoiceId: null,\n status: null,\n totalCents: 0,\n amountPaidCents: 0,\n requiresAction: false,\n error: error instanceof Error ? error.message : 'the charge threw',\n }),\n )\n if (result.ok) {\n await settleMonth(orgId, month, { state: 'paid', invoiceId: result.invoiceId, paidCents: result.amountPaidCents, ...final }, now)\n return 'paid'\n }\n if (result.invoiceId) {\n // The invoice stays open on their Billing page, where they can pay it;\n // the grace period runs from today.\n await settleMonth(orgId, month, { state: 'open', invoiceId: result.invoiceId, openedAtMs: now, ...final }, now)\n await raise(result.requiresAction ? 'the card needs the cardholder to authenticate' : result.error || 'the card was declined')\n return 'open'\n }\n await settleMonth(orgId, month, { state: 'failed', ...final }, now)\n console.error(`${LABEL}: the charge did not reach Stripe`, orgId, month, result.error)\n // Nothing retries a charge made at erasure: staff hear of it now.\n if (input.final || claim.attempts >= ALERT_AFTER_ATTEMPTS) await raise(result.error || 'Stripe did not answer')\n return 'failed'\n}\n\n/** The charge of every workspace whose readers had 4G last month, once each. */\nexport async function runPosCellularBilling(\n gate: PluginJobHostGate,\n deps: PosCellularBillingDeps = {},\n): Promise<PosCellularBillingReport> {\n const config = deps.config === undefined ? parsePosCellularConfig(process.env) : deps.config\n const now = (deps.now ?? Date.now)()\n const report: PosCellularBillingReport = {\n month: null,\n workspaces: 0,\n paid: 0,\n open: 0,\n failed: 0,\n unbillable: 0,\n deferred: 0,\n storesGone: 0,\n paidLate: 0,\n warned: 0,\n turnedOff: 0,\n }\n if (!config) return report\n const charge = deps.charge ?? ((request: OrgUsageInvoiceRequest) => chargeOrgUsageInvoice(request))\n const readBilling = deps.readBilling ?? ((orgId: string) => readOrgBilling(orgId) as Promise<{ stripeCustomerId?: unknown }>)\n const alert = deps.alert ?? raiseOperatorAlert\n const turnOff = deps.turnOff ?? turnOffPosCellularConfiguration\n\n const month = posCellularPreviousMonthKey(now)\n report.month = month\n const bounds = posCellularMonthBounds(month) as { startMs: number; endMs: number }\n const records = await recordsForMonth(bounds.startMs)\n report.storesGone = await closeGoneStores(records, { turnOff, alert }, now)\n\n const byOrg = posCellularReadersByWorkspace(\n records.map(({ record }) => record),\n month,\n )\n report.workspaces = byOrg.size\n for (const [orgId, { readers, hostIds }] of byOrg) {\n // A store locked for security or abuse is charged nothing while it is:\n // its card may be the stolen one the lock is about. Tried again daily.\n const locked = await Promise.all(hostIds.map((hostId) => gate.isLocked(hostId).catch(() => true)))\n if (locked.some(Boolean)) {\n report.deferred += 1\n continue\n }\n const outcome = await chargeWorkspaceMonth({ orgId, month, readers }, { config, now, charge, readBilling, alert })\n if (outcome === 'paid') report.paid += 1\n else if (outcome === 'open') report.open += 1\n else if (outcome === 'failed') report.failed += 1\n else if (outcome === 'unbillable') report.unbillable += 1\n }\n\n const grace = await enforcePosCellularGrace({\n config,\n now,\n alert,\n turnOff,\n invoiceStatus: deps.invoiceStatus ?? posCellularInvoiceStatus,\n notify:\n deps.notify ??\n (async (notice) => (await import('./pos-cellular-notify')).sendPosCellularTurnedOffNotice(notice)),\n warn:\n deps.warn ??\n (async (notice) => (await import('./pos-cellular-notify')).sendPosCellularPaymentDueNotice(notice)),\n })\n report.paidLate = grace.paidLate\n report.warned = grace.warned\n report.turnedOff = grace.turnedOff\n return report\n}\n\n/**\n * WARN, THEN TURN OFF (AGL-4038): every charge left open is asked about at\n * Stripe; paid or voided since, it is settled so; still unpaid within its\n * grace, the workspace is warned once of the day 4G turns off; still unpaid\n * past it, 4G goes off for the workspace. A charge already suspended is\n * finished if a run died half-way (a store still on, nobody told yet) and\n * settled once paid.\n */\nasync function enforcePosCellularGrace(context: {\n config: PosCellularConfig\n now: number\n alert: typeof raiseOperatorAlert\n turnOff: (configurationId: string) => Promise<boolean>\n invoiceStatus: InvoiceStatus\n notify: NonNullable<PosCellularBillingDeps['notify']>\n warn: NonNullable<PosCellularBillingDeps['warn']>\n}): Promise<{ paidLate: number; warned: number; turnedOff: number }> {\n const { config, now } = context\n let paidLate = 0\n let warned = 0\n let turnedOff = 0\n for (const state of ['open', 'suspended'] as const) {\n const snapshot = await chargesRef().where('state', '==', state).limit(200).get()\n for (const doc of snapshot.docs as unknown as Array<{ id: string; data: () => PosCellularCharge }>) {\n const id = String(doc.id)\n const stored = doc.data()\n const invoice = stored.invoiceId ? await context.invoiceStatus(stored.invoiceId).catch(() => null) : null\n if (invoice?.status === 'paid' || invoice?.status === 'void') {\n const settled = invoice.status === 'paid' ? 'paid' : 'voided'\n if (state === 'suspended') {\n await settleSuspendedPosCellularCharge(id, stored, settled, invoice.amountPaidCents, now)\n } else {\n await settleMonth(stored.orgId, stored.month, { state: settled, ...(settled === 'paid' ? { paidCents: invoice.amountPaidCents } : {}) }, now)\n }\n if (settled === 'paid') paidLate += 1\n continue\n }\n // Stripe could not be asked: never read as unpaid.\n if (!invoice) continue\n if (state === 'open') {\n if (!posCellularOverdue(stored, config.graceDays, now)) {\n if (posCellularWarningDue(stored) && (await warnPaymentDue(id, context))) warned += 1\n continue\n }\n const claimed = await claimSuspension(id, now)\n if (!claimed) continue\n turnedOff += 1\n await context\n .alert(COMMERCE_POS_CELLULAR_TURNED_OFF_UNPAID, {\n dedupeKey: id,\n orgId: stored.orgId,\n context: {\n orgId: stored.orgId,\n month: posCellularMonthLabel(stored.month),\n amount: formatOperatorAlertAmount(stored.amountCents),\n graceDays: String(config.graceDays),\n },\n })\n .catch((error: unknown) => console.error(`${LABEL}: the turned-off alert was not raised`, id, error))\n }\n await finishSuspension(id, { ...stored, state: 'suspended', suspendedAtMs: stored.suspendedAtMs ?? now }, context)\n }\n }\n return { paidLate, warned, turnedOff }\n}\n\n/**\n * Claims the warning of an open charge, once: the charge as it stood, or null\n * when a run already warned of it or it is no longer open. The day its grace\n * counts from is pinned with the claim, so the day the warning states is the\n * day the turn-off keeps, even for a charge from before that day was stored.\n */\nasync function claimWarning(id: string, now: number): Promise<PosCellularCharge | null> {\n const ref = chargesRef().doc(id)\n return firestore().runTransaction(async (transaction: any) => {\n const snapshot = await transaction.get(ref)\n const charge = snapshot.exists ? (snapshot.data() as PosCellularCharge) : null\n if (!charge || !posCellularWarningDue(charge)) return null\n const openedAtMs = Number(charge.openedAtMs ?? charge.updatedAtMs)\n transaction.set(ref, { warnedAtMs: now, openedAtMs, updatedAtMs: now }, { merge: true })\n return { ...charge, openedAtMs }\n })\n}\n\n/**\n * WARN AT THE START (AGL-4038): the members who manage the workspace's\n * billing are told the charge is due and the day 4G turns off for its stores\n * unless it is paid. Claimed before it is sent, so two runs never both send\n * it; a warning nobody could be sent is released for the next run to try.\n */\nasync function warnPaymentDue(\n id: string,\n context: { config: PosCellularConfig; now: number; warn: NonNullable<PosCellularBillingDeps['warn']> },\n): Promise<boolean> {\n const { config, now } = context\n const charge = await claimWarning(id, now)\n if (!charge) return false\n const told = await (async () => {\n // The stores that have 4G now, which lose it on that day.\n const snapshot = await recordsRef().where('orgId', '==', charge.orgId).where('enabled', '==', true).limit(500).get()\n const hostIds = [\n ...new Set(\n (snapshot.docs as unknown as Array<{ data: () => PosCellularReaderRecord }>).map((doc) => doc.data().hostId),\n ),\n ]\n return context.warn({\n orgId: charge.orgId,\n month: charge.month,\n amount: formatOperatorAlertAmount(charge.amountCents),\n readers: charge.readers,\n openedAtMs: Number(charge.openedAtMs),\n turnsOffAtMs: posCellularGraceEndsAtMs(charge, config.graceDays),\n hostIds,\n })\n })().catch((error: unknown) => {\n console.error(`${LABEL}: the payment-due warning was not sent`, id, error)\n return false\n })\n if (!told) await chargesRef().doc(id).set({ warnedAtMs: null, updatedAtMs: now }, { merge: true })\n return told\n}\n\n/** Moves an open charge to `suspended`, once: false when a run already did, or it is no longer open. */\nasync function claimSuspension(id: string, now: number): Promise<boolean> {\n const ref = chargesRef().doc(id)\n return firestore().runTransaction(async (transaction: any) => {\n const snapshot = await transaction.get(ref)\n if (!snapshot.exists || (snapshot.data() as PosCellularCharge).state !== 'open') return false\n transaction.set(ref, { state: 'suspended', suspendedAtMs: now, updatedAtMs: now }, { merge: true })\n return true\n })\n}\n\n/**\n * 4G off at Stripe for every store of the workspace that still has it, each\n * store's settings saying why, its readers' periods closed, and the workspace\n * told once. Safe to run again: a store already off and a notice already\n * sent are left alone.\n */\nasync function finishSuspension(\n id: string,\n charge: PosCellularCharge,\n context: {\n now: number\n alert: typeof raiseOperatorAlert\n turnOff: (configurationId: string) => Promise<boolean>\n notify: NonNullable<PosCellularBillingDeps['notify']>\n },\n): Promise<void> {\n const { now } = context\n const snapshot = await recordsRef().where('orgId', '==', charge.orgId).where('enabled', '==', true).limit(500).get()\n const records = (snapshot.docs as unknown as Array<{ id: string; data: () => PosCellularReaderRecord }>).map(\n (doc) => ({ id: String(doc.id), record: doc.data() }),\n )\n const hostIds = new Set(charge.suspendedHostIds ?? [])\n if (records.length) {\n await turnOffConfigurations(\n records.map(({ record }) => record),\n { turnOff: context.turnOff, alert: context.alert },\n )\n const suspension: PosCellularSuspension = { month: charge.month, invoiceId: charge.invoiceId, atMs: now }\n for (const hostId of new Set(records.map(({ record }) => record.hostId))) {\n hostIds.add(hostId)\n const terminal = firestore().collection('hosts').doc(hostId).collection('terminal').doc('config')\n if (!(await terminal.get()).exists) continue\n await terminal.set(\n { cellularEnabled: false, cellularChangedAtMs: now, cellularChangedBy: 'unpaid', cellularSuspended: suspension },\n { merge: true },\n )\n }\n for (const { id: recordId, record } of records) await recordsRef().doc(recordId).set(closePosCellularPeriod(record, now))\n }\n const patch: Partial<PosCellularCharge> = {}\n if (records.length || hostIds.size !== (charge.suspendedHostIds ?? []).length) patch.suspendedHostIds = [...hostIds]\n if (!charge.noticeSentAtMs) {\n const told = await context.notify({\n orgId: charge.orgId,\n month: charge.month,\n amount: formatOperatorAlertAmount(charge.amountCents),\n readers: charge.readers,\n openedAtMs: Number(charge.openedAtMs ?? charge.updatedAtMs),\n turnedOffAtMs: Number(charge.suspendedAtMs ?? now),\n hostIds: [...hostIds],\n })\n if (told) patch.noticeSentAtMs = now\n }\n // A suspension already finished, and still unpaid, writes nothing.\n if (Object.keys(patch).length) await chargesRef().doc(id).set({ ...patch, updatedAtMs: now }, { merge: true })\n}\n\n/**\n * Commerce's 4G share of a WORKSPACE erasure (AGL-4038), before its data\n * goes:\n *\n * 1. CHARGE IT. The month the workspace is deleted in is charged now, for\n * each S710 that had 4G in it, as the monthly run would have charged it a\n * month later; and last month too, if the run had not charged it yet.\n * Through the run's own claim and key, so the two never charge one month\n * twice. A workspace that is locked is not charged (its card may be the\n * stolen one the lock is about): staff are alerted instead. Any failure\n * alerts staff and goes on.\n * 2. TURN IT OFF. Every store of the workspace with 4G on has cellular turned\n * off at Stripe, so the platform stops paying for readers nobody will be\n * charged for, and their periods are closed.\n *\n * Never fails the erasure: a refusal is a must alert. A dry run only counts.\n */\nexport function createPosCellularOrgEraser(\n deps: Pick<PosCellularBillingDeps, 'turnOff' | 'alert' | 'now' | 'config' | 'charge' | 'readBilling'> = {},\n): PluginOrgEraser {\n return async ({ orgId, dryRun }) => {\n const empty = { cellularStoresTurnedOff: 0, cellularTurnOffFailed: 0, cellularFinalMonthsCharged: 0, cellularFinalChargeFailed: 0 }\n if (!orgId) return empty\n const now = (deps.now ?? Date.now)()\n const alert = deps.alert ?? raiseOperatorAlert\n const snapshot = await recordsRef().where('orgId', '==', orgId).limit(500).get()\n const all = (snapshot.docs as unknown as Array<{ id: string; data: () => PosCellularReaderRecord }>).map((doc) => ({\n id: String(doc.id),\n record: doc.data(),\n }))\n const records = all.filter(({ record }) => record.enabled)\n const stores = new Set(records.map(({ record }) => record.stripeConfigurationId).filter(Boolean)).size\n\n // 1. The final month (and last month, if it is still owed).\n const config = deps.config === undefined ? parsePosCellularConfig(process.env) : deps.config\n // The months with readers that no run has settled yet.\n const months: Array<{ month: string; readers: number }> = []\n for (const month of config ? [posCellularPreviousMonthKey(now), posCellularMonthKey(now)] : []) {\n const readers = posCellularReadersByWorkspace(all.map(({ record }) => record), month).get(orgId)?.readers ?? 0\n if (!readers) continue\n const existing = await chargesRef().doc(posCellularChargeId(orgId, month)).get()\n const state = existing.exists ? (existing.data() as PosCellularCharge).state : null\n if (!state || !POS_CELLULAR_SETTLED_STATES.includes(state)) months.push({ month, readers })\n }\n let charged = 0\n let chargeFailed = 0\n if (dryRun) return { ...empty, cellularStoresTurnedOff: stores, cellularFinalMonthsCharged: months.length }\n if (config && months.length) {\n const org = await firestore().collection('orgs').doc(orgId).get().catch(() => null)\n const locked = org?.exists ? normalizeOrgLockdown(org.data() as never) !== null : false\n for (const { month, readers } of months) {\n try {\n if (locked) {\n chargeFailed += 1\n await alert(COMMERCE_POS_CELLULAR_CHARGE_FAILED, {\n dedupeKey: posCellularChargeId(orgId, month),\n orgId,\n context: {\n orgId,\n month: posCellularMonthLabel(month),\n readers: String(readers),\n amount: formatOperatorAlertAmount(posCellularChargeCents(readers, config)),\n reason: 'the workspace is locked, so it was not charged as it was deleted',\n },\n })\n continue\n }\n const outcome = await chargeWorkspaceMonth(\n { orgId, month, readers, final: true },\n {\n config,\n now,\n charge: deps.charge ?? ((request: OrgUsageInvoiceRequest) => chargeOrgUsageInvoice(request)),\n readBilling:\n deps.readBilling ?? ((id: string) => readOrgBilling(id) as Promise<{ stripeCustomerId?: unknown }>),\n alert,\n },\n )\n if (outcome === 'paid') charged += 1\n else if (outcome !== 'settled') chargeFailed += 1\n } catch (error) {\n chargeFailed += 1\n console.error(`${LABEL}: the final month was not charged`, orgId, month, error)\n await alert(COMMERCE_POS_CELLULAR_CHARGE_FAILED, {\n dedupeKey: posCellularChargeId(orgId, month),\n orgId,\n context: {\n orgId,\n month: posCellularMonthLabel(month),\n readers: String(readers),\n amount: formatOperatorAlertAmount(posCellularChargeCents(readers, config)),\n reason: 'the charge failed as the workspace was deleted',\n },\n }).catch(() => undefined)\n }\n }\n }\n\n // 2. Off at Stripe, so the platform stops paying for it.\n if (!records.length) return { ...empty, cellularFinalMonthsCharged: charged, cellularFinalChargeFailed: chargeFailed }\n const { off, failed } = await turnOffConfigurations(\n records.map(({ record }) => record),\n { turnOff: deps.turnOff ?? turnOffPosCellularConfiguration, alert },\n )\n for (const { id, record } of records) await recordsRef().doc(id).set(closePosCellularPeriod(record, now))\n return {\n cellularStoresTurnedOff: off,\n cellularTurnOffFailed: failed,\n cellularFinalMonthsCharged: charged,\n cellularFinalChargeFailed: chargeFailed,\n }\n }\n}\n\n/** The eraser over the platform's own Firestore and Stripe, as the declarations register it. */\nexport const posCellularOrgEraser: PluginOrgEraser = (request) => createPosCellularOrgEraser()(request)\n"],"names":["normalizeOrgLockdown","formatOperatorAlertAmount","firebaseAdmin","raiseOperatorAlert","readOrgBilling","chargeOrgUsageInvoice","USAGE_INVOICE_MIN_CHARGE_CENTS","BUNDLE_ID","COMMERCE_POS_CELLULAR_CHARGE_FAILED","COMMERCE_POS_CELLULAR_TURN_OFF_FAILED","COMMERCE_POS_CELLULAR_TURNED_OFF_UNPAID","closePosCellularPeriod","parsePosCellularConfig","posCellularChargeCents","posCellularGraceEndsAtMs","posCellularMonthBounds","posCellularMonthKey","posCellularMonthLabel","posCellularOverdue","posCellularPreviousMonthKey","posCellularReadersByWorkspace","posCellularWarningDue","POS_CELLULAR_CHARGE_KIND","POS_CELLULAR_CHARGES_COLLECTION","POS_CELLULAR_READERS_COLLECTION","POS_CELLULAR_SETTLED_STATES","posCellularInvoiceStatus","settleSuspendedPosCellularCharge","turnOffPosCellularConfiguration","LABEL","CLAIM_STALE_MS","ALERT_AFTER_ATTEMPTS","firestore","app","recordsRef","collection","chargesRef","posCellularChargeId","orgId","month","recordsForMonth","startMs","on","off","Promise","all","where","limit","get","byId","Map","doc","docs","set","String","id","data","map","record","closeGoneStores","records","deps","now","open","filter","enabled","hostIds","Set","hostId","gone","host","exists","mine","turnOffConfigurations","configurations","stripeConfigurationId","failed","configurationId","done","turnOff","catch","alert","dedupeKey","context","error","console","claimMonth","readers","amountCents","ref","runTransaction","transaction","snapshot","existing","includes","state","updatedAtMs","attempts","claim","invoiceId","paidCents","createdAtMs","settleMonth","patch","merge","chargeWorkspaceMonth","input","billing","config","stored","final","raise","reason","amount","org","readBilling","stripeCustomerId","label","result","charge","productId","currency","description","metadata","pluginId","kind","idempotencyKey","ok","status","totalCents","amountPaidCents","requiresAction","Error","message","openedAtMs","runPosCellularBilling","gate","undefined","process","env","Date","report","workspaces","paid","unbillable","deferred","storesGone","paidLate","warned","turnedOff","request","bounds","byOrg","size","locked","isLocked","some","Boolean","outcome","grace","enforcePosCellularGrace","invoiceStatus","notify","notice","sendPosCellularTurnedOffNotice","warn","sendPosCellularPaymentDueNotice","invoice","settled","graceDays","warnPaymentDue","claimed","claimSuspension","finishSuspension","suspendedAtMs","claimWarning","Number","warnedAtMs","told","turnsOffAtMs","suspendedHostIds","length","suspension","atMs","add","terminal","cellularEnabled","cellularChangedAtMs","cellularChangedBy","cellularSuspended","recordId","noticeSentAtMs","turnedOffAtMs","Object","keys","createPosCellularOrgEraser","dryRun","empty","cellularStoresTurnedOff","cellularTurnOffFailed","cellularFinalMonthsCharged","cellularFinalChargeFailed","stores","months","push","charged","chargeFailed","posCellularOrgEraser"],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
/** What the warning, the day a charge is left open, says. */
|
|
18
|
+
export interface PosCellularPaymentDueNotice {
|
|
19
|
+
orgId: string;
|
|
20
|
+
month: string;
|
|
21
|
+
/** Formatted, e.g. `$21.65`. */
|
|
22
|
+
amount: string;
|
|
23
|
+
readers: number;
|
|
24
|
+
openedAtMs: number;
|
|
25
|
+
/** When the grace runs out: 4G turns off for the workspace's stores then, unless it is paid. */
|
|
26
|
+
turnsOffAtMs: number;
|
|
27
|
+
/** The stores with 4G on now, which lose it then. */
|
|
28
|
+
hostIds: string[];
|
|
29
|
+
}
|
|
30
|
+
/** What the notice that 4G was turned off says. */
|
|
31
|
+
export interface PosCellularTurnedOffNotice {
|
|
32
|
+
orgId: string;
|
|
33
|
+
month: string;
|
|
34
|
+
/** Formatted, e.g. `$21.65`. */
|
|
35
|
+
amount: string;
|
|
36
|
+
readers: number;
|
|
37
|
+
openedAtMs: number;
|
|
38
|
+
turnedOffAtMs: number;
|
|
39
|
+
hostIds: string[];
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The day a month's charge is left open: it is due, and 4G turns off for the
|
|
43
|
+
* workspace's stores on the day its grace runs out unless it is paid.
|
|
44
|
+
*/
|
|
45
|
+
export declare function sendPosCellularPaymentDueNotice(notice: PosCellularPaymentDueNotice): Promise<boolean>;
|
|
46
|
+
/** The day 4G was turned off for the workspace's stores because a month's charge stayed unpaid. */
|
|
47
|
+
export declare function sendPosCellularTurnedOffNotice(notice: PosCellularTurnedOffNotice): Promise<boolean>;
|
|
@@ -0,0 +1,150 @@
|
|
|
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 { isAccountBanLockdownReason, normalizeOrgLockdown } from "@aglyn/aglyn/app-utils/lockdown";
|
|
19
|
+
import { platformConsoleOrigin } from "@aglyn/aglyn/app-utils/platform-brand";
|
|
20
|
+
import { POS_CELLULAR_EMAIL_KEYS, sendEmail } from "@aglyn/shared-util-email";
|
|
21
|
+
import { firebaseAdmin, hostDisplayName, listOrgMembers, memberHasOrgPermission, meterPlatformEmail, notifyUsers } from "@aglyn/tenant-data-admin";
|
|
22
|
+
import { filterSuppressedEmails } from "@aglyn/tenant-data-admin/server/email-suppression";
|
|
23
|
+
import { orgSystemEmailBrand, renderSystemEmailContent } from "@aglyn/tenant-data-admin/server/render-system-email";
|
|
24
|
+
import { posCellularDayLabel, posCellularMonthLabel } from "../model/pos-cellular.js";
|
|
25
|
+
/** The workspace as the notices name it; null for a banned account, which is sent nothing (AGL-3420). */ async function readWorkspace(firestore, orgId) {
|
|
26
|
+
var _ref, _ref1, _ref2;
|
|
27
|
+
const org = await firestore.collection('orgs').doc(orgId).get().catch(()=>null);
|
|
28
|
+
const data = (_ref = org == null ? void 0 : org.data()) != null ? _ref : null;
|
|
29
|
+
const lock = normalizeOrgLockdown(data);
|
|
30
|
+
if (lock && isAccountBanLockdownReason(lock.reason)) return null;
|
|
31
|
+
const slug = String((_ref1 = data == null ? void 0 : data['slug']) != null ? _ref1 : '').trim();
|
|
32
|
+
return {
|
|
33
|
+
name: String((_ref2 = data == null ? void 0 : data['name']) != null ? _ref2 : '').trim() || 'your workspace',
|
|
34
|
+
billingPath: slug ? `/${slug}/billing` : '/billing',
|
|
35
|
+
timeZone: resolveSiteTimeZone(data, null)
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/** The stores' names, one per line, or `fallback` when none is left. */ async function storeNames(firestore, hostIds, fallback) {
|
|
39
|
+
const hosts = await Promise.all(hostIds.map((hostId)=>firestore.collection('hosts').doc(hostId).get().catch(()=>null)));
|
|
40
|
+
const names = hosts.map((host, index)=>(host == null ? void 0 : host.exists) ? hostDisplayName(host.data(), hostIds[index]) : null).filter((name)=>Boolean(name));
|
|
41
|
+
return names.join('\n') || fallback;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Emails the members who hold "Manage billing" and puts the same words in
|
|
45
|
+
* their console feed. True once someone was emailed, or nobody can be.
|
|
46
|
+
*/ async function tellBillingManagers(orgId, workspace, message) {
|
|
47
|
+
// Whoever may pay it: the workspace's "Manage billing" key, not a role.
|
|
48
|
+
const members = await listOrgMembers(orgId);
|
|
49
|
+
const managers = (await Promise.all(members.map(async (member)=>await memberHasOrgPermission(orgId, member, 'billing.manage').catch(()=>false) ? member : null))).filter((member)=>member !== null);
|
|
50
|
+
const addresses = managers.map((member)=>{
|
|
51
|
+
var _member_email;
|
|
52
|
+
return String((_member_email = member.email) != null ? _member_email : '').trim();
|
|
53
|
+
}).filter(Boolean);
|
|
54
|
+
const recipients = await filterSuppressedEmails(addresses);
|
|
55
|
+
let told = false;
|
|
56
|
+
if (recipients.length) {
|
|
57
|
+
const brand = await orgSystemEmailBrand(orgId);
|
|
58
|
+
const content = await renderSystemEmailContent(message.key, message.merge, brand, {
|
|
59
|
+
subject: message.title,
|
|
60
|
+
text: `${message.title}\n\n${message.body}\n\n${message.merge['cellular.billingUrl']}`
|
|
61
|
+
});
|
|
62
|
+
const results = await Promise.all(recipients.map((to)=>sendEmail(_extends({
|
|
63
|
+
to
|
|
64
|
+
}, content, brand.fromName ? {
|
|
65
|
+
fromName: brand.fromName
|
|
66
|
+
} : {}, {
|
|
67
|
+
context: message.key
|
|
68
|
+
}))));
|
|
69
|
+
const sent = results.filter((result)=>result.sent).length;
|
|
70
|
+
await meterPlatformEmail(sent);
|
|
71
|
+
told = sent > 0;
|
|
72
|
+
}
|
|
73
|
+
await notifyUsers(managers.map((member)=>{
|
|
74
|
+
var _member_$id;
|
|
75
|
+
return String((_member_$id = member.$id) != null ? _member_$id : '');
|
|
76
|
+
}).filter(Boolean), {
|
|
77
|
+
type: 'billing.paymentFailed',
|
|
78
|
+
title: message.title,
|
|
79
|
+
body: message.body,
|
|
80
|
+
level: 'warning',
|
|
81
|
+
link: workspace.billingPath,
|
|
82
|
+
orgId
|
|
83
|
+
}, // The designed email above is the email; the notification is the feed.
|
|
84
|
+
{
|
|
85
|
+
skipEmail: true
|
|
86
|
+
});
|
|
87
|
+
return told || recipients.length === 0;
|
|
88
|
+
}
|
|
89
|
+
const readersText = (readers)=>`${readers} Stripe Reader S710${readers === 1 ? '' : 's'}`;
|
|
90
|
+
/**
|
|
91
|
+
* The day a month's charge is left open: it is due, and 4G turns off for the
|
|
92
|
+
* workspace's stores on the day its grace runs out unless it is paid.
|
|
93
|
+
*/ export async function sendPosCellularPaymentDueNotice(notice) {
|
|
94
|
+
try {
|
|
95
|
+
const firestore = firebaseAdmin.app().firestore();
|
|
96
|
+
const workspace = await readWorkspace(firestore, notice.orgId);
|
|
97
|
+
if (!workspace) return false;
|
|
98
|
+
const month = posCellularMonthLabel(notice.month);
|
|
99
|
+
const turnsOffOn = posCellularDayLabel(notice.turnsOffAtMs, workspace.timeZone);
|
|
100
|
+
const merge = {
|
|
101
|
+
'org.name': workspace.name,
|
|
102
|
+
'cellular.month': month,
|
|
103
|
+
'cellular.amount': notice.amount,
|
|
104
|
+
'cellular.readers': readersText(notice.readers),
|
|
105
|
+
'cellular.openedOn': posCellularDayLabel(notice.openedAtMs, workspace.timeZone),
|
|
106
|
+
'cellular.turnsOffOn': turnsOffOn,
|
|
107
|
+
// Blank when no store has 4G now: the email then leaves the row out.
|
|
108
|
+
'cellular.stores': await storeNames(firestore, notice.hostIds, ''),
|
|
109
|
+
'cellular.billingUrl': `${platformConsoleOrigin()}${workspace.billingPath}`
|
|
110
|
+
};
|
|
111
|
+
return await tellBillingManagers(notice.orgId, workspace, {
|
|
112
|
+
key: POS_CELLULAR_EMAIL_KEYS.paymentDue,
|
|
113
|
+
merge,
|
|
114
|
+
title: `4G turns off on ${turnsOffOn} unless the ${month} charge is paid`,
|
|
115
|
+
body: `The 4G charge of ${notice.amount} for ${month} didn’t go through. ` + `Pay it on the Billing page before ${turnsOffOn} to keep 4G on for your stores.`
|
|
116
|
+
});
|
|
117
|
+
} catch (error) {
|
|
118
|
+
console.error('[pos-cellular] the payment-due notice failed', notice.orgId, notice.month, error);
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/** The day 4G was turned off for the workspace's stores because a month's charge stayed unpaid. */ export async function sendPosCellularTurnedOffNotice(notice) {
|
|
123
|
+
try {
|
|
124
|
+
const firestore = firebaseAdmin.app().firestore();
|
|
125
|
+
const workspace = await readWorkspace(firestore, notice.orgId);
|
|
126
|
+
if (!workspace) return false;
|
|
127
|
+
const month = posCellularMonthLabel(notice.month);
|
|
128
|
+
const merge = {
|
|
129
|
+
'org.name': workspace.name,
|
|
130
|
+
'cellular.month': month,
|
|
131
|
+
'cellular.amount': notice.amount,
|
|
132
|
+
'cellular.readers': readersText(notice.readers),
|
|
133
|
+
'cellular.openedOn': posCellularDayLabel(notice.openedAtMs, workspace.timeZone),
|
|
134
|
+
'cellular.turnedOffOn': posCellularDayLabel(notice.turnedOffAtMs, workspace.timeZone),
|
|
135
|
+
'cellular.stores': await storeNames(firestore, notice.hostIds, 'Your stores'),
|
|
136
|
+
'cellular.billingUrl': `${platformConsoleOrigin()}${workspace.billingPath}`
|
|
137
|
+
};
|
|
138
|
+
return await tellBillingManagers(notice.orgId, workspace, {
|
|
139
|
+
key: POS_CELLULAR_EMAIL_KEYS.turnedOffUnpaid,
|
|
140
|
+
merge,
|
|
141
|
+
title: `4G is off for your card readers: the ${month} charge is unpaid`,
|
|
142
|
+
body: `The 4G charge of ${notice.amount} for ${month} is still unpaid, so 4G was turned off for your stores. ` + 'Pay it on the Billing page, then turn 4G on again from each store’s POS devices card.'
|
|
143
|
+
});
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.error('[pos-cellular] the turned-off notice failed', notice.orgId, notice.month, error);
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
//# sourceMappingURL=pos-cellular-notify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/pos-cellular-notify.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 { isAccountBanLockdownReason, normalizeOrgLockdown } from '@aglyn/aglyn/app-utils/lockdown'\nimport { platformConsoleOrigin } from '@aglyn/aglyn/app-utils/platform-brand'\nimport { POS_CELLULAR_EMAIL_KEYS, sendEmail } from '@aglyn/shared-util-email'\nimport {\n firebaseAdmin,\n hostDisplayName,\n listOrgMembers,\n memberHasOrgPermission,\n meterPlatformEmail,\n notifyUsers,\n} from '@aglyn/tenant-data-admin'\nimport { filterSuppressedEmails } from '@aglyn/tenant-data-admin/server/email-suppression'\nimport {\n orgSystemEmailBrand,\n renderSystemEmailContent,\n} from '@aglyn/tenant-data-admin/server/render-system-email'\nimport { posCellularDayLabel, posCellularMonthLabel } from '../model/pos-cellular'\n\n/*==========================================\n * TELLING THE WORKSPACE ABOUT AN UNPAID 4G CHARGE (AGL-4038).\n *\n * Twice, from the daily run (`pos-cellular-billing.ts`), to the members who\n * hold \"Manage billing\" (the key, never a role): the designed system email\n * (`pos-cellular-emails.ts` in the email library), and the same words in\n * their console notification feed, without mailing them twice.\n *\n * 1. PAYMENT DUE, the day a month's charge doesn't go through: the amount,\n * the month, and the day 4G turns off for the workspace's stores unless\n * the open invoice is paid, in the workspace's time zone.\n * 2. TURNED OFF, when that day comes and it is still unpaid: the month, the\n * amount, the stores, and the way back.\n *\n * Each returns whether anyone was told (or there was nobody to tell), so the\n * caller records it once. Neither throws: a lost email must not undo the\n * step it reports on or stop the daily run.\n *=========================================*/\n\n/** What the warning, the day a charge is left open, says. */\nexport interface PosCellularPaymentDueNotice {\n orgId: string\n month: string\n /** Formatted, e.g. `$21.65`. */\n amount: string\n readers: number\n openedAtMs: number\n /** When the grace runs out: 4G turns off for the workspace's stores then, unless it is paid. */\n turnsOffAtMs: number\n /** The stores with 4G on now, which lose it then. */\n hostIds: string[]\n}\n\n/** What the notice that 4G was turned off says. */\nexport interface PosCellularTurnedOffNotice {\n orgId: string\n month: string\n /** Formatted, e.g. `$21.65`. */\n amount: string\n readers: number\n openedAtMs: number\n turnedOffAtMs: number\n hostIds: string[]\n}\n\ntype Firestore = ReturnType<ReturnType<typeof firebaseAdmin.app>['firestore']>\n\ninterface Workspace {\n name: string\n billingPath: string\n timeZone: string\n}\n\n/** The workspace as the notices name it; null for a banned account, which is sent nothing (AGL-3420). */\nasync function readWorkspace(firestore: Firestore, orgId: string): Promise<Workspace | null> {\n const org = await firestore.collection('orgs').doc(orgId).get().catch(() => null)\n const data = (org?.data() ?? null) as Record<string, unknown> | null\n const lock = normalizeOrgLockdown(data as never)\n if (lock && isAccountBanLockdownReason(lock.reason)) return null\n const slug = String(data?.['slug'] ?? '').trim()\n return {\n name: String(data?.['name'] ?? '').trim() || 'your workspace',\n billingPath: slug ? `/${slug}/billing` : '/billing',\n timeZone: resolveSiteTimeZone(data as { timeZone?: string } | null, null),\n }\n}\n\n/** The stores' names, one per line, or `fallback` when none is left. */\nasync function storeNames(firestore: Firestore, hostIds: readonly string[], fallback: string): Promise<string> {\n const hosts = await Promise.all(\n hostIds.map((hostId) => firestore.collection('hosts').doc(hostId).get().catch(() => null)),\n )\n const names = hosts\n .map((host, index) =>\n host?.exists ? hostDisplayName(host.data() as Record<string, unknown>, hostIds[index]) : null,\n )\n .filter((name): name is string => Boolean(name))\n return names.join('\\n') || fallback\n}\n\n/**\n * Emails the members who hold \"Manage billing\" and puts the same words in\n * their console feed. True once someone was emailed, or nobody can be.\n */\nasync function tellBillingManagers(\n orgId: string,\n workspace: Workspace,\n message: {\n key: string\n merge: Record<string, string>\n title: string\n body: string\n },\n): Promise<boolean> {\n // Whoever may pay it: the workspace's \"Manage billing\" key, not a role.\n const members = await listOrgMembers(orgId)\n const managers = (\n await Promise.all(\n members.map(async (member) =>\n (await memberHasOrgPermission(orgId, member, 'billing.manage').catch(() => false)) ? member : null,\n ),\n )\n ).filter((member): member is (typeof members)[number] => member !== null)\n const addresses = managers.map((member) => String((member as { email?: unknown }).email ?? '').trim()).filter(Boolean)\n const recipients = await filterSuppressedEmails(addresses)\n let told = false\n if (recipients.length) {\n const brand = await orgSystemEmailBrand(orgId)\n const content = await renderSystemEmailContent(message.key, message.merge, brand, {\n subject: message.title,\n text: `${message.title}\\n\\n${message.body}\\n\\n${message.merge['cellular.billingUrl']}`,\n })\n const results = await Promise.all(\n recipients.map((to) =>\n sendEmail({\n to,\n ...content,\n ...(brand.fromName ? { fromName: brand.fromName } : {}),\n context: message.key,\n }),\n ),\n )\n const sent = results.filter((result) => result.sent).length\n await meterPlatformEmail(sent)\n told = sent > 0\n }\n await notifyUsers(\n managers.map((member) => String((member as { $id?: unknown }).$id ?? '')).filter(Boolean),\n {\n type: 'billing.paymentFailed',\n title: message.title,\n body: message.body,\n level: 'warning',\n link: workspace.billingPath,\n orgId,\n },\n // The designed email above is the email; the notification is the feed.\n { skipEmail: true },\n )\n return told || recipients.length === 0\n}\n\nconst readersText = (readers: number) => `${readers} Stripe Reader S710${readers === 1 ? '' : 's'}`\n\n/**\n * The day a month's charge is left open: it is due, and 4G turns off for the\n * workspace's stores on the day its grace runs out unless it is paid.\n */\nexport async function sendPosCellularPaymentDueNotice(notice: PosCellularPaymentDueNotice): Promise<boolean> {\n try {\n const firestore = firebaseAdmin.app().firestore()\n const workspace = await readWorkspace(firestore, notice.orgId)\n if (!workspace) return false\n const month = posCellularMonthLabel(notice.month)\n const turnsOffOn = posCellularDayLabel(notice.turnsOffAtMs, workspace.timeZone)\n const merge: Record<string, string> = {\n 'org.name': workspace.name,\n 'cellular.month': month,\n 'cellular.amount': notice.amount,\n 'cellular.readers': readersText(notice.readers),\n 'cellular.openedOn': posCellularDayLabel(notice.openedAtMs, workspace.timeZone),\n 'cellular.turnsOffOn': turnsOffOn,\n // Blank when no store has 4G now: the email then leaves the row out.\n 'cellular.stores': await storeNames(firestore, notice.hostIds, ''),\n 'cellular.billingUrl': `${platformConsoleOrigin()}${workspace.billingPath}`,\n }\n return await tellBillingManagers(notice.orgId, workspace, {\n key: POS_CELLULAR_EMAIL_KEYS.paymentDue,\n merge,\n title: `4G turns off on ${turnsOffOn} unless the ${month} charge is paid`,\n body:\n `The 4G charge of ${notice.amount} for ${month} didn’t go through. ` +\n `Pay it on the Billing page before ${turnsOffOn} to keep 4G on for your stores.`,\n })\n } catch (error) {\n console.error('[pos-cellular] the payment-due notice failed', notice.orgId, notice.month, error)\n return false\n }\n}\n\n/** The day 4G was turned off for the workspace's stores because a month's charge stayed unpaid. */\nexport async function sendPosCellularTurnedOffNotice(notice: PosCellularTurnedOffNotice): Promise<boolean> {\n try {\n const firestore = firebaseAdmin.app().firestore()\n const workspace = await readWorkspace(firestore, notice.orgId)\n if (!workspace) return false\n const month = posCellularMonthLabel(notice.month)\n const merge: Record<string, string> = {\n 'org.name': workspace.name,\n 'cellular.month': month,\n 'cellular.amount': notice.amount,\n 'cellular.readers': readersText(notice.readers),\n 'cellular.openedOn': posCellularDayLabel(notice.openedAtMs, workspace.timeZone),\n 'cellular.turnedOffOn': posCellularDayLabel(notice.turnedOffAtMs, workspace.timeZone),\n 'cellular.stores': await storeNames(firestore, notice.hostIds, 'Your stores'),\n 'cellular.billingUrl': `${platformConsoleOrigin()}${workspace.billingPath}`,\n }\n return await tellBillingManagers(notice.orgId, workspace, {\n key: POS_CELLULAR_EMAIL_KEYS.turnedOffUnpaid,\n merge,\n title: `4G is off for your card readers: the ${month} charge is unpaid`,\n body:\n `The 4G charge of ${notice.amount} for ${month} is still unpaid, so 4G was turned off for your stores. ` +\n 'Pay it on the Billing page, then turn 4G on again from each store’s POS devices card.',\n })\n } catch (error) {\n console.error('[pos-cellular] the turned-off notice failed', notice.orgId, notice.month, error)\n return false\n }\n}\n"],"names":["resolveSiteTimeZone","isAccountBanLockdownReason","normalizeOrgLockdown","platformConsoleOrigin","POS_CELLULAR_EMAIL_KEYS","sendEmail","firebaseAdmin","hostDisplayName","listOrgMembers","memberHasOrgPermission","meterPlatformEmail","notifyUsers","filterSuppressedEmails","orgSystemEmailBrand","renderSystemEmailContent","posCellularDayLabel","posCellularMonthLabel","readWorkspace","firestore","orgId","org","collection","doc","get","catch","data","lock","reason","slug","String","trim","name","billingPath","timeZone","storeNames","hostIds","fallback","hosts","Promise","all","map","hostId","names","host","index","exists","filter","Boolean","join","tellBillingManagers","workspace","message","members","managers","member","addresses","email","recipients","told","length","brand","content","key","merge","subject","title","text","body","results","to","fromName","context","sent","result","$id","type","level","link","skipEmail","readersText","readers","sendPosCellularPaymentDueNotice","notice","app","month","turnsOffOn","turnsOffAtMs","amount","openedAtMs","paymentDue","error","console","sendPosCellularTurnedOffNotice","turnedOffAtMs","turnedOffUnpaid"],"mappings":"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"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import { type PosCellularCharge } from '../model/pos-cellular';
|
|
18
|
+
import type { PosStaff } from './pos-auth';
|
|
19
|
+
/** The workspace key turning 4G on takes, beside "Registers and devices". */
|
|
20
|
+
export declare const POS_CELLULAR_BILLING_PERMISSION = "billing.manage";
|
|
21
|
+
/** What a member without it is told, naming the permission. */
|
|
22
|
+
export declare const POS_CELLULAR_BILLING_REFUSAL = "Your role does not include \"Manage billing\" \u2014 ask an organization admin. 4G is charged to the workspace.";
|
|
23
|
+
/** Whether the member may turn 4G on for a store: the workspace's "Manage billing", resolved for that store. */
|
|
24
|
+
export declare function mayTurnOnPosCellular(uid: string, hostId: string): Promise<boolean>;
|
|
25
|
+
/**
|
|
26
|
+
* A charge's invoice as Stripe has it now: its status and what it collected,
|
|
27
|
+
* or null when Stripe could not be asked (which is never read as "unpaid
|
|
28
|
+
* long enough to act on" nor as "paid").
|
|
29
|
+
*/
|
|
30
|
+
export declare function posCellularInvoiceStatus(invoiceId: string): Promise<{
|
|
31
|
+
status: string;
|
|
32
|
+
amountPaidCents: number;
|
|
33
|
+
} | null>;
|
|
34
|
+
/**
|
|
35
|
+
* The month whose unpaid charge turned 4G off for the workspace and is STILL
|
|
36
|
+
* unpaid, or null. Asks Stripe about each, so one paid since is settled as
|
|
37
|
+
* paid here, and its stores' notices cleared, rather than waiting for the
|
|
38
|
+
* next daily run.
|
|
39
|
+
*/
|
|
40
|
+
export declare function unpaidPosCellularSuspension(orgId: string, now: number, invoiceStatus?: (invoiceId: string) => Promise<{
|
|
41
|
+
status: string;
|
|
42
|
+
amountPaidCents: number;
|
|
43
|
+
} | null>): Promise<{
|
|
44
|
+
month: string;
|
|
45
|
+
} | null>;
|
|
46
|
+
/**
|
|
47
|
+
* A suspended month that was paid (or voided by staff): settled, and the
|
|
48
|
+
* notice on each store it turned 4G off for taken down. 4G stays off until
|
|
49
|
+
* the merchant turns it on again.
|
|
50
|
+
*/
|
|
51
|
+
export declare function settleSuspendedPosCellularCharge(chargeId: string, charge: PosCellularCharge, state: 'paid' | 'voided', paidCents: number, now: number): Promise<void>;
|
|
52
|
+
export interface PosCellularAnswer {
|
|
53
|
+
status: number;
|
|
54
|
+
body: {
|
|
55
|
+
ok: true;
|
|
56
|
+
enabled: boolean;
|
|
57
|
+
} | {
|
|
58
|
+
error: string;
|
|
59
|
+
code?: string;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Opens a 4G period for every S710 the store has while 4G is on, and closes
|
|
64
|
+
* every open one that should not be: 4G off, or the reader gone. In one
|
|
65
|
+
* transaction over the store's records, so two calls at once never open a
|
|
66
|
+
* reader twice. Idempotent, and cheap where the store never had 4G: one
|
|
67
|
+
* read of its settings and one of its (empty) records.
|
|
68
|
+
*/
|
|
69
|
+
export declare function syncPosCellularReaders(input: {
|
|
70
|
+
hostId: string;
|
|
71
|
+
orgId: string;
|
|
72
|
+
now?: number;
|
|
73
|
+
}): Promise<{
|
|
74
|
+
open: number;
|
|
75
|
+
closed: number;
|
|
76
|
+
}>;
|
|
77
|
+
/**
|
|
78
|
+
* `cellular` on the card readers route: turns 4G on (`enabled: true`, with
|
|
79
|
+
* `consent: true`) or off for the caller's store. The route has already
|
|
80
|
+
* checked the "Registers and devices" key on the store.
|
|
81
|
+
*/
|
|
82
|
+
export declare function setPosStoreCellular(staff: PosStaff, body: Record<string, unknown>): Promise<PosCellularAnswer>;
|
|
83
|
+
/**
|
|
84
|
+
* Turns 4G off at Stripe on a store's Configuration, by its id: for a store
|
|
85
|
+
* or workspace that is being deleted, whose settings may be gone already.
|
|
86
|
+
* True when Stripe took it, or the Configuration no longer exists.
|
|
87
|
+
*/
|
|
88
|
+
export declare function turnOffPosCellularConfiguration(configurationId: string): Promise<boolean>;
|