@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,765 @@
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 * as Aglyn from "@aglyn/aglyn/server";
18
+ import recordCapturedContact from "@aglyn/aglyn/plugin-manager/record-captured-contact";
19
+ import { FieldValue } from "firebase-admin/firestore";
20
+ import * as CommerceModel from "../model/index.js";
21
+ import { posOfflineFlagLabels, posOfflineSaleTotals, posOfflineSoldAt, posOfflineTotalsAddUp, POS_OFFLINE_LATE_SYNC_MS, POS_OFFLINE_SYNC_BATCH_MAX, sanitizePosOfflineSale } from "../model/commerce-pos-offline.js";
22
+ import { ORDER_PAID_EVENT } from "../model/order-events.js";
23
+ import { posMaxDiscountPct } from "../plugin-config.js";
24
+ import { alertLowStockCrossing } from "./low-stock.js";
25
+ import { notifyOrderBuyer } from "./order-notifications.js";
26
+ import { raiseOrderEvent } from "./order-events.js";
27
+ import { offlineFeeMonthKey } from "./pos-fee-month.js";
28
+ import { authorizePosOps, defaultPosOpsDeps, posOpsBody, posOpsCleanId, resolvePosStaffAssertion } from "./pos-ops-gate.js";
29
+ import { notifyPosSaleCompleted } from "./pos-sale.js";
30
+ import { decrementVariantStock } from "./reserve-stock.js";
31
+ export function defaultPosOfflineSyncDeps() {
32
+ const base = defaultPosOpsDeps();
33
+ return _extends({}, base, {
34
+ feePct: (org, productType)=>Aglyn.resolveTransactionFeePct(org, productType),
35
+ registerWithinCap: (org, hostId, rank)=>Aglyn.checkHostRegisterQuota(org, hostId, rank).allowed,
36
+ decrementStock: async (input)=>{
37
+ const moved = await decrementVariantStock(_extends({
38
+ firestore: base.firestore(),
39
+ hostRef: input.hostRef,
40
+ hostId: input.hostId,
41
+ productId: input.productId,
42
+ variantId: input.variantId,
43
+ quantity: input.quantity
44
+ }, input.locationId ? {
45
+ locationId: input.locationId
46
+ } : {}, {
47
+ ledger: {
48
+ reason: 'sale',
49
+ orderId: input.orderId
50
+ }
51
+ }));
52
+ if (moved.before && moved.after) alertLowStockCrossing(input.hostId, moved.before, moved.after);
53
+ return moved;
54
+ },
55
+ afterSale: async (input)=>{
56
+ const settle = async (label, work)=>{
57
+ try {
58
+ await work();
59
+ } catch (error) {
60
+ console.error(`[pos-offline-sync] ${label} failed`, input.orderId, error);
61
+ }
62
+ };
63
+ if (input.email) {
64
+ await settle('contact', ()=>{
65
+ var _ref, _ref1;
66
+ var _input_order_totals, _input_order_totals1;
67
+ return recordCapturedContact({
68
+ orgId: '',
69
+ hostId: input.hostId,
70
+ identity: _extends({
71
+ email: input.email
72
+ }, input.name ? {
73
+ name: input.name
74
+ } : {}),
75
+ surface: 'relationship',
76
+ lifecycleFloor: 'customer',
77
+ purchaseCents: Number((_ref = (_input_order_totals = input.order.totals) == null ? void 0 : _input_order_totals.totalCents) != null ? _ref : 0),
78
+ interaction: {
79
+ source: 'order',
80
+ refId: input.orderId,
81
+ summary: `In-store purchase ($${(Number((_ref1 = (_input_order_totals1 = input.order.totals) == null ? void 0 : _input_order_totals1.totalCents) != null ? _ref1 : 0) / 100).toFixed(2)})`
82
+ }
83
+ });
84
+ });
85
+ }
86
+ // The sale-completed listeners hear it too, told it was rung offline:
87
+ // the cloud printers must not print a receipt or pop the drawer for a
88
+ // sale the customer walked away with hours ago.
89
+ await settle('sale completed', ()=>notifyPosSaleCompleted({
90
+ hostId: input.hostId,
91
+ orderId: input.orderId,
92
+ order: input.order,
93
+ offline: true
94
+ }));
95
+ // The emailed receipt sends now, on sync (the printed one went offline).
96
+ await settle('receipt', ()=>notifyOrderBuyer({
97
+ hostId: input.hostId,
98
+ orderId: input.orderId
99
+ }, 'receipt', {
100
+ email: input.email
101
+ }));
102
+ await settle('paid event', ()=>raiseOrderEvent(ORDER_PAID_EVENT, {
103
+ hostId: input.hostId,
104
+ orderId: input.orderId,
105
+ key: 'paid'
106
+ }));
107
+ }
108
+ });
109
+ }
110
+ const money = (cents)=>`$${(Math.max(0, cents) / 100).toFixed(2)}`;
111
+ /** The store's in-person tax, as every register sale computes it. */ export function posInPersonTax(settings) {
112
+ var _taxSettings_origin;
113
+ const taxSettings = settings != null ? settings : {};
114
+ const decision = CommerceModel.storefrontTaxDecision({
115
+ settings: taxSettings
116
+ });
117
+ if (decision.kind === 'undecided') {
118
+ return {
119
+ ok: false,
120
+ reason: CommerceModel.STOREFRONT_TAX_UNDECIDED_MESSAGE
121
+ };
122
+ }
123
+ const misconfigured = CommerceModel.storefrontTaxMisconfiguration(taxSettings, {
124
+ inPerson: true
125
+ });
126
+ if (misconfigured) return {
127
+ ok: false,
128
+ reason: misconfigured
129
+ };
130
+ const rate = decision.kind === 'manual' ? CommerceModel.resolveTaxRate(taxSettings, (_taxSettings_origin = taxSettings.origin) != null ? _taxSettings_origin : {}) : null;
131
+ return {
132
+ ok: true,
133
+ pct: rate && rate.pct > 0 ? rate.pct : null,
134
+ pricesIncludeTax: taxSettings.pricesIncludeTax === true,
135
+ decision
136
+ };
137
+ }
138
+ async function readRegisters(staff) {
139
+ const docs = (await staff.hostRef.collection('registers').get()).docs.map((doc)=>{
140
+ var _doc_data, _ref, _ref1;
141
+ var _doc_get_toMillis, _doc_get;
142
+ return {
143
+ id: doc.id,
144
+ data: (_doc_data = doc.data()) != null ? _doc_data : {},
145
+ createdAtMs: Number((_ref = (_ref1 = (_doc_get = doc.get('createdAt')) == null ? void 0 : (_doc_get_toMillis = _doc_get.toMillis) == null ? void 0 : _doc_get_toMillis.call(_doc_get)) != null ? _ref1 : doc.get('createdAtMs')) != null ? _ref : 0)
146
+ };
147
+ }).sort((a, b)=>a.createdAtMs - b.createdAtMs || a.id.localeCompare(b.id));
148
+ return new Map(docs.map((doc, rank)=>[
149
+ doc.id,
150
+ {
151
+ rank,
152
+ data: doc.data
153
+ }
154
+ ]));
155
+ }
156
+ async function readStoreTax(staff) {
157
+ var _store_get;
158
+ const store = await staff.hostRef.collection('settings').doc('store').get();
159
+ return (_store_get = store.get('tax')) != null ? _store_get : undefined;
160
+ }
161
+ /** The kit a register caches to sell offline. */ export async function buildPosOfflineKit(deps, staff) {
162
+ var _host_get;
163
+ const [registers, taxSettings, config, host, store] = await Promise.all([
164
+ readRegisters(staff),
165
+ readStoreTax(staff),
166
+ staff.orgId ? deps.pluginConfig(staff.orgId, staff.hostId).catch(()=>({})) : Promise.resolve({}),
167
+ staff.hostRef.get(),
168
+ staff.hostRef.collection('settings').doc('store').get()
169
+ ]);
170
+ const tax = posInPersonTax(taxSettings);
171
+ return _extends({
172
+ v: 1,
173
+ hostId: staff.hostId,
174
+ orgId: staff.orgId,
175
+ issuedAtMs: deps.now(),
176
+ available: tax.ok
177
+ }, 'reason' in tax ? {
178
+ unavailableReason: tax.reason
179
+ } : {}, {
180
+ tax: 'decision' in tax ? {
181
+ pct: tax.pct,
182
+ pricesIncludeTax: tax.pricesIncludeTax
183
+ } : {
184
+ pct: null,
185
+ pricesIncludeTax: false
186
+ },
187
+ maxDiscountPct: posMaxDiscountPct(config),
188
+ requireOpenShift: staff.settings.requireOpenShift,
189
+ registers: [
190
+ ...registers.entries()
191
+ ].filter(([, register])=>deps.registerWithinCap(staff.org, staff.hostId, register.rank)).map(([id, register])=>{
192
+ var _register_data_name;
193
+ return _extends({
194
+ id,
195
+ name: String((_register_data_name = register.data['name']) != null ? _register_data_name : 'Register').slice(0, 120)
196
+ }, register.data['locationId'] ? {
197
+ locationId: String(register.data['locationId'])
198
+ } : {}, {
199
+ openShiftId: posOpsCleanId(register.data['openShiftId']) || null
200
+ });
201
+ }),
202
+ receipt: _extends({
203
+ name: String((_host_get = host.get('displayName')) != null ? _host_get : '') || 'Receipt'
204
+ }, typeof host.get('logoUrl') === 'string' && host.get('logoUrl') ? {
205
+ logo: String(host.get('logoUrl'))
206
+ } : {}, staff.settings.receiptAddress ? {
207
+ address: staff.settings.receiptAddress
208
+ } : {}, store.get('receiptFooter') ? {
209
+ footer: String(store.get('receiptFooter')).slice(0, 500)
210
+ } : {}, staff.settings.returnPolicy ? {
211
+ returnPolicy: staff.settings.returnPolicy
212
+ } : {})
213
+ });
214
+ }
215
+ const refused = (saleKey, reason, error, retry)=>({
216
+ saleKey,
217
+ status: 'refused',
218
+ reason,
219
+ error,
220
+ retry
221
+ });
222
+ const replayOf = (record)=>({
223
+ saleKey: record.saleKey,
224
+ status: 'replayed',
225
+ orderId: record.orderId,
226
+ number: record.number,
227
+ flags: record.flags,
228
+ stockConflicts: record.stockConflicts
229
+ });
230
+ /** The take the plan owes on the goods after the discount (AGL-2111, AGL-2256). */ function takeFeeCents(deps, staff, lines, totals) {
231
+ let applies = false;
232
+ const gross = lines.reduce((sum, line)=>{
233
+ var _line_productType;
234
+ const pct = deps.feePct(staff.org, (_line_productType = line.productType) != null ? _line_productType : 'physical');
235
+ if (pct > 0) applies = true;
236
+ return sum + Math.round(line.unitAmountCents * line.quantity * pct / 100);
237
+ }, 0);
238
+ const charged = Math.max(0, totals.itemsCents - totals.discountCents);
239
+ const scaled = totals.itemsCents > 0 ? Math.round(gross * charged / totals.itemsCents) : 0;
240
+ return applies && charged > 0 ? Math.max(1, scaled) : scaled;
241
+ }
242
+ /**
243
+ * The steps after the commit, each recorded as it finishes. Run by the sync
244
+ * that recorded the sale, and again by any later sync of it that finds them
245
+ * unfinished.
246
+ */ async function finishSale(context, recordRef, orderRef, record) {
247
+ var _orderSnapshot_data;
248
+ const { deps, staff } = context;
249
+ const orderSnapshot = await orderRef.get();
250
+ const order = (_orderSnapshot_data = orderSnapshot.data()) != null ? _orderSnapshot_data : {};
251
+ let current = record;
252
+ if (!current.stockDone) {
253
+ var _order_lineItems;
254
+ const conflicts = [
255
+ ...current.stockConflicts
256
+ ];
257
+ const done = new Set(current.stockLines);
258
+ const lines = (_order_lineItems = order.lineItems) != null ? _order_lineItems : [];
259
+ for (const [index, line] of lines.entries()){
260
+ var _line_variantId;
261
+ if (done.has(index)) continue;
262
+ const moved = await deps.decrementStock(_extends({
263
+ hostRef: staff.hostRef,
264
+ hostId: staff.hostId,
265
+ productId: line.productId,
266
+ variantId: (_line_variantId = line.variantId) != null ? _line_variantId : 'default',
267
+ quantity: line.quantity
268
+ }, order['locationId'] ? {
269
+ locationId: String(order['locationId'])
270
+ } : {}, {
271
+ orderId: orderRef.id
272
+ }));
273
+ // A failed commit leaves the line for the next sync to take, rather than
274
+ // marking stock taken that never moved.
275
+ if (moved.failed) continue;
276
+ // Untracked stock (or a product gone since) moves nothing and is short of nothing.
277
+ const short = moved.before ? moved.applied - moved.requested : 0;
278
+ if (short > 0) {
279
+ conflicts.push(_extends({
280
+ productId: line.productId
281
+ }, line.variantId ? {
282
+ variantId: line.variantId
283
+ } : {}, {
284
+ name: [
285
+ line.name,
286
+ line.variantLabel
287
+ ].filter(Boolean).join(' — '),
288
+ requested: Math.abs(moved.requested),
289
+ applied: Math.abs(moved.applied),
290
+ shortUnits: short
291
+ }));
292
+ }
293
+ done.add(index);
294
+ await recordRef.update({
295
+ stockLines: [
296
+ ...done
297
+ ].sort((a, b)=>a - b),
298
+ stockConflicts: conflicts
299
+ });
300
+ }
301
+ const stockDone = lines.every((_line, index)=>done.has(index));
302
+ const flags = conflicts.length && !current.flags.includes('stock-short') ? [
303
+ ...current.flags,
304
+ 'stock-short'
305
+ ] : current.flags;
306
+ current = _extends({}, current, {
307
+ stockLines: [
308
+ ...done
309
+ ],
310
+ stockConflicts: conflicts,
311
+ stockDone,
312
+ flags
313
+ });
314
+ await recordRef.update({
315
+ stockDone,
316
+ flags,
317
+ stockConflicts: conflicts
318
+ });
319
+ if (conflicts.length && conflicts.length !== record.stockConflicts.length) {
320
+ const fresh = (await orderRef.get()).data();
321
+ const stamp = fresh == null ? void 0 : fresh.offline;
322
+ await orderRef.update(_extends({}, stamp ? {
323
+ offline: _extends({}, stamp, {
324
+ flags,
325
+ stockConflicts: conflicts
326
+ })
327
+ } : {}, {
328
+ timeline: CommerceModel.appendOrderEvent(fresh != null ? fresh : {}, 'offline-stock-short', conflicts.map((conflict)=>`${conflict.shortUnits} of ${conflict.requested}× ${conflict.name} not in stock`).join('; ').slice(0, 500), deps.now())
329
+ }));
330
+ }
331
+ if (!stockDone) return current;
332
+ }
333
+ if (!current.notified) {
334
+ var _order_customerEmail, _order_customerName;
335
+ const email = String((_order_customerEmail = order.customerEmail) != null ? _order_customerEmail : '');
336
+ await deps.afterSale({
337
+ hostId: staff.hostId,
338
+ orderId: orderRef.id,
339
+ order: order,
340
+ email,
341
+ name: String((_order_customerName = order.customerName) != null ? _order_customerName : '')
342
+ });
343
+ current = _extends({}, current, {
344
+ notified: true,
345
+ status: 'settled'
346
+ });
347
+ await recordRef.update({
348
+ notified: true,
349
+ status: 'settled'
350
+ });
351
+ }
352
+ return current;
353
+ }
354
+ async function syncOne(context, raw) {
355
+ var _ref, _sale_customer;
356
+ const { deps, staff } = context;
357
+ const read = sanitizePosOfflineSale(raw);
358
+ const rawKey = String((_ref = raw == null ? void 0 : raw['saleKey']) != null ? _ref : '').slice(0, 64);
359
+ if ('error' in read) return refused(rawKey, 'invalid', read.error, false);
360
+ const sale = read.sale;
361
+ if (sale.hostId !== staff.hostId) {
362
+ return refused(sale.saleKey, 'wrong-site', 'This sale was rung for another site.', false);
363
+ }
364
+ if (sale.signedInUid !== staff.uid) {
365
+ return refused(sale.saleKey, 'wrong-staff', 'This sale was rung while another member was signed in. It syncs when they sign in on this register.', true);
366
+ }
367
+ if (sale.orgId && staff.orgId && sale.orgId !== staff.orgId) {
368
+ return refused(sale.saleKey, 'wrong-workspace', 'This sale was rung in another workspace.', false);
369
+ }
370
+ const firestore = deps.firestore();
371
+ const hostRef = staff.hostRef;
372
+ const recordRef = hostRef.collection('posOfflineSales').doc(sale.saleKey);
373
+ const orderRef = hostRef.collection('orders').doc(sale.saleKey);
374
+ const existing = await recordRef.get();
375
+ if (existing.exists) {
376
+ const record = existing.data();
377
+ if (record.signedInUid !== staff.uid) {
378
+ return refused(sale.saleKey, 'conflict', 'Another sale already used this key.', false);
379
+ }
380
+ return replayOf(record.status === 'settled' ? record : await finishSale(context, recordRef, orderRef, record));
381
+ }
382
+ const now = deps.now();
383
+ const flags = new Set();
384
+ const soldAt = posOfflineSoldAt(sale.soldAtMs, now);
385
+ if (soldAt.adjusted) flags.add('clock-adjusted');
386
+ else if (now - soldAt.atMs > POS_OFFLINE_LATE_SYNC_MS) flags.add('late-sync');
387
+ // The lines as sold, checked against the catalog as it stands now. The
388
+ // price on the order is the one rung — that is what the customer paid —
389
+ // and the catalog's is kept beside it where they differ.
390
+ const productIds = [
391
+ ...new Set(sale.lines.map((line)=>line.productId))
392
+ ];
393
+ const snapshots = await Promise.all(productIds.map((id)=>hostRef.collection('products').doc(id).get()));
394
+ const products = new Map(snapshots.map((snapshot)=>[
395
+ snapshot.id,
396
+ snapshot.exists ? CommerceModel.liftLegacyProduct(snapshot.data()) : null
397
+ ]));
398
+ const priceDrift = [];
399
+ const lineItems = sale.lines.map((line, index)=>{
400
+ var _product_variants_find, _ref, _product_type;
401
+ const product = products.get(line.productId);
402
+ if (!product) {
403
+ var _line_productType;
404
+ flags.add('unknown-product');
405
+ return _extends({
406
+ productId: line.productId
407
+ }, line.variantId ? {
408
+ variantId: line.variantId
409
+ } : {}, {
410
+ name: line.name
411
+ }, line.variantLabel ? {
412
+ variantLabel: line.variantLabel
413
+ } : {}, line.sku ? {
414
+ sku: line.sku
415
+ } : {}, {
416
+ productType: (_line_productType = line.productType) != null ? _line_productType : 'physical',
417
+ quantity: line.quantity,
418
+ unitAmountCents: line.unitAmountCents
419
+ });
420
+ }
421
+ const variant = (_product_variants_find = product.variants.find((item)=>item.id === line.variantId)) != null ? _product_variants_find : product.variants[0];
422
+ const chosen = CommerceModel.resolveLineModifiers(product, line.modifiers);
423
+ const currentCents = variant && CommerceModel.variantHasPrice(variant) && chosen.ok ? Math.round(Number(variant.priceUsd) * 100) + chosen.extraCents : null;
424
+ if (currentCents !== line.unitAmountCents) {
425
+ flags.add('price-changed');
426
+ priceDrift.push({
427
+ index,
428
+ rungCents: line.unitAmountCents,
429
+ currentCents: currentCents != null ? currentCents : 0
430
+ });
431
+ }
432
+ return _extends({
433
+ productId: line.productId
434
+ }, variant && variant.id !== 'default' ? {
435
+ variantId: variant.id
436
+ } : {}, {
437
+ name: product.name || line.name
438
+ }, line.variantLabel ? {
439
+ variantLabel: line.variantLabel
440
+ } : {}, (variant == null ? void 0 : variant.sku) ? {
441
+ sku: variant.sku
442
+ } : line.sku ? {
443
+ sku: line.sku
444
+ } : {}, {
445
+ productType: (_ref = (_product_type = product.type) != null ? _product_type : line.productType) != null ? _ref : 'physical',
446
+ quantity: line.quantity,
447
+ unitAmountCents: line.unitAmountCents
448
+ }, chosen.ok && chosen.modifiers.length ? {
449
+ modifiers: chosen.modifiers
450
+ } : {});
451
+ });
452
+ // The money: what the register rang, when its own arithmetic holds; the
453
+ // arithmetic of its lines, with the tax it rang, when it does not.
454
+ let totals;
455
+ if (posOfflineTotalsAddUp(sale)) {
456
+ totals = CommerceModel.computeOrderTotals(lineItems, {
457
+ discountCents: sale.totals.discountCents,
458
+ taxCents: sale.totals.taxCents
459
+ });
460
+ } else {
461
+ flags.add('totals-restated');
462
+ const restated = posOfflineSaleTotals({
463
+ lines: sale.lines,
464
+ discountPct: sale.discountPct,
465
+ tax: {
466
+ pct: null,
467
+ pricesIncludeTax: false
468
+ }
469
+ });
470
+ totals = CommerceModel.computeOrderTotals(lineItems, {
471
+ discountCents: restated.discountCents,
472
+ taxCents: Math.min(sale.totals.taxCents, restated.itemsCents - restated.discountCents)
473
+ });
474
+ }
475
+ if ('decision' in context.tax) {
476
+ const expected = posOfflineSaleTotals({
477
+ lines: sale.lines,
478
+ discountPct: sale.discountPct,
479
+ tax: {
480
+ pct: context.tax.pct,
481
+ pricesIncludeTax: context.tax.pricesIncludeTax
482
+ }
483
+ });
484
+ if (expected.taxCents !== totals.taxCents) flags.add('tax-differs');
485
+ } else if (totals.taxCents > 0) {
486
+ flags.add('tax-differs');
487
+ }
488
+ if (sale.discountPct > posMaxDiscountPct(context.config)) flags.add('discount-over-limit');
489
+ if (sale.cashTenderedCents < totals.totalCents) flags.add('cash-short');
490
+ // Where it was rung.
491
+ const register = context.registers.get(sale.registerId);
492
+ if (!register) flags.add('unknown-register');
493
+ else if (!deps.registerWithinCap(staff.org, staff.hostId, register.rank)) flags.add('register-over-cap');
494
+ let shiftId = '';
495
+ if (sale.shiftId && register) {
496
+ const shift = await hostRef.collection('registers').doc(sale.registerId).collection('shifts').doc(sale.shiftId).get();
497
+ if (shift.exists) {
498
+ shiftId = sale.shiftId;
499
+ if (shift.get('status') !== 'open') flags.add('shift-closed');
500
+ }
501
+ }
502
+ if (!shiftId && staff.settings.requireOpenShift) flags.add('no-shift');
503
+ // Who rang it: a PIN-switched cashier's assertion is read as of the moment
504
+ // the cash was taken (it was valid then, and expiring since is the normal
505
+ // case for a sale that waited to sync), and the member is re-checked NOW.
506
+ let cashierId = staff.uid;
507
+ if (sale.cashierAssertion) {
508
+ const memberUid = await resolvePosStaffAssertion(_extends({}, deps, {
509
+ now: ()=>soldAt.atMs
510
+ }), hostRef, sale.cashierAssertion, {
511
+ hostId: staff.hostId,
512
+ registerId: sale.registerId,
513
+ purpose: 'cashier'
514
+ });
515
+ if (memberUid) cashierId = memberUid;
516
+ else flags.add('cashier-unverified');
517
+ }
518
+ const takeFee = takeFeeCents(deps, staff, lineItems, totals);
519
+ totals = _extends({}, totals, {
520
+ feeCents: takeFee
521
+ });
522
+ const changeCents = Math.max(0, sale.cashTenderedCents - totals.totalCents);
523
+ const flagList = [
524
+ ...flags
525
+ ];
526
+ const stamp = _extends({
527
+ saleKey: sale.saleKey,
528
+ soldAtMs: soldAt.atMs,
529
+ syncedAtMs: now,
530
+ syncedBy: staff.uid,
531
+ flags: flagList
532
+ }, priceDrift.length ? {
533
+ priceDrift
534
+ } : {});
535
+ const customer = (_sale_customer = sale.customer) != null ? _sale_customer : {};
536
+ const feeMonth = offlineFeeMonthKey(new Date(now));
537
+ const feeRef = staff.orgId ? firestore.collection('orgs').doc(staff.orgId).collection('offlineFees').doc(feeMonth) : null;
538
+ const counterRef = hostRef.collection('counters').doc('orders');
539
+ const committed = await firestore.runTransaction(async (transaction)=>{
540
+ var _counter_get;
541
+ const raced = await transaction.get(recordRef);
542
+ if (raced.exists) return {
543
+ raced: raced.data()
544
+ };
545
+ const taken = await transaction.get(orderRef);
546
+ if (taken.exists) return {
547
+ collision: true
548
+ };
549
+ const counter = await transaction.get(counterRef);
550
+ const number = Number((_counter_get = counter.get('next')) != null ? _counter_get : 1);
551
+ transaction.set(counterRef, {
552
+ next: number + 1
553
+ }, {
554
+ merge: true
555
+ });
556
+ const paidDetail = `Cash — received ${money(sale.cashTenderedCents)}, change ${money(changeCents)}. ` + 'Rung while the register was offline.';
557
+ const timeline = [
558
+ {
559
+ atMs: soldAt.atMs,
560
+ event: 'paid',
561
+ detail: paidDetail
562
+ },
563
+ {
564
+ atMs: now,
565
+ event: 'offline-synced',
566
+ detail: flagList.length ? `Synced. Check: ${posOfflineFlagLabels(flagList).join('; ')}`.slice(0, 1000) : 'Synced.'
567
+ }
568
+ ];
569
+ transaction.create(orderRef, CommerceModel.withOrderListFields(orderRef.id, _extends({
570
+ number,
571
+ status: 'paid',
572
+ channel: 'pos',
573
+ registerId: sale.registerId,
574
+ cashierId
575
+ }, shiftId ? {
576
+ shiftId
577
+ } : {}, customer.name ? {
578
+ customerName: customer.name
579
+ } : {}, customer.kind && customer.id ? {
580
+ customerRecord: {
581
+ kind: customer.kind,
582
+ id: customer.id
583
+ }
584
+ } : {}, sale.discountPct > 0 ? {
585
+ discountPct: sale.discountPct,
586
+ discountBy: cashierId
587
+ } : {}, sale.locationId ? {
588
+ locationId: sale.locationId
589
+ } : {}, {
590
+ lineItems,
591
+ totals,
592
+ taxMode: 'decision' in context.tax ? CommerceModel.storefrontTaxModeForDecision(context.tax.decision, totals.taxCents) : totals.taxCents > 0 ? 'manual' : 'none'
593
+ }, takeFee > 0 ? {
594
+ feeCollection: 'invoice'
595
+ } : {}, {
596
+ payments: [
597
+ {
598
+ id: 'pay_cash',
599
+ method: 'cash',
600
+ amountCents: totals.totalCents,
601
+ status: 'succeeded',
602
+ atMs: soldAt.atMs,
603
+ settledAtMs: soldAt.atMs,
604
+ takeFeeCents: takeFee,
605
+ feeCents: 0,
606
+ cashierId,
607
+ cashTenderedCents: sale.cashTenderedCents,
608
+ changeCents
609
+ }
610
+ ],
611
+ customerEmail: customer.email || null,
612
+ timeline,
613
+ offline: stamp,
614
+ createdAtMs: soldAt.atMs,
615
+ createdAt: FieldValue.serverTimestamp()
616
+ })));
617
+ const record = {
618
+ saleKey: sale.saleKey,
619
+ orderId: orderRef.id,
620
+ number,
621
+ signedInUid: staff.uid,
622
+ registerId: sale.registerId,
623
+ soldAtMs: soldAt.atMs,
624
+ syncedAtMs: now,
625
+ status: 'recorded',
626
+ flags: flagList,
627
+ stockConflicts: [],
628
+ stockLines: [],
629
+ stockDone: false,
630
+ notified: false
631
+ };
632
+ transaction.create(recordRef, record);
633
+ // The take accrues with the order, in the same transaction (AGL-2111).
634
+ if (takeFee > 0 && feeRef) {
635
+ transaction.set(feeRef, {
636
+ month: feeMonth,
637
+ feeCents: FieldValue.increment(takeFee),
638
+ orders: FieldValue.increment(1)
639
+ }, {
640
+ merge: true
641
+ });
642
+ }
643
+ return {
644
+ record
645
+ };
646
+ });
647
+ if ('collision' in committed) {
648
+ return refused(sale.saleKey, 'conflict', 'Another order already has this sale’s key.', false);
649
+ }
650
+ if ('raced' in committed) {
651
+ const record = committed.raced;
652
+ if (record.signedInUid !== staff.uid) {
653
+ return refused(sale.saleKey, 'conflict', 'Another sale already used this key.', false);
654
+ }
655
+ return replayOf(record);
656
+ }
657
+ const finished = await finishSale(context, recordRef, orderRef, committed.record);
658
+ return {
659
+ saleKey: sale.saleKey,
660
+ status: 'recorded',
661
+ orderId: orderRef.id,
662
+ number: finished.number,
663
+ flags: finished.flags,
664
+ stockConflicts: finished.stockConflicts
665
+ };
666
+ }
667
+ export async function handlePosOfflineSync(deps, req) {
668
+ var _req_query;
669
+ if (req.method !== 'GET' && req.method !== 'POST') {
670
+ return {
671
+ status: 405,
672
+ body: {
673
+ error: 'Method not allowed'
674
+ }
675
+ };
676
+ }
677
+ const body = req.method === 'GET' ? Object.fromEntries(Object.entries((_req_query = req.query) != null ? _req_query : {}).map(([key, value])=>[
678
+ key,
679
+ Array.isArray(value) ? value[0] : value
680
+ ])) : posOpsBody(req);
681
+ const gate = await authorizePosOps(deps, req, body['hostId']);
682
+ if ('error' in gate) return {
683
+ status: gate.status,
684
+ body: {
685
+ error: gate.error
686
+ }
687
+ };
688
+ const staff = gate.staff;
689
+ if (req.method === 'GET') {
690
+ return {
691
+ status: 200,
692
+ body: {
693
+ kit: await buildPosOfflineKit(deps, staff)
694
+ }
695
+ };
696
+ }
697
+ const sales = Array.isArray(body['sales']) ? body['sales'] : null;
698
+ if (!sales) return {
699
+ status: 400,
700
+ body: {
701
+ error: 'Missing sales'
702
+ }
703
+ };
704
+ if (sales.length > POS_OFFLINE_SYNC_BATCH_MAX) {
705
+ return {
706
+ status: 400,
707
+ body: {
708
+ error: `Send at most ${POS_OFFLINE_SYNC_BATCH_MAX} sales at a time`
709
+ }
710
+ };
711
+ }
712
+ if (sales.length === 0) return {
713
+ status: 200,
714
+ body: {
715
+ results: []
716
+ }
717
+ };
718
+ const [registers, taxSettings, config] = await Promise.all([
719
+ readRegisters(staff),
720
+ readStoreTax(staff),
721
+ staff.orgId ? deps.pluginConfig(staff.orgId, staff.hostId).catch(()=>({})) : Promise.resolve({})
722
+ ]);
723
+ const context = {
724
+ deps,
725
+ staff,
726
+ config,
727
+ tax: posInPersonTax(taxSettings),
728
+ registers
729
+ };
730
+ const results = [];
731
+ // One at a time, in the order they were rung, so order numbers follow the
732
+ // till and one sale's failure cannot take the rest with it.
733
+ for (const sale of sales){
734
+ try {
735
+ results.push(await syncOne(context, sale));
736
+ } catch (error) {
737
+ var _ref;
738
+ console.error('[pos-offline-sync] sale failed', error);
739
+ const key = String((_ref = sale == null ? void 0 : sale['saleKey']) != null ? _ref : '').slice(0, 64);
740
+ results.push(refused(key, 'failed', 'The sale could not be synced yet. It stays on this register.', true));
741
+ }
742
+ }
743
+ return {
744
+ status: 200,
745
+ body: {
746
+ results
747
+ }
748
+ };
749
+ }
750
+ export function createPosOfflineSyncHandler(deps = defaultPosOfflineSyncDeps) {
751
+ return async (req, res)=>{
752
+ try {
753
+ const outcome = await handlePosOfflineSync(deps(), req);
754
+ return res.status(outcome.status).json(outcome.body);
755
+ } catch (error) {
756
+ console.error('[pos-offline-sync] failed', error);
757
+ return res.status(500).json({
758
+ error: 'The offline sales could not be synced'
759
+ });
760
+ }
761
+ };
762
+ }
763
+ export const posOfflineSyncHandler = createPosOfflineSyncHandler();
764
+
765
+ //# sourceMappingURL=pos-offline-sync.js.map