@aglyn/plugins-commerce 1.0.0-beta.232 → 1.0.0-beta.234

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.
Files changed (228) hide show
  1. package/package.json +13 -13
  2. package/src/lib/components/cart-extras.d.ts +6 -0
  3. package/src/lib/components/cart-extras.js +4 -1
  4. package/src/lib/components/cart-extras.js.map +1 -1
  5. package/src/lib/components/cart-fulfillment.d.ts +117 -0
  6. package/src/lib/components/cart-fulfillment.js +367 -0
  7. package/src/lib/components/cart-fulfillment.js.map +1 -0
  8. package/src/lib/components/cart.js +52 -10
  9. package/src/lib/components/cart.js.map +1 -1
  10. package/src/lib/components/commerce-console-page.js +42 -1
  11. package/src/lib/components/commerce-console-page.js.map +1 -1
  12. package/src/lib/components/console/host-orders-card.component.js +38 -10
  13. package/src/lib/components/console/host-orders-card.component.js.map +1 -1
  14. package/src/lib/components/console/local-delivery-settings-card.component.d.ts +37 -0
  15. package/src/lib/components/console/local-delivery-settings-card.component.js +542 -0
  16. package/src/lib/components/console/local-delivery-settings-card.component.js.map +1 -0
  17. package/src/lib/components/console/locations-card.component.js +177 -3
  18. package/src/lib/components/console/locations-card.component.js.map +1 -1
  19. package/src/lib/components/console/order-detail-dialog.component.js +10 -0
  20. package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
  21. package/src/lib/components/console/order-local-fulfillment-panel.component.d.ts +44 -0
  22. package/src/lib/components/console/order-local-fulfillment-panel.component.js +265 -0
  23. package/src/lib/components/console/order-local-fulfillment-panel.component.js.map +1 -0
  24. package/src/lib/components/console/order-offline-notice.component.d.ts +12 -0
  25. package/src/lib/components/console/order-offline-notice.component.js +53 -0
  26. package/src/lib/components/console/order-offline-notice.component.js.map +1 -0
  27. package/src/lib/components/console/pickup-delivery-queue-card.component.d.ts +35 -0
  28. package/src/lib/components/console/pickup-delivery-queue-card.component.js +222 -0
  29. package/src/lib/components/console/pickup-delivery-queue-card.component.js.map +1 -0
  30. package/src/lib/components/console/pos/pos-api.d.ts +24 -1
  31. package/src/lib/components/console/pos/pos-api.js +13 -0
  32. package/src/lib/components/console/pos/pos-api.js.map +1 -1
  33. package/src/lib/components/console/pos/pos-item-dialog.component.d.ts +12 -0
  34. package/src/lib/components/console/pos/pos-item-dialog.component.js +10 -8
  35. package/src/lib/components/console/pos/pos-item-dialog.component.js.map +1 -1
  36. package/src/lib/components/console/pos/pos-kiosk-queue.component.d.ts +22 -0
  37. package/src/lib/components/console/pos/pos-kiosk-queue.component.js +168 -0
  38. package/src/lib/components/console/pos/pos-kiosk-queue.component.js.map +1 -0
  39. package/src/lib/components/console/pos/pos-tender-dialogs.component.d.ts +18 -0
  40. package/src/lib/components/console/pos/pos-tender-dialogs.component.js +116 -1
  41. package/src/lib/components/console/pos/pos-tender-dialogs.component.js.map +1 -1
  42. package/src/lib/components/console/pos/pos-tender-panel.component.d.ts +8 -0
  43. package/src/lib/components/console/pos/pos-tender-panel.component.js +77 -18
  44. package/src/lib/components/console/pos/pos-tender-panel.component.js.map +1 -1
  45. package/src/lib/components/console/pos/use-pos-display.d.ts +5 -2
  46. package/src/lib/components/console/pos/use-pos-display.js +3 -2
  47. package/src/lib/components/console/pos/use-pos-display.js.map +1 -1
  48. package/src/lib/components/console/pos-devices-card.component.js +2 -2
  49. package/src/lib/components/console/pos-devices-card.component.js.map +1 -1
  50. package/src/lib/components/console/pos-display/pairing-screen.d.ts +5 -2
  51. package/src/lib/components/console/pos-display/pairing-screen.js +7 -5
  52. package/src/lib/components/console/pos-display/pairing-screen.js.map +1 -1
  53. package/src/lib/components/console/pos-display/pos-display-api.d.ts +7 -1
  54. package/src/lib/components/console/pos-display/pos-display-api.js +7 -2
  55. package/src/lib/components/console/pos-display/pos-display-api.js.map +1 -1
  56. package/src/lib/components/console/pos-kiosk/kiosk-checkout.d.ts +41 -0
  57. package/src/lib/components/console/pos-kiosk/kiosk-checkout.js +275 -0
  58. package/src/lib/components/console/pos-kiosk/kiosk-checkout.js.map +1 -0
  59. package/src/lib/components/console/pos-kiosk/kiosk-menu.d.ts +32 -0
  60. package/src/lib/components/console/pos-kiosk/kiosk-menu.js +344 -0
  61. package/src/lib/components/console/pos-kiosk/kiosk-menu.js.map +1 -0
  62. package/src/lib/components/console/pos-kiosk/kiosk-staff.d.ts +12 -0
  63. package/src/lib/components/console/pos-kiosk/kiosk-staff.js +257 -0
  64. package/src/lib/components/console/pos-kiosk/kiosk-staff.js.map +1 -0
  65. package/src/lib/components/console/pos-kiosk/pos-kiosk-api.d.ts +114 -0
  66. package/src/lib/components/console/pos-kiosk/pos-kiosk-api.js +189 -0
  67. package/src/lib/components/console/pos-kiosk/pos-kiosk-api.js.map +1 -0
  68. package/src/lib/components/console/pos-kiosk/use-kiosk-idle.d.ts +16 -0
  69. package/src/lib/components/console/pos-kiosk/use-kiosk-idle.js +80 -0
  70. package/src/lib/components/console/pos-kiosk/use-kiosk-idle.js.map +1 -0
  71. package/src/lib/components/console/pos-kiosk-page.component.d.ts +28 -0
  72. package/src/lib/components/console/pos-kiosk-page.component.js +791 -0
  73. package/src/lib/components/console/pos-kiosk-page.component.js.map +1 -0
  74. package/src/lib/components/console/pos-offline/pos-offline-api.d.ts +44 -0
  75. package/src/lib/components/console/pos-offline/pos-offline-api.js +69 -0
  76. package/src/lib/components/console/pos-offline/pos-offline-api.js.map +1 -0
  77. package/src/lib/components/console/pos-offline/pos-offline-banner.component.d.ts +7 -0
  78. package/src/lib/components/console/pos-offline/pos-offline-banner.component.js +135 -0
  79. package/src/lib/components/console/pos-offline/pos-offline-banner.component.js.map +1 -0
  80. package/src/lib/components/console/pos-offline/pos-offline-checkout.component.d.ts +32 -0
  81. package/src/lib/components/console/pos-offline/pos-offline-checkout.component.js +287 -0
  82. package/src/lib/components/console/pos-offline/pos-offline-checkout.component.js.map +1 -0
  83. package/src/lib/components/console/pos-offline/pos-offline-store.d.ts +63 -0
  84. package/src/lib/components/console/pos-offline/pos-offline-store.js +145 -0
  85. package/src/lib/components/console/pos-offline/pos-offline-store.js.map +1 -0
  86. package/src/lib/components/console/pos-offline/register-offline.d.ts +24 -0
  87. package/src/lib/components/console/pos-offline/register-offline.js +24 -0
  88. package/src/lib/components/console/pos-offline/register-offline.js.map +1 -0
  89. package/src/lib/components/console/pos-offline/use-pos-offline.d.ts +85 -0
  90. package/src/lib/components/console/pos-offline/use-pos-offline.js +542 -0
  91. package/src/lib/components/console/pos-offline/use-pos-offline.js.map +1 -0
  92. package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js +72 -17
  93. package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js.map +1 -1
  94. package/src/lib/components/console/pos-page.component.js +174 -27
  95. package/src/lib/components/console/pos-page.component.js.map +1 -1
  96. package/src/lib/components/console/products-hub-card.component.js +35 -10
  97. package/src/lib/components/console/products-hub-card.component.js.map +1 -1
  98. package/src/lib/components/console/shipping-settings-card.component.js +1 -1
  99. package/src/lib/components/console/shipping-settings-card.component.js.map +1 -1
  100. package/src/lib/components/console/stock-movements-card.component.js +48 -16
  101. package/src/lib/components/console/stock-movements-card.component.js.map +1 -1
  102. package/src/lib/components/console/store-zones.d.ts +8 -1
  103. package/src/lib/components/console/store-zones.js +11 -1
  104. package/src/lib/components/console/store-zones.js.map +1 -1
  105. package/src/lib/components/order-status.js +66 -0
  106. package/src/lib/components/order-status.js.map +1 -1
  107. package/src/lib/components/product-detail.js +42 -15
  108. package/src/lib/components/product-detail.js.map +1 -1
  109. package/src/lib/constants/local-fulfillment-list-query.d.ts +48 -0
  110. package/src/lib/constants/local-fulfillment-list-query.js +84 -0
  111. package/src/lib/constants/local-fulfillment-list-query.js.map +1 -0
  112. package/src/lib/constants/orders-list-query.d.ts +7 -2
  113. package/src/lib/constants/orders-list-query.js +89 -8
  114. package/src/lib/constants/orders-list-query.js.map +1 -1
  115. package/src/lib/constants/pos-shift-list-query.d.ts +22 -0
  116. package/src/lib/constants/pos-shift-list-query.js +115 -0
  117. package/src/lib/constants/pos-shift-list-query.js.map +1 -0
  118. package/src/lib/constants/product-list-query.d.ts +6 -1
  119. package/src/lib/constants/product-list-query.js +77 -8
  120. package/src/lib/constants/product-list-query.js.map +1 -1
  121. package/src/lib/constants/stock-movement-query.d.ts +3 -2
  122. package/src/lib/constants/stock-movement-query.js +52 -8
  123. package/src/lib/constants/stock-movement-query.js.map +1 -1
  124. package/src/lib/model/buyer-notifications.d.ts +5 -3
  125. package/src/lib/model/buyer-notifications.js +25 -4
  126. package/src/lib/model/buyer-notifications.js.map +1 -1
  127. package/src/lib/model/commerce-orders.d.ts +59 -0
  128. package/src/lib/model/commerce-orders.js.map +1 -1
  129. package/src/lib/model/commerce-pos-kiosk.d.ts +175 -0
  130. package/src/lib/model/commerce-pos-kiosk.js +147 -0
  131. package/src/lib/model/commerce-pos-kiosk.js.map +1 -0
  132. package/src/lib/model/commerce-pos-offline.d.ts +234 -0
  133. package/src/lib/model/commerce-pos-offline.js +301 -0
  134. package/src/lib/model/commerce-pos-offline.js.map +1 -0
  135. package/src/lib/model/commerce-pos-ops.d.ts +16 -6
  136. package/src/lib/model/commerce-pos-ops.js +12 -4
  137. package/src/lib/model/commerce-pos-ops.js.map +1 -1
  138. package/src/lib/model/commerce-pos.d.ts +13 -1
  139. package/src/lib/model/commerce-pos.js +5 -4
  140. package/src/lib/model/commerce-pos.js.map +1 -1
  141. package/src/lib/model/commerce-stock-holds.d.ts +24 -3
  142. package/src/lib/model/commerce-stock-holds.js +26 -8
  143. package/src/lib/model/commerce-stock-holds.js.map +1 -1
  144. package/src/lib/model/commerce.d.ts +3 -0
  145. package/src/lib/model/commerce.js.map +1 -1
  146. package/src/lib/model/index.d.ts +4 -0
  147. package/src/lib/model/index.js +4 -0
  148. package/src/lib/model/index.js.map +1 -1
  149. package/src/lib/model/local-fulfillment-settings.d.ts +178 -0
  150. package/src/lib/model/local-fulfillment-settings.js +361 -0
  151. package/src/lib/model/local-fulfillment-settings.js.map +1 -0
  152. package/src/lib/model/order-list-fields.d.ts +10 -1
  153. package/src/lib/model/order-list-fields.js +1 -0
  154. package/src/lib/model/order-list-fields.js.map +1 -1
  155. package/src/lib/model/order-local-fulfillment.d.ts +131 -0
  156. package/src/lib/model/order-local-fulfillment.js +125 -0
  157. package/src/lib/model/order-local-fulfillment.js.map +1 -0
  158. package/src/lib/model/order-shipping-export.js +4 -0
  159. package/src/lib/model/order-shipping-export.js.map +1 -1
  160. package/src/lib/model/order-status-view.d.ts +20 -1
  161. package/src/lib/model/order-status-view.js +60 -6
  162. package/src/lib/model/order-status-view.js.map +1 -1
  163. package/src/lib/plugin-config.js +6 -2
  164. package/src/lib/plugin-config.js.map +1 -1
  165. package/src/lib/plugin.js +8 -0
  166. package/src/lib/plugin.js.map +1 -1
  167. package/src/lib/pos-kiosk-config.d.ts +26 -0
  168. package/src/lib/pos-kiosk-config.js +59 -0
  169. package/src/lib/pos-kiosk-config.js.map +1 -0
  170. package/src/lib/server/api-v1/openapi.js +8 -0
  171. package/src/lib/server/api-v1/openapi.js.map +1 -1
  172. package/src/lib/server/api-v1/order-view.d.ts +19 -0
  173. package/src/lib/server/api-v1/order-view.js +35 -0
  174. package/src/lib/server/api-v1/order-view.js.map +1 -1
  175. package/src/lib/server/billing-webhook.js +238 -87
  176. package/src/lib/server/billing-webhook.js.map +1 -1
  177. package/src/lib/server/cart-checkout.d.ts +2 -0
  178. package/src/lib/server/cart-checkout.js +173 -13
  179. package/src/lib/server/cart-checkout.js.map +1 -1
  180. package/src/lib/server/checkout-extras.js +18 -4
  181. package/src/lib/server/checkout-extras.js.map +1 -1
  182. package/src/lib/server/checkout.js +71 -14
  183. package/src/lib/server/checkout.js.map +1 -1
  184. package/src/lib/server/local-fulfillment-status.d.ts +86 -0
  185. package/src/lib/server/local-fulfillment-status.js +379 -0
  186. package/src/lib/server/local-fulfillment-status.js.map +1 -0
  187. package/src/lib/server/local-fulfillment.d.ts +190 -0
  188. package/src/lib/server/local-fulfillment.js +580 -0
  189. package/src/lib/server/local-fulfillment.js.map +1 -0
  190. package/src/lib/server/membership-register.js +3 -1
  191. package/src/lib/server/membership-register.js.map +1 -1
  192. package/src/lib/server/order-notifications.js +61 -0
  193. package/src/lib/server/order-notifications.js.map +1 -1
  194. package/src/lib/server/pos-display.d.ts +27 -1
  195. package/src/lib/server/pos-display.js +50 -9
  196. package/src/lib/server/pos-display.js.map +1 -1
  197. package/src/lib/server/pos-kiosk-principal.d.ts +29 -0
  198. package/src/lib/server/pos-kiosk-principal.js +42 -0
  199. package/src/lib/server/pos-kiosk-principal.js.map +1 -0
  200. package/src/lib/server/pos-kiosk.d.ts +54 -0
  201. package/src/lib/server/pos-kiosk.js +972 -0
  202. package/src/lib/server/pos-kiosk.js.map +1 -0
  203. package/src/lib/server/pos-offline-sync.d.ts +85 -0
  204. package/src/lib/server/pos-offline-sync.js +765 -0
  205. package/src/lib/server/pos-offline-sync.js.map +1 -0
  206. package/src/lib/server/pos-order.js +22 -4
  207. package/src/lib/server/pos-order.js.map +1 -1
  208. package/src/lib/server/pos-payment.d.ts +6 -0
  209. package/src/lib/server/pos-payment.js +225 -6
  210. package/src/lib/server/pos-payment.js.map +1 -1
  211. package/src/lib/server/pos-print.js +5 -0
  212. package/src/lib/server/pos-print.js.map +1 -1
  213. package/src/lib/server/pos-return.js +27 -0
  214. package/src/lib/server/pos-return.js.map +1 -1
  215. package/src/lib/server/pos-sale.d.ts +6 -0
  216. package/src/lib/server/pos-sale.js +2 -0
  217. package/src/lib/server/pos-sale.js.map +1 -1
  218. package/src/lib/server/pos-shift.js +8 -1
  219. package/src/lib/server/pos-shift.js.map +1 -1
  220. package/src/lib/server/refund.js +3 -0
  221. package/src/lib/server/refund.js.map +1 -1
  222. package/src/lib/server/stock-hold.d.ts +9 -1
  223. package/src/lib/server/stock-hold.js +15 -7
  224. package/src/lib/server/stock-hold.js.map +1 -1
  225. package/src/lib/server.js +16 -0
  226. package/src/lib/server.js.map +1 -1
  227. package/src/lib/tenant-emails.js +161 -0
  228. package/src/lib/tenant-emails.js.map +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/pos-offline-sync.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as Aglyn from '@aglyn/aglyn/server'\nimport type { PluginApiHandler, PluginApiRequest } from '@aglyn/aglyn/server'\nimport recordCapturedContact from '@aglyn/aglyn/plugin-manager/record-captured-contact'\nimport { FieldValue } from 'firebase-admin/firestore'\nimport * as CommerceModel from '../model'\nimport {\n posOfflineFlagLabels,\n posOfflineSaleTotals,\n posOfflineSoldAt,\n posOfflineTotalsAddUp,\n POS_OFFLINE_LATE_SYNC_MS,\n POS_OFFLINE_SYNC_BATCH_MAX,\n sanitizePosOfflineSale,\n type PosOfflineFlag,\n type PosOfflineKit,\n type PosOfflineOrderStamp,\n type PosOfflineRefusal,\n type PosOfflineSaleOutcome,\n type PosOfflineStockConflict,\n} from '../model/commerce-pos-offline'\nimport { ORDER_PAID_EVENT } from '../model/order-events'\nimport { posMaxDiscountPct } from '../plugin-config'\nimport { alertLowStockCrossing } from './low-stock'\nimport { notifyOrderBuyer } from './order-notifications'\nimport { raiseOrderEvent } from './order-events'\nimport { offlineFeeMonthKey } from './pos-fee-month'\nimport {\n authorizePosOps,\n defaultPosOpsDeps,\n posOpsBody,\n posOpsCleanId,\n resolvePosStaffAssertion,\n type PosOpsDeps,\n type PosOpsStaff,\n} from './pos-ops-gate'\nimport { notifyPosSaleCompleted } from './pos-sale'\nimport { decrementVariantStock, type StockDecrementOutcome } from './reserve-stock'\n\n/*==========================================\n * THE OFFLINE REGISTER'S SYNC (AGL-3625): `/api/commerce/pos-offline-sync`.\n *\n * GET ?hostId= the offline kit: the store's in-person tax rate, the\n * discount ceiling, the shift rule, the registers and their\n * open shifts, and the receipt's head and foot\n * POST {hostId, sales[]} records each cash sale rung offline, once\n *\n * The register's gate, unchanged (`authorizePosOps`): admin or editor on the\n * site, `managePos`, and the plan's `pos` entitlement — re-read at sync, so a\n * workspace that lost POS cannot sync into it. The plugin dispatcher has\n * already applied the security lockdown before this runs.\n *\n * ONE SALE, ONE ORDER, ONCE. The register's sale key is the order's id and\n * the id of a server-only record beside it (`posOfflineSales/{key}`), both\n * CREATED in one transaction. A sale sent twice — a connection that flapped\n * mid-request, a retry after an answer that never arrived — finds the record\n * and gets the first answer back, and a key that collides with any existing\n * order cannot overwrite it: `create` refuses.\n *\n * NEVER DROPPED. The customer has paid and left. So nothing the server finds\n * at sync refuses the sale: a changed price, short stock, a closed shift, a\n * register over the cap are each FLAGGED — on the order, its timeline and the\n * answer — and the sale is recorded as it happened. The only refusals are the\n * ones that protect somebody else: a sale signed for another member, another\n * site or another workspace stays on the device that rang it.\n *\n * STEPS AFTER THE COMMIT are recorded on the sync record as they finish, so a\n * request that dies between them is finished by the next sync of the same\n * sale rather than skipped (stock) or repeated (the receipt email).\n *=========================================*/\n\n/** The register's sync record: no customer data, only what dedupe and resume need. */\nexport interface PosOfflineSyncRecord {\n saleKey: string\n orderId: string\n number: number | null\n signedInUid: string\n registerId: string\n soldAtMs: number\n syncedAtMs: number\n status: 'recorded' | 'settled'\n flags: PosOfflineFlag[]\n stockConflicts: PosOfflineStockConflict[]\n /** Line indexes whose stock has been taken. */\n stockLines: number[]\n stockDone: boolean\n notified: boolean\n}\n\nexport interface PosOfflineAfterSale {\n hostId: string\n orderId: string\n order: CommerceModel.HostOrder\n email: string\n name: string\n}\n\nexport interface PosOfflineSyncDeps extends PosOpsDeps {\n /** The plan's take rate for one product type (AGL-2111). */\n feePct(org: Record<string, any> | null, productType: 'physical' | 'digital' | 'service'): number\n /** Whether the register at this creation rank is within the site's cap (AGL-1775). */\n registerWithinCap(org: Record<string, any> | null, hostId: string, rank: number): boolean\n /** Takes one line's units off the shelf, with its ledger row (AGL-2320). */\n decrementStock(input: {\n hostRef: FirebaseFirestore.DocumentReference\n hostId: string\n productId: string\n variantId: string\n quantity: number\n locationId?: string\n orderId: string\n }): Promise<StockDecrementOutcome>\n /** What a completed sale tells the rest of the workspace. Never throws. */\n afterSale(input: PosOfflineAfterSale): Promise<void>\n}\n\nexport function defaultPosOfflineSyncDeps(): PosOfflineSyncDeps {\n const base = defaultPosOpsDeps()\n return {\n ...base,\n feePct: (org, productType) => Aglyn.resolveTransactionFeePct(org as any, productType),\n registerWithinCap: (org, hostId, rank) =>\n Aglyn.checkHostRegisterQuota(org as any, hostId, rank).allowed,\n decrementStock: async (input) => {\n const moved = await decrementVariantStock({\n firestore: base.firestore(),\n hostRef: input.hostRef,\n hostId: input.hostId,\n productId: input.productId,\n variantId: input.variantId,\n quantity: input.quantity,\n ...(input.locationId ? { locationId: input.locationId } : {}),\n ledger: { reason: 'sale', orderId: input.orderId },\n })\n if (moved.before && moved.after) alertLowStockCrossing(input.hostId, moved.before, moved.after)\n return moved\n },\n afterSale: async (input) => {\n const settle = async (label: string, work: () => Promise<unknown>) => {\n try {\n await work()\n } catch (error) {\n console.error(`[pos-offline-sync] ${label} failed`, input.orderId, error)\n }\n }\n if (input.email) {\n await settle('contact', () =>\n recordCapturedContact({\n orgId: '',\n hostId: input.hostId,\n identity: { email: input.email, ...(input.name ? { name: input.name } : {}) },\n surface: 'relationship',\n lifecycleFloor: 'customer',\n purchaseCents: Number(input.order.totals?.totalCents ?? 0),\n interaction: {\n source: 'order',\n refId: input.orderId,\n summary: `In-store purchase ($${(Number(input.order.totals?.totalCents ?? 0) / 100).toFixed(2)})`,\n },\n }),\n )\n }\n // The sale-completed listeners hear it too, told it was rung offline:\n // the cloud printers must not print a receipt or pop the drawer for a\n // sale the customer walked away with hours ago.\n await settle('sale completed', () =>\n notifyPosSaleCompleted({ hostId: input.hostId, orderId: input.orderId, order: input.order, offline: true }),\n )\n // The emailed receipt sends now, on sync (the printed one went offline).\n await settle('receipt', () =>\n notifyOrderBuyer({ hostId: input.hostId, orderId: input.orderId }, 'receipt', { email: input.email }),\n )\n await settle('paid event', () =>\n raiseOrderEvent(ORDER_PAID_EVENT, { hostId: input.hostId, orderId: input.orderId, key: 'paid' }),\n )\n },\n }\n}\n\ntype Outcome = { status: number; body: Record<string, unknown> }\n\nconst money = (cents: number) => `$${(Math.max(0, cents) / 100).toFixed(2)}`\n\n/** The store's in-person tax, as every register sale computes it. */\nexport function posInPersonTax(\n settings: CommerceModel.TaxSettings | undefined,\n):\n | { ok: true; pct: number | null; pricesIncludeTax: boolean; decision: CommerceModel.StorefrontTaxDecision }\n | { ok: false; reason: string } {\n const taxSettings = (settings ?? {}) as CommerceModel.TaxSettings\n const decision = CommerceModel.storefrontTaxDecision({ settings: taxSettings })\n if (decision.kind === 'undecided') {\n return { ok: false, reason: CommerceModel.STOREFRONT_TAX_UNDECIDED_MESSAGE }\n }\n const misconfigured = CommerceModel.storefrontTaxMisconfiguration(taxSettings, { inPerson: true })\n if (misconfigured) return { ok: false, reason: misconfigured }\n const rate =\n decision.kind === 'manual' ? CommerceModel.resolveTaxRate(taxSettings, taxSettings.origin ?? {}) : null\n return {\n ok: true,\n pct: rate && rate.pct > 0 ? rate.pct : null,\n pricesIncludeTax: taxSettings.pricesIncludeTax === true,\n decision,\n }\n}\n\ninterface SyncContext {\n deps: PosOfflineSyncDeps\n staff: PosOpsStaff\n config: Record<string, unknown>\n tax: ReturnType<typeof posInPersonTax>\n /** Registers by id, with their creation rank. */\n registers: Map<string, { rank: number; data: Record<string, any> }>\n}\n\nasync function readRegisters(staff: PosOpsStaff): Promise<SyncContext['registers']> {\n const docs = (await staff.hostRef.collection('registers').get()).docs\n .map((doc) => ({\n id: doc.id,\n data: (doc.data() ?? {}) as Record<string, any>,\n createdAtMs: Number(doc.get('createdAt')?.toMillis?.() ?? doc.get('createdAtMs') ?? 0),\n }))\n .sort((a, b) => a.createdAtMs - b.createdAtMs || a.id.localeCompare(b.id))\n return new Map(docs.map((doc, rank) => [doc.id, { rank, data: doc.data }]))\n}\n\nasync function readStoreTax(staff: PosOpsStaff): Promise<CommerceModel.TaxSettings | undefined> {\n const store = await staff.hostRef.collection('settings').doc('store').get()\n return (store.get('tax') ?? undefined) as CommerceModel.TaxSettings | undefined\n}\n\n/** The kit a register caches to sell offline. */\nexport async function buildPosOfflineKit(\n deps: PosOfflineSyncDeps,\n staff: PosOpsStaff,\n): Promise<PosOfflineKit> {\n const [registers, taxSettings, config, host, store] = await Promise.all([\n readRegisters(staff),\n readStoreTax(staff),\n staff.orgId ? deps.pluginConfig(staff.orgId, staff.hostId).catch(() => ({})) : Promise.resolve({}),\n staff.hostRef.get(),\n staff.hostRef.collection('settings').doc('store').get(),\n ])\n const tax = posInPersonTax(taxSettings)\n return {\n v: 1,\n hostId: staff.hostId,\n orgId: staff.orgId,\n issuedAtMs: deps.now(),\n available: tax.ok,\n ...('reason' in tax ? { unavailableReason: tax.reason } : {}),\n tax: 'decision' in tax ? { pct: tax.pct, pricesIncludeTax: tax.pricesIncludeTax } : { pct: null, pricesIncludeTax: false },\n maxDiscountPct: posMaxDiscountPct(config),\n requireOpenShift: staff.settings.requireOpenShift,\n registers: [...registers.entries()]\n .filter(([, register]) => deps.registerWithinCap(staff.org, staff.hostId, register.rank))\n .map(([id, register]) => ({\n id,\n name: String(register.data['name'] ?? 'Register').slice(0, 120),\n ...(register.data['locationId'] ? { locationId: String(register.data['locationId']) } : {}),\n openShiftId: posOpsCleanId(register.data['openShiftId']) || null,\n })),\n receipt: {\n name: String(host.get('displayName') ?? '') || 'Receipt',\n ...(typeof host.get('logoUrl') === 'string' && host.get('logoUrl') ? { logo: String(host.get('logoUrl')) } : {}),\n ...(staff.settings.receiptAddress ? { address: staff.settings.receiptAddress } : {}),\n ...(store.get('receiptFooter') ? { footer: String(store.get('receiptFooter')).slice(0, 500) } : {}),\n ...(staff.settings.returnPolicy ? { returnPolicy: staff.settings.returnPolicy } : {}),\n },\n }\n}\n\nconst refused = (\n saleKey: string,\n reason: PosOfflineRefusal,\n error: string,\n retry: boolean,\n): PosOfflineSaleOutcome => ({ saleKey, status: 'refused', reason, error, retry })\n\nconst replayOf = (record: PosOfflineSyncRecord): PosOfflineSaleOutcome => ({\n saleKey: record.saleKey,\n status: 'replayed',\n orderId: record.orderId,\n number: record.number,\n flags: record.flags,\n stockConflicts: record.stockConflicts,\n})\n\n/** The take the plan owes on the goods after the discount (AGL-2111, AGL-2256). */\nfunction takeFeeCents(\n deps: PosOfflineSyncDeps,\n staff: PosOpsStaff,\n lines: CommerceModel.OrderLineItem[],\n totals: CommerceModel.OrderTotals,\n): number {\n let applies = false\n const gross = lines.reduce((sum, line) => {\n const pct = deps.feePct(staff.org, (line.productType ?? 'physical') as 'physical' | 'digital' | 'service')\n if (pct > 0) applies = true\n return sum + Math.round((line.unitAmountCents * line.quantity * pct) / 100)\n }, 0)\n const charged = Math.max(0, totals.itemsCents - totals.discountCents)\n const scaled = totals.itemsCents > 0 ? Math.round((gross * charged) / totals.itemsCents) : 0\n return applies && charged > 0 ? Math.max(1, scaled) : scaled\n}\n\n/**\n * The steps after the commit, each recorded as it finishes. Run by the sync\n * that recorded the sale, and again by any later sync of it that finds them\n * unfinished.\n */\nasync function finishSale(\n context: SyncContext,\n recordRef: FirebaseFirestore.DocumentReference,\n orderRef: FirebaseFirestore.DocumentReference,\n record: PosOfflineSyncRecord,\n): Promise<PosOfflineSyncRecord> {\n const { deps, staff } = context\n const orderSnapshot = await orderRef.get()\n const order = (orderSnapshot.data() ?? {}) as CommerceModel.HostOrder & Record<string, any>\n let current = record\n if (!current.stockDone) {\n const conflicts = [...current.stockConflicts]\n const done = new Set(current.stockLines)\n const lines = (order.lineItems ?? []) as CommerceModel.OrderLineItem[]\n for (const [index, line] of lines.entries()) {\n if (done.has(index)) continue\n const moved = await deps.decrementStock({\n hostRef: staff.hostRef,\n hostId: staff.hostId,\n productId: line.productId,\n variantId: line.variantId ?? 'default',\n quantity: line.quantity,\n ...(order['locationId'] ? { locationId: String(order['locationId']) } : {}),\n orderId: orderRef.id,\n })\n // A failed commit leaves the line for the next sync to take, rather than\n // marking stock taken that never moved.\n if (moved.failed) continue\n // Untracked stock (or a product gone since) moves nothing and is short of nothing.\n const short = moved.before ? moved.applied - moved.requested : 0\n if (short > 0) {\n conflicts.push({\n productId: line.productId,\n ...(line.variantId ? { variantId: line.variantId } : {}),\n name: [line.name, line.variantLabel].filter(Boolean).join(' — '),\n requested: Math.abs(moved.requested),\n applied: Math.abs(moved.applied),\n shortUnits: short,\n })\n }\n done.add(index)\n await recordRef.update({ stockLines: [...done].sort((a, b) => a - b), stockConflicts: conflicts })\n }\n const stockDone = lines.every((_line, index) => done.has(index))\n const flags: PosOfflineFlag[] =\n conflicts.length && !current.flags.includes('stock-short') ? [...current.flags, 'stock-short'] : current.flags\n current = { ...current, stockLines: [...done], stockConflicts: conflicts, stockDone, flags }\n await recordRef.update({ stockDone, flags, stockConflicts: conflicts })\n if (conflicts.length && conflicts.length !== record.stockConflicts.length) {\n const fresh = (await orderRef.get()).data() as CommerceModel.HostOrder\n const stamp = fresh?.offline\n await orderRef.update({\n ...(stamp ? { offline: { ...stamp, flags, stockConflicts: conflicts } } : {}),\n timeline: CommerceModel.appendOrderEvent(\n fresh ?? {},\n 'offline-stock-short',\n conflicts\n .map((conflict) => `${conflict.shortUnits} of ${conflict.requested}× ${conflict.name} not in stock`)\n .join('; ')\n .slice(0, 500),\n deps.now(),\n ),\n })\n }\n if (!stockDone) return current\n }\n if (!current.notified) {\n const email = String(order.customerEmail ?? '')\n await deps.afterSale({\n hostId: staff.hostId,\n orderId: orderRef.id,\n order: order as CommerceModel.HostOrder,\n email,\n name: String(order.customerName ?? ''),\n })\n current = { ...current, notified: true, status: 'settled' }\n await recordRef.update({ notified: true, status: 'settled' })\n }\n return current\n}\n\nasync function syncOne(context: SyncContext, raw: unknown): Promise<PosOfflineSaleOutcome> {\n const { deps, staff } = context\n const read = sanitizePosOfflineSale(raw)\n const rawKey = String((raw as Record<string, unknown> | null)?.['saleKey'] ?? '').slice(0, 64)\n if ('error' in read) return refused(rawKey, 'invalid', read.error, false)\n const sale = read.sale\n if (sale.hostId !== staff.hostId) {\n return refused(sale.saleKey, 'wrong-site', 'This sale was rung for another site.', false)\n }\n if (sale.signedInUid !== staff.uid) {\n return refused(\n sale.saleKey,\n 'wrong-staff',\n 'This sale was rung while another member was signed in. It syncs when they sign in on this register.',\n true,\n )\n }\n if (sale.orgId && staff.orgId && sale.orgId !== staff.orgId) {\n return refused(sale.saleKey, 'wrong-workspace', 'This sale was rung in another workspace.', false)\n }\n\n const firestore = deps.firestore()\n const hostRef = staff.hostRef\n const recordRef = hostRef.collection('posOfflineSales').doc(sale.saleKey)\n const orderRef = hostRef.collection('orders').doc(sale.saleKey)\n\n const existing = await recordRef.get()\n if (existing.exists) {\n const record = existing.data() as PosOfflineSyncRecord\n if (record.signedInUid !== staff.uid) {\n return refused(sale.saleKey, 'conflict', 'Another sale already used this key.', false)\n }\n return replayOf(record.status === 'settled' ? record : await finishSale(context, recordRef, orderRef, record))\n }\n\n const now = deps.now()\n const flags = new Set<PosOfflineFlag>()\n const soldAt = posOfflineSoldAt(sale.soldAtMs, now)\n if (soldAt.adjusted) flags.add('clock-adjusted')\n else if (now - soldAt.atMs > POS_OFFLINE_LATE_SYNC_MS) flags.add('late-sync')\n\n // The lines as sold, checked against the catalog as it stands now. The\n // price on the order is the one rung — that is what the customer paid —\n // and the catalog's is kept beside it where they differ.\n const productIds = [...new Set(sale.lines.map((line) => line.productId))]\n const snapshots = await Promise.all(productIds.map((id) => hostRef.collection('products').doc(id).get()))\n const products = new Map(\n snapshots.map((snapshot) => [\n snapshot.id,\n snapshot.exists ? CommerceModel.liftLegacyProduct(snapshot.data() as any) : null,\n ]),\n )\n const priceDrift: NonNullable<PosOfflineOrderStamp['priceDrift']> = []\n const lineItems: CommerceModel.OrderLineItem[] = sale.lines.map((line, index) => {\n const product = products.get(line.productId)\n if (!product) {\n flags.add('unknown-product')\n return {\n productId: line.productId,\n ...(line.variantId ? { variantId: line.variantId } : {}),\n name: line.name,\n ...(line.variantLabel ? { variantLabel: line.variantLabel } : {}),\n ...(line.sku ? { sku: line.sku } : {}),\n productType: line.productType ?? 'physical',\n quantity: line.quantity,\n unitAmountCents: line.unitAmountCents,\n }\n }\n const variant = product.variants.find((item) => item.id === line.variantId) ?? product.variants[0]\n const chosen = CommerceModel.resolveLineModifiers(product, line.modifiers)\n const currentCents =\n variant && CommerceModel.variantHasPrice(variant) && chosen.ok\n ? Math.round(Number(variant.priceUsd) * 100) + chosen.extraCents\n : null\n if (currentCents !== line.unitAmountCents) {\n flags.add('price-changed')\n priceDrift.push({ index, rungCents: line.unitAmountCents, currentCents: currentCents ?? 0 })\n }\n return {\n productId: line.productId,\n ...(variant && variant.id !== 'default' ? { variantId: variant.id } : {}),\n name: product.name || line.name,\n ...(line.variantLabel ? { variantLabel: line.variantLabel } : {}),\n ...(variant?.sku ? { sku: variant.sku } : line.sku ? { sku: line.sku } : {}),\n productType: product.type ?? line.productType ?? 'physical',\n quantity: line.quantity,\n unitAmountCents: line.unitAmountCents,\n ...(chosen.ok && chosen.modifiers.length ? { modifiers: chosen.modifiers } : {}),\n }\n })\n\n // The money: what the register rang, when its own arithmetic holds; the\n // arithmetic of its lines, with the tax it rang, when it does not.\n let totals: CommerceModel.OrderTotals\n if (posOfflineTotalsAddUp(sale)) {\n totals = CommerceModel.computeOrderTotals(lineItems, {\n discountCents: sale.totals.discountCents,\n taxCents: sale.totals.taxCents,\n })\n } else {\n flags.add('totals-restated')\n const restated = posOfflineSaleTotals({\n lines: sale.lines,\n discountPct: sale.discountPct,\n tax: { pct: null, pricesIncludeTax: false },\n })\n totals = CommerceModel.computeOrderTotals(lineItems, {\n discountCents: restated.discountCents,\n taxCents: Math.min(sale.totals.taxCents, restated.itemsCents - restated.discountCents),\n })\n }\n if ('decision' in context.tax) {\n const expected = posOfflineSaleTotals({\n lines: sale.lines,\n discountPct: sale.discountPct,\n tax: { pct: context.tax.pct, pricesIncludeTax: context.tax.pricesIncludeTax },\n })\n if (expected.taxCents !== totals.taxCents) flags.add('tax-differs')\n } else if (totals.taxCents > 0) {\n flags.add('tax-differs')\n }\n if (sale.discountPct > posMaxDiscountPct(context.config)) flags.add('discount-over-limit')\n if (sale.cashTenderedCents < totals.totalCents) flags.add('cash-short')\n\n // Where it was rung.\n const register = context.registers.get(sale.registerId)\n if (!register) flags.add('unknown-register')\n else if (!deps.registerWithinCap(staff.org, staff.hostId, register.rank)) flags.add('register-over-cap')\n let shiftId = ''\n if (sale.shiftId && register) {\n const shift = await hostRef\n .collection('registers')\n .doc(sale.registerId)\n .collection('shifts')\n .doc(sale.shiftId)\n .get()\n if (shift.exists) {\n shiftId = sale.shiftId\n if (shift.get('status') !== 'open') flags.add('shift-closed')\n }\n }\n if (!shiftId && staff.settings.requireOpenShift) flags.add('no-shift')\n\n // Who rang it: a PIN-switched cashier's assertion is read as of the moment\n // the cash was taken (it was valid then, and expiring since is the normal\n // case for a sale that waited to sync), and the member is re-checked NOW.\n let cashierId = staff.uid\n if (sale.cashierAssertion) {\n const memberUid = await resolvePosStaffAssertion(\n { ...deps, now: () => soldAt.atMs },\n hostRef,\n sale.cashierAssertion,\n { hostId: staff.hostId, registerId: sale.registerId, purpose: 'cashier' },\n )\n if (memberUid) cashierId = memberUid\n else flags.add('cashier-unverified')\n }\n\n const takeFee = takeFeeCents(deps, staff, lineItems, totals)\n totals = { ...totals, feeCents: takeFee }\n const changeCents = Math.max(0, sale.cashTenderedCents - totals.totalCents)\n const flagList = [...flags]\n const stamp: PosOfflineOrderStamp = {\n saleKey: sale.saleKey,\n soldAtMs: soldAt.atMs,\n syncedAtMs: now,\n syncedBy: staff.uid,\n flags: flagList,\n ...(priceDrift.length ? { priceDrift } : {}),\n }\n const customer = sale.customer ?? {}\n const feeMonth = offlineFeeMonthKey(new Date(now))\n const feeRef = staff.orgId\n ? firestore.collection('orgs').doc(staff.orgId).collection('offlineFees').doc(feeMonth)\n : null\n const counterRef = hostRef.collection('counters').doc('orders')\n\n const committed = await firestore.runTransaction(async (transaction) => {\n const raced = await transaction.get(recordRef)\n if (raced.exists) return { raced: raced.data() as PosOfflineSyncRecord }\n const taken = await transaction.get(orderRef)\n if (taken.exists) return { collision: true as const }\n const counter = await transaction.get(counterRef)\n const number = Number(counter.get('next') ?? 1)\n transaction.set(counterRef, { next: number + 1 }, { merge: true })\n const paidDetail =\n `Cash — received ${money(sale.cashTenderedCents)}, change ${money(changeCents)}. ` +\n 'Rung while the register was offline.'\n const timeline: CommerceModel.OrderTimelineEvent[] = [\n { atMs: soldAt.atMs, event: 'paid', detail: paidDetail },\n {\n atMs: now,\n event: 'offline-synced',\n detail: flagList.length\n ? `Synced. Check: ${posOfflineFlagLabels(flagList).join('; ')}`.slice(0, 1000)\n : 'Synced.',\n },\n ]\n transaction.create(\n orderRef,\n CommerceModel.withOrderListFields(orderRef.id, {\n number,\n status: 'paid',\n channel: 'pos',\n registerId: sale.registerId,\n cashierId,\n ...(shiftId ? { shiftId } : {}),\n ...(customer.name ? { customerName: customer.name } : {}),\n ...(customer.kind && customer.id ? { customerRecord: { kind: customer.kind, id: customer.id } } : {}),\n ...(sale.discountPct > 0 ? { discountPct: sale.discountPct, discountBy: cashierId } : {}),\n ...(sale.locationId ? { locationId: sale.locationId } : {}),\n lineItems,\n totals,\n taxMode: 'decision' in context.tax\n ? CommerceModel.storefrontTaxModeForDecision(context.tax.decision, totals.taxCents)\n : totals.taxCents > 0\n ? 'manual'\n : 'none',\n ...(takeFee > 0 ? { feeCollection: 'invoice' as const } : {}),\n payments: [\n {\n id: 'pay_cash',\n method: 'cash',\n amountCents: totals.totalCents,\n status: 'succeeded',\n atMs: soldAt.atMs,\n settledAtMs: soldAt.atMs,\n takeFeeCents: takeFee,\n feeCents: 0,\n cashierId,\n cashTenderedCents: sale.cashTenderedCents,\n changeCents,\n } satisfies CommerceModel.OrderPayment,\n ],\n customerEmail: customer.email || null,\n timeline,\n offline: stamp,\n createdAtMs: soldAt.atMs,\n createdAt: FieldValue.serverTimestamp(),\n }),\n )\n const record: PosOfflineSyncRecord = {\n saleKey: sale.saleKey,\n orderId: orderRef.id,\n number,\n signedInUid: staff.uid,\n registerId: sale.registerId,\n soldAtMs: soldAt.atMs,\n syncedAtMs: now,\n status: 'recorded',\n flags: flagList,\n stockConflicts: [],\n stockLines: [],\n stockDone: false,\n notified: false,\n }\n transaction.create(recordRef, record)\n // The take accrues with the order, in the same transaction (AGL-2111).\n if (takeFee > 0 && feeRef) {\n transaction.set(\n feeRef,\n { month: feeMonth, feeCents: FieldValue.increment(takeFee), orders: FieldValue.increment(1) },\n { merge: true },\n )\n }\n return { record }\n })\n if ('collision' in committed) {\n return refused(sale.saleKey, 'conflict', 'Another order already has this sale’s key.', false)\n }\n if ('raced' in committed) {\n const record = committed.raced\n if (record.signedInUid !== staff.uid) {\n return refused(sale.saleKey, 'conflict', 'Another sale already used this key.', false)\n }\n return replayOf(record)\n }\n const finished = await finishSale(context, recordRef, orderRef, committed.record)\n return {\n saleKey: sale.saleKey,\n status: 'recorded',\n orderId: orderRef.id,\n number: finished.number,\n flags: finished.flags,\n stockConflicts: finished.stockConflicts,\n }\n}\n\nexport async function handlePosOfflineSync(\n deps: PosOfflineSyncDeps,\n req: PluginApiRequest,\n): Promise<Outcome> {\n if (req.method !== 'GET' && req.method !== 'POST') {\n return { status: 405, body: { error: 'Method not allowed' } }\n }\n const body =\n req.method === 'GET'\n ? Object.fromEntries(\n Object.entries(req.query ?? {}).map(([key, value]) => [key, Array.isArray(value) ? value[0] : value]),\n )\n : posOpsBody(req)\n const gate = await authorizePosOps(deps, req, body['hostId'])\n if ('error' in gate) return { status: gate.status, body: { error: gate.error } }\n const staff = gate.staff\n if (req.method === 'GET') {\n return { status: 200, body: { kit: await buildPosOfflineKit(deps, staff) } }\n }\n const sales = Array.isArray(body['sales']) ? (body['sales'] as unknown[]) : null\n if (!sales) return { status: 400, body: { error: 'Missing sales' } }\n if (sales.length > POS_OFFLINE_SYNC_BATCH_MAX) {\n return { status: 400, body: { error: `Send at most ${POS_OFFLINE_SYNC_BATCH_MAX} sales at a time` } }\n }\n if (sales.length === 0) return { status: 200, body: { results: [] } }\n const [registers, taxSettings, config] = await Promise.all([\n readRegisters(staff),\n readStoreTax(staff),\n staff.orgId ? deps.pluginConfig(staff.orgId, staff.hostId).catch(() => ({})) : Promise.resolve({}),\n ])\n const context: SyncContext = { deps, staff, config, tax: posInPersonTax(taxSettings), registers }\n const results: PosOfflineSaleOutcome[] = []\n // One at a time, in the order they were rung, so order numbers follow the\n // till and one sale's failure cannot take the rest with it.\n for (const sale of sales) {\n try {\n results.push(await syncOne(context, sale))\n } catch (error) {\n console.error('[pos-offline-sync] sale failed', error)\n const key = String((sale as Record<string, unknown> | null)?.['saleKey'] ?? '').slice(0, 64)\n results.push(refused(key, 'failed', 'The sale could not be synced yet. It stays on this register.', true))\n }\n }\n return { status: 200, body: { results } }\n}\n\nexport function createPosOfflineSyncHandler(\n deps: () => PosOfflineSyncDeps = defaultPosOfflineSyncDeps,\n): PluginApiHandler {\n return async (req, res) => {\n try {\n const outcome = await handlePosOfflineSync(deps(), req)\n return res.status(outcome.status).json(outcome.body)\n } catch (error) {\n console.error('[pos-offline-sync] failed', error)\n return res.status(500).json({ error: 'The offline sales could not be synced' })\n }\n }\n}\n\nexport const posOfflineSyncHandler = createPosOfflineSyncHandler()\n"],"names":["Aglyn","recordCapturedContact","FieldValue","CommerceModel","posOfflineFlagLabels","posOfflineSaleTotals","posOfflineSoldAt","posOfflineTotalsAddUp","POS_OFFLINE_LATE_SYNC_MS","POS_OFFLINE_SYNC_BATCH_MAX","sanitizePosOfflineSale","ORDER_PAID_EVENT","posMaxDiscountPct","alertLowStockCrossing","notifyOrderBuyer","raiseOrderEvent","offlineFeeMonthKey","authorizePosOps","defaultPosOpsDeps","posOpsBody","posOpsCleanId","resolvePosStaffAssertion","notifyPosSaleCompleted","decrementVariantStock","defaultPosOfflineSyncDeps","base","feePct","org","productType","resolveTransactionFeePct","registerWithinCap","hostId","rank","checkHostRegisterQuota","allowed","decrementStock","input","moved","firestore","hostRef","productId","variantId","quantity","locationId","ledger","reason","orderId","before","after","afterSale","settle","label","work","error","console","email","orgId","identity","name","surface","lifecycleFloor","purchaseCents","Number","order","totals","totalCents","interaction","source","refId","summary","toFixed","offline","key","money","cents","Math","max","posInPersonTax","settings","taxSettings","decision","storefrontTaxDecision","kind","ok","STOREFRONT_TAX_UNDECIDED_MESSAGE","misconfigured","storefrontTaxMisconfiguration","inPerson","rate","resolveTaxRate","origin","pct","pricesIncludeTax","readRegisters","staff","docs","collection","get","map","doc","id","data","createdAtMs","toMillis","sort","a","b","localeCompare","Map","readStoreTax","store","undefined","buildPosOfflineKit","deps","host","registers","config","Promise","all","pluginConfig","catch","resolve","tax","v","issuedAtMs","now","available","unavailableReason","maxDiscountPct","requireOpenShift","entries","filter","register","String","slice","openShiftId","receipt","logo","receiptAddress","address","footer","returnPolicy","refused","saleKey","retry","status","replayOf","record","number","flags","stockConflicts","takeFeeCents","lines","applies","gross","reduce","sum","line","round","unitAmountCents","charged","itemsCents","discountCents","scaled","finishSale","context","recordRef","orderRef","orderSnapshot","current","stockDone","conflicts","done","Set","stockLines","lineItems","index","has","failed","short","applied","requested","push","variantLabel","Boolean","join","abs","shortUnits","add","update","every","_line","length","includes","fresh","stamp","timeline","appendOrderEvent","conflict","notified","customerEmail","customerName","syncOne","raw","sale","read","rawKey","signedInUid","uid","existing","exists","soldAt","soldAtMs","adjusted","atMs","productIds","snapshots","products","snapshot","liftLegacyProduct","priceDrift","product","sku","variant","variants","find","item","chosen","resolveLineModifiers","modifiers","currentCents","variantHasPrice","priceUsd","extraCents","rungCents","type","computeOrderTotals","taxCents","restated","discountPct","min","expected","cashTenderedCents","registerId","shiftId","shift","cashierId","cashierAssertion","memberUid","purpose","takeFee","feeCents","changeCents","flagList","syncedAtMs","syncedBy","customer","feeMonth","Date","feeRef","counterRef","committed","runTransaction","transaction","counter","raced","taken","collision","set","next","merge","paidDetail","event","detail","create","withOrderListFields","channel","customerRecord","discountBy","taxMode","storefrontTaxModeForDecision","feeCollection","payments","method","amountCents","settledAtMs","createdAt","serverTimestamp","month","increment","orders","finished","handlePosOfflineSync","req","body","Object","fromEntries","query","value","Array","isArray","gate","kit","sales","results","createPosOfflineSyncHandler","res","outcome","json","posOfflineSyncHandler"],"mappings":"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"}
@@ -33,6 +33,7 @@ import { notifyPosSaleCompleted } from "./pos-sale.js";
33
33
  import { posSaleStamp } from "./pos-sale-stamp.js";
34
34
  import { quoteSaleTaxWithEngine } from "./tax-engine-quote.js";
35
35
  import { resolveOrgPermissions } from "@aglyn/tenant-runtime/org-permissions";
36
+ import { posKioskPrincipal } from "./pos-kiosk-principal.js";
36
37
  /**
37
38
  * The settlement claim (AGL-1691) now lives in `@aglyn/aglyn/server`
38
39
  * (AGL-1697), because it is the answer for every unkeyed money route and not
@@ -59,7 +60,13 @@ import { resolveOrgPermissions } from "@aglyn/tenant-runtime/org-permissions";
59
60
  }
60
61
  const authorization = String((_req_headers_authorization = req.headers.authorization) != null ? _req_headers_authorization : '');
61
62
  const idToken = authorization.startsWith('Bearer ') ? authorization.slice('Bearer '.length) : undefined;
62
- if (!idToken) return res.status(401).json({
63
+ // A self-service kiosk's cart (AGL-3623), handed over in-process by
64
+ // `pos-kiosk.ts` as the staff member who paired it — checked below exactly
65
+ // as that member's own sale would be. Only an open sale, on its own
66
+ // register: the kiosk route never sends a discount, a coupon, a stay or a
67
+ // customer, and this refuses them should it ever try.
68
+ const kiosk = posKioskPrincipal(req);
69
+ if (!idToken && !kiosk) return res.status(401).json({
63
70
  error: 'Unauthenticated'
64
71
  });
65
72
  const body = typeof req.body === 'string' ? JSON.parse(req.body) : (_req_body = req.body) != null ? _req_body : {};
@@ -110,6 +117,11 @@ import { resolveOrgPermissions } from "@aglyn/tenant-runtime/org-permissions";
110
117
  error: 'Missing hostId or lines'
111
118
  });
112
119
  }
120
+ if (kiosk && (payment !== 'open' || registerId !== kiosk.registerId || discountPct !== 0 || couponCode || reservationId || customerEmail || body.customer || body.cashierAssertion)) {
121
+ return res.status(400).json({
122
+ error: 'A kiosk order cannot carry that'
123
+ });
124
+ }
113
125
  let claim = null;
114
126
  /**
115
127
  * The redemption slot this sale reserved (AGL-305), hoisted so every refusal
@@ -128,7 +140,9 @@ import { resolveOrgPermissions } from "@aglyn/tenant-runtime/org-permissions";
128
140
  try {
129
141
  var _hostSnapshot_get, _storeSettings_get, _taxSettings_origin, _ref2, _ref3;
130
142
  var _registerDocs_rank, _ownerOrg_org, _ownerOrg_org1;
131
- const decoded = await firebaseAdmin.app().auth().verifyIdToken(idToken);
143
+ const decoded = kiosk ? {
144
+ uid: kiosk.uid
145
+ } : await firebaseAdmin.app().auth().verifyIdToken(idToken);
132
146
  const firestore = firebaseAdmin.app().firestore();
133
147
  const hostRef = firestore.collection('hosts').doc(hostId);
134
148
  const hostSnapshot = await hostRef.get();
@@ -776,11 +790,15 @@ import { resolveOrgPermissions } from "@aglyn/tenant-runtime/org-permissions";
776
790
  posFeeOrgId: offlineFeeOrgId
777
791
  } : {}, {
778
792
  payments: [],
779
- customerEmail: customerEmail || null,
793
+ customerEmail: customerEmail || null
794
+ }, kiosk ? {
795
+ posSource: 'kiosk',
796
+ kioskDeviceId: kiosk.deviceId
797
+ } : {}, {
780
798
  timeline: [
781
799
  {
782
800
  atMs: Date.now(),
783
- event: 'pos-sale-opened'
801
+ event: kiosk ? 'pos-kiosk-order-opened' : 'pos-sale-opened'
784
802
  }
785
803
  ],
786
804
  createdAtMs: Date.now(),