@aglyn/plugins-commerce 1.0.0-beta.285 → 1.0.0-beta.287

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (420) hide show
  1. package/README.md +1 -1
  2. package/package.json +13 -13
  3. package/src/lib/components/cart.js +25 -12
  4. package/src/lib/components/cart.js.map +1 -1
  5. package/src/lib/components/commerce-console-page.js +70 -13
  6. package/src/lib/components/commerce-console-page.js.map +1 -1
  7. package/src/lib/components/console/order-detail-dialog.component.js +2 -1
  8. package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
  9. package/src/lib/components/console/payment-methods-card.component.js +1 -1
  10. package/src/lib/components/console/payment-methods-card.component.js.map +1 -1
  11. package/src/lib/components/console/pos/pos-cart-panel.component.d.ts +5 -0
  12. package/src/lib/components/console/pos/pos-cart-panel.component.js +18 -12
  13. package/src/lib/components/console/pos/pos-cart-panel.component.js.map +1 -1
  14. package/src/lib/components/console/pos/pos-hardware-api.d.ts +76 -5
  15. package/src/lib/components/console/pos/pos-hardware-api.js +53 -11
  16. package/src/lib/components/console/pos/pos-hardware-api.js.map +1 -1
  17. package/src/lib/components/console/pos/pos-hardware-buyer.component.d.ts +18 -0
  18. package/src/lib/components/console/pos/pos-hardware-buyer.component.js +629 -0
  19. package/src/lib/components/console/pos/pos-hardware-buyer.component.js.map +1 -0
  20. package/src/lib/components/console/pos/pos-hardware-sale-api.d.ts +162 -0
  21. package/src/lib/components/console/pos/pos-hardware-sale-api.js +122 -0
  22. package/src/lib/components/console/pos/pos-hardware-sale-api.js.map +1 -0
  23. package/src/lib/components/console/pos/pos-hardware-sale-terms.component.d.ts +39 -0
  24. package/src/lib/components/console/pos/pos-hardware-sale-terms.component.js +251 -0
  25. package/src/lib/components/console/pos/pos-hardware-sale-terms.component.js.map +1 -0
  26. package/src/lib/components/console/pos/use-pos-display.js +50 -0
  27. package/src/lib/components/console/pos/use-pos-display.js.map +1 -1
  28. package/src/lib/components/console/pos-cellular-control.component.d.ts +41 -0
  29. package/src/lib/components/console/pos-cellular-control.component.js +211 -0
  30. package/src/lib/components/console/pos-cellular-control.component.js.map +1 -0
  31. package/src/lib/components/console/pos-devices-card.component.d.ts +9 -1
  32. package/src/lib/components/console/pos-devices-card.component.js +47 -15
  33. package/src/lib/components/console/pos-devices-card.component.js.map +1 -1
  34. package/src/lib/components/console/pos-display/pos-display-api.d.ts +6 -0
  35. package/src/lib/components/console/pos-display/pos-display-api.js +8 -1
  36. package/src/lib/components/console/pos-display/pos-display-api.js.map +1 -1
  37. package/src/lib/components/console/pos-display-page.component.d.ts +13 -0
  38. package/src/lib/components/console/pos-display-page.component.js +44 -2
  39. package/src/lib/components/console/pos-display-page.component.js.map +1 -1
  40. package/src/lib/components/console/pos-hardware-card.component.d.ts +12 -4
  41. package/src/lib/components/console/pos-hardware-card.component.js +157 -36
  42. package/src/lib/components/console/pos-hardware-card.component.js.map +1 -1
  43. package/src/lib/components/console/pos-hardware-orders-staff-page.component.js +360 -80
  44. package/src/lib/components/console/pos-hardware-orders-staff-page.component.js.map +1 -1
  45. package/src/lib/components/console/pos-hardware-terms-page.component.d.ts +34 -0
  46. package/src/lib/components/console/pos-hardware-terms-page.component.js +257 -0
  47. package/src/lib/components/console/pos-hardware-terms-page.component.js.map +1 -0
  48. package/src/lib/components/console/pos-hardware-terms-sign-page.component.d.ts +27 -0
  49. package/src/lib/components/console/pos-hardware-terms-sign-page.component.js +104 -0
  50. package/src/lib/components/console/pos-hardware-terms-sign-page.component.js.map +1 -0
  51. package/src/lib/components/console/pos-hardware-waiting-card.component.d.ts +24 -0
  52. package/src/lib/components/console/pos-hardware-waiting-card.component.js +205 -0
  53. package/src/lib/components/console/pos-hardware-waiting-card.component.js.map +1 -0
  54. package/src/lib/components/console/pos-ops/pos-check-in-dialog.component.js +297 -201
  55. package/src/lib/components/console/pos-ops/pos-check-in-dialog.component.js.map +1 -1
  56. package/src/lib/components/console/pos-ops/pos-check-ins-card.component.d.ts +3 -0
  57. package/src/lib/components/console/pos-ops/pos-check-ins-card.component.js +260 -92
  58. package/src/lib/components/console/pos-ops/pos-check-ins-card.component.js.map +1 -1
  59. package/src/lib/components/console/pos-ops/pos-operations-bar.component.d.ts +9 -0
  60. package/src/lib/components/console/pos-ops/pos-operations-bar.component.js +15 -6
  61. package/src/lib/components/console/pos-ops/pos-operations-bar.component.js.map +1 -1
  62. package/src/lib/components/console/pos-ops/pos-rain-check-dialog.component.d.ts +25 -0
  63. package/src/lib/components/console/pos-ops/pos-rain-check-dialog.component.js +136 -0
  64. package/src/lib/components/console/pos-ops/pos-rain-check-dialog.component.js.map +1 -0
  65. package/src/lib/components/console/pos-ops/pos-shift-panel.component.d.ts +6 -0
  66. package/src/lib/components/console/pos-ops/pos-shift-panel.component.js +48 -31
  67. package/src/lib/components/console/pos-ops/pos-shift-panel.component.js.map +1 -1
  68. package/src/lib/components/console/pos-page.component.d.ts +1 -1
  69. package/src/lib/components/console/pos-page.component.js +63 -12
  70. package/src/lib/components/console/pos-page.component.js.map +1 -1
  71. package/src/lib/components/console/pos-reader-splash-setting.component.js +1 -1
  72. package/src/lib/components/console/pos-reader-splash-setting.component.js.map +1 -1
  73. package/src/lib/components/console/product-check-in-fields.component.d.ts +4 -2
  74. package/src/lib/components/console/product-check-in-fields.component.js +60 -14
  75. package/src/lib/components/console/product-check-in-fields.component.js.map +1 -1
  76. package/src/lib/components/console/product-editor-dialog.component.js +44 -1
  77. package/src/lib/components/console/product-editor-dialog.component.js.map +1 -1
  78. package/src/lib/components/console/product-hardware-sku-field.component.d.ts +19 -0
  79. package/src/lib/components/console/product-hardware-sku-field.component.js +92 -0
  80. package/src/lib/components/console/product-hardware-sku-field.component.js.map +1 -0
  81. package/src/lib/components/console/product-kiosk-offer-field.component.d.ts +22 -0
  82. package/src/lib/components/console/product-kiosk-offer-field.component.js +94 -0
  83. package/src/lib/components/console/product-kiosk-offer-field.component.js.map +1 -0
  84. package/src/lib/components/console/product-register-fields.component.d.ts +4 -0
  85. package/src/lib/components/console/product-register-fields.component.js +31 -2
  86. package/src/lib/components/console/product-register-fields.component.js.map +1 -1
  87. package/src/lib/components/console/products-hub-card.component.js +11 -2
  88. package/src/lib/components/console/products-hub-card.component.js.map +1 -1
  89. package/src/lib/components/console/register-hardware-card.component.d.ts +11 -0
  90. package/src/lib/components/console/register-hardware-card.component.js +56 -27
  91. package/src/lib/components/console/register-hardware-card.component.js.map +1 -1
  92. package/src/lib/components/console/reservation-guests-dialog.component.d.ts +28 -0
  93. package/src/lib/components/console/reservation-guests-dialog.component.js +189 -0
  94. package/src/lib/components/console/reservation-guests-dialog.component.js.map +1 -0
  95. package/src/lib/components/console/reservations-card.component.d.ts +9 -0
  96. package/src/lib/components/console/reservations-card.component.js +158 -23
  97. package/src/lib/components/console/reservations-card.component.js.map +1 -1
  98. package/src/lib/components/console/shippingeasy-card.component.js +1 -1
  99. package/src/lib/components/console/shippingeasy-card.component.js.map +1 -1
  100. package/src/lib/components/console/shipstation-card.component.d.ts +1 -1
  101. package/src/lib/components/console/shipstation-card.component.js +3 -3
  102. package/src/lib/components/console/shipstation-card.component.js.map +1 -1
  103. package/src/lib/components/product-detail.d.ts +4 -0
  104. package/src/lib/components/product-detail.js +40 -5
  105. package/src/lib/components/product-detail.js.map +1 -1
  106. package/src/lib/components/product-reviews.js +28 -11
  107. package/src/lib/components/product-reviews.js.map +1 -1
  108. package/src/lib/components/reservation-widget.js +28 -5
  109. package/src/lib/components/reservation-widget.js.map +1 -1
  110. package/src/lib/components/use-day-picker.d.ts +25 -0
  111. package/src/lib/components/use-day-picker.js +57 -0
  112. package/src/lib/components/use-day-picker.js.map +1 -0
  113. package/src/lib/constants/operator-alerts.d.ts +55 -0
  114. package/src/lib/constants/operator-alerts.js +156 -1
  115. package/src/lib/constants/operator-alerts.js.map +1 -1
  116. package/src/lib/declarations.console-server.js +54 -1
  117. package/src/lib/declarations.console-server.js.map +1 -1
  118. package/src/lib/declarations.d.ts +4 -2
  119. package/src/lib/declarations.js +11 -4
  120. package/src/lib/declarations.js.map +1 -1
  121. package/src/lib/declarations.server.js +9 -0
  122. package/src/lib/declarations.server.js.map +1 -1
  123. package/src/lib/model/commerce-cart.d.ts +9 -1
  124. package/src/lib/model/commerce-cart.js +4 -3
  125. package/src/lib/model/commerce-cart.js.map +1 -1
  126. package/src/lib/model/commerce-check-in-product.d.ts +26 -0
  127. package/src/lib/model/commerce-check-in-product.js +64 -2
  128. package/src/lib/model/commerce-check-in-product.js.map +1 -1
  129. package/src/lib/model/commerce-check-in-record.d.ts +127 -0
  130. package/src/lib/model/commerce-check-in-record.js +36 -0
  131. package/src/lib/model/commerce-check-in-record.js.map +1 -0
  132. package/src/lib/model/commerce-check-in.d.ts +91 -87
  133. package/src/lib/model/commerce-check-in.js +186 -62
  134. package/src/lib/model/commerce-check-in.js.map +1 -1
  135. package/src/lib/model/commerce-kiosk-offer.d.ts +31 -0
  136. package/src/lib/model/commerce-kiosk-offer.js +35 -0
  137. package/src/lib/model/commerce-kiosk-offer.js.map +1 -0
  138. package/src/lib/model/commerce-orders.d.ts +76 -0
  139. package/src/lib/model/commerce-orders.js +6 -0
  140. package/src/lib/model/commerce-orders.js.map +1 -1
  141. package/src/lib/model/commerce-pos-day-report.d.ts +54 -1
  142. package/src/lib/model/commerce-pos-day-report.js +39 -2
  143. package/src/lib/model/commerce-pos-day-report.js.map +1 -1
  144. package/src/lib/model/commerce-pos-offline.d.ts +1 -1
  145. package/src/lib/model/commerce-pos-offline.js +6 -1
  146. package/src/lib/model/commerce-pos-offline.js.map +1 -1
  147. package/src/lib/model/commerce-pos-ops.js +3 -2
  148. package/src/lib/model/commerce-pos-ops.js.map +1 -1
  149. package/src/lib/model/commerce-pos.d.ts +36 -3
  150. package/src/lib/model/commerce-pos.js +14 -6
  151. package/src/lib/model/commerce-pos.js.map +1 -1
  152. package/src/lib/model/commerce-receipt.js +3 -2
  153. package/src/lib/model/commerce-receipt.js.map +1 -1
  154. package/src/lib/model/commerce-reservations.d.ts +69 -4
  155. package/src/lib/model/commerce-reservations.js +57 -5
  156. package/src/lib/model/commerce-reservations.js.map +1 -1
  157. package/src/lib/model/commerce.d.ts +66 -0
  158. package/src/lib/model/commerce.js +15 -0
  159. package/src/lib/model/commerce.js.map +1 -1
  160. package/src/lib/model/order-list-fields.d.ts +11 -0
  161. package/src/lib/model/order-list-fields.js +17 -1
  162. package/src/lib/model/order-list-fields.js.map +1 -1
  163. package/src/lib/model/own-store-tax-summary.d.ts +152 -0
  164. package/src/lib/model/own-store-tax-summary.js +288 -0
  165. package/src/lib/model/own-store-tax-summary.js.map +1 -0
  166. package/src/lib/model/plugin-permissions.d.ts +67 -0
  167. package/src/lib/model/plugin-permissions.js +224 -7
  168. package/src/lib/model/plugin-permissions.js.map +1 -1
  169. package/src/lib/model/pos-cellular.d.ts +223 -0
  170. package/src/lib/model/pos-cellular.js +293 -0
  171. package/src/lib/model/pos-cellular.js.map +1 -0
  172. package/src/lib/model/pos-hardware-in-person.d.ts +98 -0
  173. package/src/lib/model/pos-hardware-in-person.js +224 -0
  174. package/src/lib/model/pos-hardware-in-person.js.map +1 -0
  175. package/src/lib/model/pos-hardware-tax-summary.d.ts +166 -0
  176. package/src/lib/model/pos-hardware-tax-summary.js +225 -0
  177. package/src/lib/model/pos-hardware-tax-summary.js.map +1 -0
  178. package/src/lib/model/pos-hardware-terms.d.ts +74 -0
  179. package/src/lib/model/pos-hardware-terms.js +115 -0
  180. package/src/lib/model/pos-hardware-terms.js.map +1 -0
  181. package/src/lib/model/pos-hardware.d.ts +349 -7
  182. package/src/lib/model/pos-hardware.js +291 -20
  183. package/src/lib/model/pos-hardware.js.map +1 -1
  184. package/src/lib/model/product-write.d.ts +10 -0
  185. package/src/lib/model/product-write.js +4 -2
  186. package/src/lib/model/product-write.js.map +1 -1
  187. package/src/lib/plugin.js +16 -0
  188. package/src/lib/plugin.js.map +1 -1
  189. package/src/lib/server/billing-webhook.js +25 -1
  190. package/src/lib/server/billing-webhook.js.map +1 -1
  191. package/src/lib/server/cancel-order.js +7 -5
  192. package/src/lib/server/cancel-order.js.map +1 -1
  193. package/src/lib/server/cart-checkout.js +20 -8
  194. package/src/lib/server/cart-checkout.js.map +1 -1
  195. package/src/lib/server/cart.js +29 -0
  196. package/src/lib/server/cart.js.map +1 -1
  197. package/src/lib/server/checkout.js +42 -13
  198. package/src/lib/server/checkout.js.map +1 -1
  199. package/src/lib/server/collection-membership.d.ts +4 -0
  200. package/src/lib/server/collection-membership.js +5 -10
  201. package/src/lib/server/collection-membership.js.map +1 -1
  202. package/src/lib/server/commerce-site-keys.d.ts +29 -0
  203. package/src/lib/server/commerce-site-keys.js +40 -0
  204. package/src/lib/server/commerce-site-keys.js.map +1 -0
  205. package/src/lib/server/draft-order.js +8 -5
  206. package/src/lib/server/draft-order.js.map +1 -1
  207. package/src/lib/server/fulfill-order.js +7 -5
  208. package/src/lib/server/fulfill-order.js.map +1 -1
  209. package/src/lib/server/gift-cards.js +8 -5
  210. package/src/lib/server/gift-cards.js.map +1 -1
  211. package/src/lib/server/local-fulfillment-status.js +9 -6
  212. package/src/lib/server/local-fulfillment-status.js.map +1 -1
  213. package/src/lib/server/member-post.js +6 -5
  214. package/src/lib/server/member-post.js.map +1 -1
  215. package/src/lib/server/membership-admin-password.d.ts +4 -2
  216. package/src/lib/server/membership-admin-password.js +10 -8
  217. package/src/lib/server/membership-admin-password.js.map +1 -1
  218. package/src/lib/server/membership-admin-remove.d.ts +7 -5
  219. package/src/lib/server/membership-admin-remove.js +9 -9
  220. package/src/lib/server/membership-admin-remove.js.map +1 -1
  221. package/src/lib/server/order-notifications.js +5 -2
  222. package/src/lib/server/order-notifications.js.map +1 -1
  223. package/src/lib/server/order-print.js +7 -5
  224. package/src/lib/server/order-print.js.map +1 -1
  225. package/src/lib/server/order-receipt-send.js +8 -5
  226. package/src/lib/server/order-receipt-send.js.map +1 -1
  227. package/src/lib/server/orders-shipping-prepare.js +9 -6
  228. package/src/lib/server/orders-shipping-prepare.js.map +1 -1
  229. package/src/lib/server/own-store-tax-return-source.d.ts +47 -0
  230. package/src/lib/server/own-store-tax-return-source.js +312 -0
  231. package/src/lib/server/own-store-tax-return-source.js.map +1 -0
  232. package/src/lib/server/payment-methods.js +13 -9
  233. package/src/lib/server/payment-methods.js.map +1 -1
  234. package/src/lib/server/pos-auth.d.ts +37 -6
  235. package/src/lib/server/pos-auth.js +40 -15
  236. package/src/lib/server/pos-auth.js.map +1 -1
  237. package/src/lib/server/pos-cellular-billing.d.ts +81 -0
  238. package/src/lib/server/pos-cellular-billing.js +711 -0
  239. package/src/lib/server/pos-cellular-billing.js.map +1 -0
  240. package/src/lib/server/pos-cellular-notify.d.ts +47 -0
  241. package/src/lib/server/pos-cellular-notify.js +150 -0
  242. package/src/lib/server/pos-cellular-notify.js.map +1 -0
  243. package/src/lib/server/pos-cellular.d.ts +88 -0
  244. package/src/lib/server/pos-cellular.js +339 -0
  245. package/src/lib/server/pos-cellular.js.map +1 -0
  246. package/src/lib/server/pos-check-in.d.ts +5 -1
  247. package/src/lib/server/pos-check-in.js +296 -28
  248. package/src/lib/server/pos-check-in.js.map +1 -1
  249. package/src/lib/server/pos-day-report.js +29 -3
  250. package/src/lib/server/pos-day-report.js.map +1 -1
  251. package/src/lib/server/pos-display.d.ts +16 -0
  252. package/src/lib/server/pos-display.js +129 -2
  253. package/src/lib/server/pos-display.js.map +1 -1
  254. package/src/lib/server/pos-hardware-admin.d.ts +10 -1
  255. package/src/lib/server/pos-hardware-admin.js +250 -84
  256. package/src/lib/server/pos-hardware-admin.js.map +1 -1
  257. package/src/lib/server/pos-hardware-attach.d.ts +105 -0
  258. package/src/lib/server/pos-hardware-attach.js +443 -0
  259. package/src/lib/server/pos-hardware-attach.js.map +1 -0
  260. package/src/lib/server/pos-hardware-buyer-lookup.d.ts +58 -0
  261. package/src/lib/server/pos-hardware-buyer-lookup.js +180 -0
  262. package/src/lib/server/pos-hardware-buyer-lookup.js.map +1 -0
  263. package/src/lib/server/pos-hardware-buyer-record.d.ts +29 -0
  264. package/src/lib/server/pos-hardware-buyer-record.js +86 -0
  265. package/src/lib/server/pos-hardware-buyer-record.js.map +1 -0
  266. package/src/lib/server/pos-hardware-cancel.d.ts +58 -0
  267. package/src/lib/server/pos-hardware-cancel.js +147 -0
  268. package/src/lib/server/pos-hardware-cancel.js.map +1 -0
  269. package/src/lib/server/pos-hardware-closure-notices.d.ts +27 -0
  270. package/src/lib/server/pos-hardware-closure-notices.js +85 -0
  271. package/src/lib/server/pos-hardware-closure-notices.js.map +1 -0
  272. package/src/lib/server/pos-hardware-closure.d.ts +60 -0
  273. package/src/lib/server/pos-hardware-closure.js +153 -0
  274. package/src/lib/server/pos-hardware-closure.js.map +1 -0
  275. package/src/lib/server/pos-hardware-in-person.d.ts +61 -0
  276. package/src/lib/server/pos-hardware-in-person.js +236 -0
  277. package/src/lib/server/pos-hardware-in-person.js.map +1 -0
  278. package/src/lib/server/pos-hardware-notify.d.ts +40 -2
  279. package/src/lib/server/pos-hardware-notify.js +195 -14
  280. package/src/lib/server/pos-hardware-notify.js.map +1 -1
  281. package/src/lib/server/pos-hardware-readers.d.ts +115 -0
  282. package/src/lib/server/pos-hardware-readers.js +430 -0
  283. package/src/lib/server/pos-hardware-readers.js.map +1 -0
  284. package/src/lib/server/pos-hardware-returns.d.ts +116 -0
  285. package/src/lib/server/pos-hardware-returns.js +502 -0
  286. package/src/lib/server/pos-hardware-returns.js.map +1 -0
  287. package/src/lib/server/pos-hardware-sale-fields.d.ts +28 -0
  288. package/src/lib/server/pos-hardware-sale-fields.js +44 -0
  289. package/src/lib/server/pos-hardware-sale-fields.js.map +1 -0
  290. package/src/lib/server/pos-hardware-sale.d.ts +54 -0
  291. package/src/lib/server/pos-hardware-sale.js +369 -0
  292. package/src/lib/server/pos-hardware-sale.js.map +1 -0
  293. package/src/lib/server/pos-hardware-tax-return-source.d.ts +99 -0
  294. package/src/lib/server/pos-hardware-tax-return-source.js +462 -0
  295. package/src/lib/server/pos-hardware-tax-return-source.js.map +1 -0
  296. package/src/lib/server/pos-hardware-terms.d.ts +64 -0
  297. package/src/lib/server/pos-hardware-terms.js +154 -0
  298. package/src/lib/server/pos-hardware-terms.js.map +1 -0
  299. package/src/lib/server/pos-hardware-user-eraser.d.ts +3 -0
  300. package/src/lib/server/pos-hardware-user-eraser.js +31 -7
  301. package/src/lib/server/pos-hardware-user-eraser.js.map +1 -1
  302. package/src/lib/server/pos-hardware-webhook.d.ts +5 -0
  303. package/src/lib/server/pos-hardware-webhook.js +51 -6
  304. package/src/lib/server/pos-hardware-webhook.js.map +1 -1
  305. package/src/lib/server/pos-hardware.d.ts +74 -1
  306. package/src/lib/server/pos-hardware.js +175 -10
  307. package/src/lib/server/pos-hardware.js.map +1 -1
  308. package/src/lib/server/pos-kiosk.d.ts +2 -0
  309. package/src/lib/server/pos-kiosk.js +17 -12
  310. package/src/lib/server/pos-kiosk.js.map +1 -1
  311. package/src/lib/server/pos-offline-card-order.d.ts +64 -0
  312. package/src/lib/server/pos-offline-card-order.js +102 -0
  313. package/src/lib/server/pos-offline-card-order.js.map +1 -0
  314. package/src/lib/server/pos-offline-card-reconcile.d.ts +67 -1
  315. package/src/lib/server/pos-offline-card-reconcile.js +215 -18
  316. package/src/lib/server/pos-offline-card-reconcile.js.map +1 -1
  317. package/src/lib/server/pos-offline-sync.d.ts +39 -0
  318. package/src/lib/server/pos-offline-sync.js +190 -55
  319. package/src/lib/server/pos-offline-sync.js.map +1 -1
  320. package/src/lib/server/pos-ops-gate.d.ts +15 -4
  321. package/src/lib/server/pos-ops-gate.js +42 -9
  322. package/src/lib/server/pos-ops-gate.js.map +1 -1
  323. package/src/lib/server/pos-ops-routes.js +24 -0
  324. package/src/lib/server/pos-ops-routes.js.map +1 -1
  325. package/src/lib/server/pos-order-refund-ids.d.ts +28 -0
  326. package/src/lib/server/pos-order-refund-ids.js +31 -0
  327. package/src/lib/server/pos-order-refund-ids.js.map +1 -0
  328. package/src/lib/server/pos-order.js +52 -49
  329. package/src/lib/server/pos-order.js.map +1 -1
  330. package/src/lib/server/pos-payment.js +1 -1
  331. package/src/lib/server/pos-payment.js.map +1 -1
  332. package/src/lib/server/pos-reader-splash-admin.js +30 -32
  333. package/src/lib/server/pos-reader-splash-admin.js.map +1 -1
  334. package/src/lib/server/pos-reader-splash-images-route.d.ts +17 -0
  335. package/src/lib/server/pos-reader-splash-images-route.js +113 -0
  336. package/src/lib/server/pos-reader-splash-images-route.js.map +1 -0
  337. package/src/lib/server/pos-reader-splash-images.d.ts +51 -0
  338. package/src/lib/server/pos-reader-splash-images.js +123 -0
  339. package/src/lib/server/pos-reader-splash-images.js.map +1 -0
  340. package/src/lib/server/pos-reader-splash.d.ts +68 -1
  341. package/src/lib/server/pos-reader-splash.js +182 -11
  342. package/src/lib/server/pos-reader-splash.js.map +1 -1
  343. package/src/lib/server/pos-readers.d.ts +29 -0
  344. package/src/lib/server/pos-readers.js +134 -35
  345. package/src/lib/server/pos-readers.js.map +1 -1
  346. package/src/lib/server/pos-return.d.ts +10 -0
  347. package/src/lib/server/pos-return.js +26 -1
  348. package/src/lib/server/pos-return.js.map +1 -1
  349. package/src/lib/server/pos-sale.js +6 -1
  350. package/src/lib/server/pos-sale.js.map +1 -1
  351. package/src/lib/server/pos-shift.js +11 -0
  352. package/src/lib/server/pos-shift.js.map +1 -1
  353. package/src/lib/server/pos-staff-pin.js +25 -20
  354. package/src/lib/server/pos-staff-pin.js.map +1 -1
  355. package/src/lib/server/pos-terminal.d.ts +14 -4
  356. package/src/lib/server/pos-terminal.js +34 -38
  357. package/src/lib/server/pos-terminal.js.map +1 -1
  358. package/src/lib/server/printers.d.ts +7 -3
  359. package/src/lib/server/printers.js +18 -12
  360. package/src/lib/server/printers.js.map +1 -1
  361. package/src/lib/server/product-drafts.d.ts +11 -1
  362. package/src/lib/server/product-drafts.js +12 -8
  363. package/src/lib/server/product-drafts.js.map +1 -1
  364. package/src/lib/server/product.d.ts +15 -1
  365. package/src/lib/server/product.js +16 -3
  366. package/src/lib/server/product.js.map +1 -1
  367. package/src/lib/server/products-write.d.ts +26 -2
  368. package/src/lib/server/products-write.js +19 -7
  369. package/src/lib/server/products-write.js.map +1 -1
  370. package/src/lib/server/refund.js +34 -11
  371. package/src/lib/server/refund.js.map +1 -1
  372. package/src/lib/server/reservation-availability-query.d.ts +8 -0
  373. package/src/lib/server/reservation-availability-query.js +11 -1
  374. package/src/lib/server/reservation-availability-query.js.map +1 -1
  375. package/src/lib/server/reservation-availability.d.ts +1 -1
  376. package/src/lib/server/reservation-availability.js +7 -2
  377. package/src/lib/server/reservation-availability.js.map +1 -1
  378. package/src/lib/server/reservation-guests.d.ts +32 -0
  379. package/src/lib/server/reservation-guests.js +285 -0
  380. package/src/lib/server/reservation-guests.js.map +1 -0
  381. package/src/lib/server/reservation-walk-in.d.ts +11 -1
  382. package/src/lib/server/reservation-walk-in.js +56 -12
  383. package/src/lib/server/reservation-walk-in.js.map +1 -1
  384. package/src/lib/server/reserve.js +18 -5
  385. package/src/lib/server/reserve.js.map +1 -1
  386. package/src/lib/server/returns.js +9 -6
  387. package/src/lib/server/returns.js.map +1 -1
  388. package/src/lib/server/reviews.d.ts +22 -2
  389. package/src/lib/server/reviews.js +88 -20
  390. package/src/lib/server/reviews.js.map +1 -1
  391. package/src/lib/server/shipping-connectors.js +10 -11
  392. package/src/lib/server/shipping-connectors.js.map +1 -1
  393. package/src/lib/server/site-page-resolver.js +20 -3
  394. package/src/lib/server/site-page-resolver.js.map +1 -1
  395. package/src/lib/server/store-day.d.ts +33 -0
  396. package/src/lib/server/store-day.js +46 -0
  397. package/src/lib/server/store-day.js.map +1 -0
  398. package/src/lib/server/store-setup-ai-writer.d.ts +2 -1
  399. package/src/lib/server/store-setup-ai-writer.js +5 -6
  400. package/src/lib/server/store-setup-ai-writer.js.map +1 -1
  401. package/src/lib/server/storefront-tax.d.ts +13 -0
  402. package/src/lib/server/storefront-tax.js +8 -1
  403. package/src/lib/server/storefront-tax.js.map +1 -1
  404. package/src/lib/server/tax-return-source.d.ts +32 -3
  405. package/src/lib/server/tax-return-source.js +99 -20
  406. package/src/lib/server/tax-return-source.js.map +1 -1
  407. package/src/lib/server.js +100 -2
  408. package/src/lib/server.js.map +1 -1
  409. package/src/lib/testing/fake-firestore.js +58 -16
  410. package/src/lib/testing/fake-firestore.js.map +1 -1
  411. package/src/lib/testing/pos-ops-memory-firestore.js +18 -4
  412. package/src/lib/testing/pos-ops-memory-firestore.js.map +1 -1
  413. package/src/lib/testing/site-register-permissions.d.ts +29 -0
  414. package/src/lib/testing/site-register-permissions.js +38 -0
  415. package/src/lib/testing/site-register-permissions.js.map +1 -0
  416. package/src/lib/transfer/tracking.server.js +8 -5
  417. package/src/lib/transfer/tracking.server.js.map +1 -1
  418. package/src/lib/utils/add-to-cart.d.ts +2 -0
  419. package/src/lib/utils/add-to-cart.js +6 -3
  420. package/src/lib/utils/add-to-cart.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/pos-hardware-notify.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { formatOperatorAlertAmount } from '@aglyn/aglyn/app-utils/operator-alerts'\nimport {\n isAccountBanLockdownReason,\n normalizeOrgLockdown,\n} from '@aglyn/aglyn/app-utils/lockdown'\nimport { POS_HARDWARE_EMAIL_KEYS, sendEmail } from '@aglyn/shared-util-email'\nimport {\n firebaseAdmin,\n hostDisplayName,\n meterPlatformEmail,\n raiseOperatorAlert,\n} from '@aglyn/tenant-data-admin'\nimport { filterSuppressedEmails } from '@aglyn/tenant-data-admin/server/email-suppression'\nimport {\n orgSystemEmailBrand,\n renderSystemEmailContent,\n} from '@aglyn/tenant-data-admin/server/render-system-email'\nimport { COMMERCE_POS_HARDWARE_ORDER } from '../constants/operator-alerts'\nimport { carrierLabelFor } from '../model/tracking-url'\nimport { formatPosHardwareCents, POS_HARDWARE_ANCHOR, type PosHardwareOrder } from '../model/pos-hardware'\nimport { posHardwareOrderNumber, posSettingsUrl } from './pos-hardware'\n\n/*==========================================\n * TELLING PEOPLE ABOUT A HARDWARE ORDER (AGL-4038).\n *\n * The buyer gets a system email at each step they wait on: received, shipped\n * (with the carrier and tracking link) and delivered (with the way to set the\n * reader up). Staff get the \"New hardware order\" operator alert, because in\n * phase 1 a person places every order with Stripe.\n *\n * Never throws. The order is already recorded when any of these run, and a\n * lost email must not undo it or turn a webhook into a redelivery.\n *=========================================*/\n\nexport type PosHardwareEmailKind = keyof typeof POS_HARDWARE_EMAIL_KEYS\n\n/** The lines as the emails list them, one per item. */\nfunction itemsText(order: PosHardwareOrder): string {\n return (order.lines ?? []).map((line) => `${line.name} × ${line.quantity}`).join('\\n')\n}\n\nfunction shipToText(order: PosHardwareOrder): string {\n const address = order.shipping?.address\n const cityLine = address\n ? [address.city, [address.state, address.postalCode].filter(Boolean).join(' ')].filter(Boolean).join(', ')\n : ''\n return [order.shipping?.name, address?.line1, address?.line2, cityLine].filter(Boolean).join('\\n')\n}\n\nasync function siteAndOrgNames(order: PosHardwareOrder): Promise<{ site: string; org: string; ban: boolean }> {\n const firestore = firebaseAdmin.app().firestore()\n const [host, org] = await Promise.all([\n firestore.collection('hosts').doc(order.hostId).get().catch(() => null),\n firestore.collection('orgs').doc(order.orgId).get().catch(() => null),\n ])\n const lock = normalizeOrgLockdown(org?.data() as never)\n return {\n site: host?.exists ? hostDisplayName(host.data() as Record<string, unknown>, order.hostId) : 'your site',\n org: String(org?.get('name') ?? '').trim() || 'your workspace',\n ban: Boolean(lock && isAccountBanLockdownReason(lock.reason)),\n }\n}\n\n/** The fallback subject and first line, when no design renders. */\nconst FALLBACK: Record<PosHardwareEmailKind, (number: string) => string> = {\n received: (number) => `We have your card reader order ${number}`,\n shipped: (number) => `Your card reader order ${number} has shipped`,\n delivered: (number) => `Your card reader order ${number} was delivered`,\n}\n\n/** The merge values for one order's emails. Exported for the render spec. */\nexport async function posHardwareEmailMerge(\n orderId: string,\n order: PosHardwareOrder,\n names: { site: string; org: string },\n): Promise<Record<string, string>> {\n const base = await posSettingsUrl(order.hostId)\n const [path] = base.split('#')\n const ordersUrl = `${path}#${POS_HARDWARE_ANCHOR}`\n return {\n 'org.name': names.org,\n 'site.name': names.site,\n 'order.number': posHardwareOrderNumber(orderId),\n 'order.items': itemsText(order),\n 'order.total': formatPosHardwareCents(order.totalCents ?? 0),\n 'order.shipTo': shipToText(order),\n 'order.shippingMethod': order.shipping?.label ?? '',\n 'order.carrier': carrierLabelFor(order.tracking?.carrier) || 'the carrier',\n 'order.trackingNumber': order.tracking?.number ?? '',\n // An unknown carrier has no tracker to link; the card shows the number.\n 'order.trackingUrl': order.tracking?.url ?? ordersUrl,\n 'order.ordersUrl': ordersUrl,\n 'order.setupUrl': `${path}#pos-devices`,\n }\n}\n\nexport async function sendPosHardwareEmail(\n kind: PosHardwareEmailKind,\n orderId: string,\n order: PosHardwareOrder,\n): Promise<void> {\n try {\n const to = String(order.contactEmail ?? '').trim()\n if (!to) return\n const names = await siteAndOrgNames(order)\n // A ban is a ban (AGL-3420): after its notice the account is sent nothing.\n if (names.ban) return\n const [recipient] = await filterSuppressedEmails([to])\n if (!recipient) return\n const merge = await posHardwareEmailMerge(orderId, order, names)\n const subject = FALLBACK[kind](merge['order.number'])\n const brand = await orgSystemEmailBrand(order.orgId)\n const content = await renderSystemEmailContent(POS_HARDWARE_EMAIL_KEYS[kind], merge, brand, {\n subject,\n text: `${subject}\\n\\n${merge['order.items']}\\n\\n${merge['order.ordersUrl']}`,\n })\n const result = await sendEmail({\n to: recipient,\n ...content,\n ...(brand.fromName ? { fromName: brand.fromName } : {}),\n context: POS_HARDWARE_EMAIL_KEYS[kind],\n })\n if (result.sent) await meterPlatformEmail(1)\n } catch (error) {\n console.error('[pos-hardware] email failed', kind, orderId, error)\n }\n}\n\n/** \"New hardware order\", once per order. */\nexport async function raisePosHardwareOrderAlert(orderId: string, order: PosHardwareOrder): Promise<void> {\n try {\n const names = await siteAndOrgNames(order)\n await raiseOperatorAlert(COMMERCE_POS_HARDWARE_ORDER, {\n dedupeKey: orderId,\n orgId: order.orgId,\n hostId: order.hostId,\n context: {\n orderNumber: posHardwareOrderNumber(orderId),\n amount: formatOperatorAlertAmount(order.totalCents ?? 0),\n site: `${names.site} (${order.hostId})`,\n items: (order.lines ?? []).map((line) => `${line.quantity} × ${line.name}`).join(', '),\n shipping: order.shipping?.label ?? 'shipping',\n },\n })\n } catch (error) {\n console.error('[pos-hardware] operator alert failed', orderId, error)\n }\n}\n"],"names":["formatOperatorAlertAmount","isAccountBanLockdownReason","normalizeOrgLockdown","POS_HARDWARE_EMAIL_KEYS","sendEmail","firebaseAdmin","hostDisplayName","meterPlatformEmail","raiseOperatorAlert","filterSuppressedEmails","orgSystemEmailBrand","renderSystemEmailContent","COMMERCE_POS_HARDWARE_ORDER","carrierLabelFor","formatPosHardwareCents","POS_HARDWARE_ANCHOR","posHardwareOrderNumber","posSettingsUrl","itemsText","order","lines","map","line","name","quantity","join","shipToText","address","shipping","cityLine","city","state","postalCode","filter","Boolean","line1","line2","siteAndOrgNames","firestore","app","host","org","Promise","all","collection","doc","hostId","get","catch","orgId","lock","data","site","exists","String","trim","ban","reason","FALLBACK","received","number","shipped","delivered","posHardwareEmailMerge","orderId","names","base","path","split","ordersUrl","totalCents","label","tracking","carrier","url","sendPosHardwareEmail","kind","to","contactEmail","recipient","merge","subject","brand","content","text","result","fromName","context","sent","error","console","raisePosHardwareOrderAlert","dedupeKey","orderNumber","amount","items"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/pos-hardware-notify.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { formatOperatorAlertAmount } from '@aglyn/aglyn/app-utils/operator-alerts'\nimport {\n isAccountBanLockdownReason,\n normalizeOrgLockdown,\n} from '@aglyn/aglyn/app-utils/lockdown'\nimport { POS_HARDWARE_EMAIL_KEYS, sendEmail } from '@aglyn/shared-util-email'\nimport { platformConsoleOrigin } from '@aglyn/aglyn/app-utils/platform-brand'\nimport {\n firebaseAdmin,\n hostDisplayName,\n meterPlatformEmail,\n raiseOperatorAlert,\n} from '@aglyn/tenant-data-admin'\nimport { filterSuppressedEmails } from '@aglyn/tenant-data-admin/server/email-suppression'\nimport {\n orgSystemEmailBrand,\n renderSystemEmailContent,\n} from '@aglyn/tenant-data-admin/server/render-system-email'\nimport {\n COMMERCE_POS_HARDWARE_CANCELED_AFTER_ORDERING,\n COMMERCE_POS_HARDWARE_ORDER,\n COMMERCE_POS_HARDWARE_REFUND_FAILED,\n} from '../constants/operator-alerts'\nimport { carrierLabelFor } from '../model/tracking-url'\nimport {\n formatPosHardwareCents,\n POS_HARDWARE_ANCHOR,\n type PosHardwareCancelReason,\n type PosHardwareOrder,\n} from '../model/pos-hardware'\nimport { hardwareOrdersRef, posHardwareOrderNumber, posSettingsUrl } from './pos-hardware'\n\n/*==========================================\n * TELLING PEOPLE ABOUT A HARDWARE ORDER (AGL-4038).\n *\n * The buyer gets a system email at each step they wait on: received, shipped\n * (with the carrier and tracking link) and delivered (with the way to set the\n * reader up), and canceled and refunded when staff cancel it before it ships\n * and choose to tell them, or the workspace is deleted or their account is\n * closed first; a reader bought in person gets \"refunded\" when staff refund\n * it and choose to tell them. The canceled and refunded emails are sent\n * ONCE, by a claim on the order ({@link sendPosHardwareEmailOnce}), so the\n * staff page and a closure never both send one. Staff get the \"New hardware order\" operator alert,\n * because in phase 1 a person places every order with Stripe, and an alert\n * when a closure cancels an order already placed with Stripe or Stripe\n * refuses a closure's refund.\n *\n * Never throws. The order is already recorded when any of these run, and a\n * lost email must not undo it or turn a webhook into a redelivery.\n *=========================================*/\n\nexport type PosHardwareEmailKind = keyof typeof POS_HARDWARE_EMAIL_KEYS\n\n/** The lines as the emails list them, one per item. */\nfunction itemsText(order: PosHardwareOrder): string {\n return (order.lines ?? []).map((line) => `${line.name} × ${line.quantity}`).join('\\n')\n}\n\nfunction shipToText(order: PosHardwareOrder): string {\n const address = order.shipping?.address\n const cityLine = address\n ? [address.city, [address.state, address.postalCode].filter(Boolean).join(' ')].filter(Boolean).join(', ')\n : ''\n return [order.shipping?.name, address?.line1, address?.line2, cityLine].filter(Boolean).join('\\n')\n}\n\nasync function siteAndOrgNames(order: PosHardwareOrder): Promise<{ site: string; org: string; ban: boolean }> {\n const firestore = firebaseAdmin.app().firestore()\n const [host, org] = await Promise.all([\n firestore.collection('hosts').doc(order.hostId).get().catch(() => null),\n firestore.collection('orgs').doc(order.orgId).get().catch(() => null),\n ])\n const lock = normalizeOrgLockdown(org?.data() as never)\n return {\n site: host?.exists ? hostDisplayName(host.data() as Record<string, unknown>, order.hostId) : 'your site',\n org: String(org?.get('name') ?? '').trim() || UNNAMED_WORKSPACE,\n ban: Boolean(lock && isAccountBanLockdownReason(lock.reason)),\n }\n}\n\n/** The fallback subject and first line, when no design renders. */\nconst FALLBACK: Record<PosHardwareEmailKind, (number: string) => string> = {\n received: (number) => `We have your card reader order ${number}`,\n shipped: (number) => `Your card reader order ${number} has shipped`,\n delivered: (number) => `Your card reader order ${number} was delivered`,\n canceled: (number) => `Your card reader order ${number} was canceled and refunded`,\n refunded: (number) => `Your refund for card reader order ${number}`,\n invited: (number) => `Your card reader order ${number} is waiting for your account`,\n returnRefunded: (number) => `We refunded your returned card reader order ${number}`,\n}\n\n/** The fallback a workspace with no name gets in a sentence. */\nconst UNNAMED_WORKSPACE = 'your workspace'\n\n/**\n * Who canceled the order and why, as the email's first sentence; the\n * template goes on \"It had not shipped yet, so we refunded …\".\n */\nfunction cancelReasonText(reason: PosHardwareCancelReason | undefined, org: string): string {\n if (reason === 'workspace-closed') {\n return org && org !== UNNAMED_WORKSPACE\n ? `We canceled your order because the ${org} workspace was deleted.`\n : 'We canceled your order because your workspace was deleted.'\n }\n if (reason === 'account-closed') return 'We canceled your order because the account that placed it was closed.'\n return 'Our team canceled your order.'\n}\n\n/** Why, for staff: the closure that canceled it, never who the buyer was. */\nfunction staffReasonText(reason: PosHardwareCancelReason, orgId: string): string {\n if (reason === 'workspace-closed') return `its workspace ${orgId} was deleted`\n if (reason === 'account-closed') return 'the account that placed it was closed'\n return 'staff canceled it'\n}\n\n/** The merge values for one order's emails. Exported for the render spec. */\nexport async function posHardwareEmailMerge(\n orderId: string,\n order: PosHardwareOrder,\n names: { site: string; org: string },\n): Promise<Record<string, string>> {\n const base = await posSettingsUrl(order.hostId)\n const [path] = base.split('#')\n const ordersUrl = `${path}#${POS_HARDWARE_ANCHOR}`\n return {\n 'org.name': names.org,\n 'site.name': names.site,\n 'order.number': posHardwareOrderNumber(orderId),\n 'order.items': itemsText(order),\n 'order.total': formatPosHardwareCents(order.totalCents ?? 0),\n 'order.shipTo': shipToText(order),\n 'order.shippingMethod': order.shipping?.label ?? '',\n 'order.carrier': carrierLabelFor(order.tracking?.carrier) || 'the carrier',\n 'order.trackingNumber': order.tracking?.number ?? '',\n // An unknown carrier has no tracker to link; the card shows the number.\n 'order.trackingUrl': order.tracking?.url ?? ordersUrl,\n 'order.ordersUrl': ordersUrl,\n 'order.setupUrl': `${path}#pos-devices`,\n // What Stripe reported refunding, or the whole charge where it has not.\n 'order.refunded': formatPosHardwareCents(order.refundedCents ?? order.totalCents ?? 0),\n // This refund alone, for an order refunded in parts; the whole of it otherwise.\n 'order.refundedNow': formatPosHardwareCents(\n (order.refunds ?? []).slice(-1)[0]?.cents ?? order.refundedCents ?? order.totalCents ?? 0,\n ),\n 'order.cancelReason': cancelReasonText(order.cancelReason, names.org),\n // What a return kept back: the original shipping and any restocking fee.\n 'order.kept': formatPosHardwareCents(Math.max(0, (order.totalCents ?? 0) - (order.refundedCents ?? 0))),\n }\n}\n\n/** What became of one email. */\nexport type PosHardwareEmailOutcome =\n /** Sent. */\n | 'sent'\n /** Nobody to send it to: no address, suppressed, or the account is banned. */\n | 'skipped'\n /** The send failed, and may be tried again. */\n | 'failed'\n\nexport async function sendPosHardwareEmail(\n kind: PosHardwareEmailKind,\n orderId: string,\n order: PosHardwareOrder,\n): Promise<PosHardwareEmailOutcome> {\n try {\n const to = String(order.contactEmail ?? '').trim()\n if (!to) return 'skipped'\n const names = await siteAndOrgNames(order)\n // A ban is a ban (AGL-3420): after its notice the account is sent nothing.\n if (names.ban) return 'skipped'\n const [recipient] = await filterSuppressedEmails([to])\n if (!recipient) return 'skipped'\n const merge = await posHardwareEmailMerge(orderId, order, names)\n const subject = FALLBACK[kind](merge['order.number'])\n // A refund in person is in the selling workspace's brand, as its\n // invitation is; the rest in the buyer's.\n const brand = await orgSystemEmailBrand(kind === 'refunded' ? (order.posSale?.orgId ?? order.orgId) : order.orgId)\n // A canceled order's workspace may be gone, so its fallback names the\n // refund rather than linking a card that no longer opens.\n const last =\n kind === 'canceled'\n ? `Refunded: ${merge['order.refunded']}`\n : kind === 'refunded'\n ? `Refunded now: ${merge['order.refundedNow']}`\n : merge['order.ordersUrl']\n const content = await renderSystemEmailContent(POS_HARDWARE_EMAIL_KEYS[kind], merge, brand, {\n subject,\n text: `${subject}\\n\\n${merge['order.items']}\\n\\n${last}`,\n })\n const result = await sendEmail({\n to: recipient,\n ...content,\n ...(brand.fromName ? { fromName: brand.fromName } : {}),\n context: POS_HARDWARE_EMAIL_KEYS[kind],\n })\n if (!result.sent) return 'failed'\n await meterPlatformEmail(1)\n return 'sent'\n } catch (error) {\n console.error('[pos-hardware] email failed', kind, orderId, error)\n return 'failed'\n }\n}\n\n/** How long a claimed send that never finished holds the next one back. */\nconst EMAIL_CLAIM_STALE_MS = 10 * 60 * 1000\n\n/**\n * Sends one email for an order ONCE, under `key` (the kind by default; one\n * per refund for a refund in parts). The claim is a field on the order,\n * `buyerEmails.{key}`, taken in a transaction before the send, so the staff\n * page and a closure, a retried press or two staff at once, send it once\n * between them. A send that failed can be claimed again; one that found\n * nobody to send to is not tried again. Never throws.\n */\nexport async function sendPosHardwareEmailOnce(\n kind: PosHardwareEmailKind,\n orderId: string,\n order: PosHardwareOrder,\n key: string = kind,\n): Promise<PosHardwareEmailOutcome | 'already'> {\n try {\n const firestore = firebaseAdmin.app().firestore()\n const ref = hardwareOrdersRef(order.orgId).doc(orderId)\n const claimed = await firestore.runTransaction(async (transaction: any) => {\n const snapshot = await transaction.get(ref)\n if (!snapshot.exists) return false\n const held = (snapshot.data()?.buyerEmails ?? {})[key] as { state?: string; atMs?: number } | undefined\n const now = Date.now()\n if (held?.state === 'sent' || held?.state === 'skipped') return false\n if (held?.state === 'sending' && now - Number(held.atMs ?? 0) < EMAIL_CLAIM_STALE_MS) return false\n transaction.set(ref, { buyerEmails: { [key]: { state: 'sending', atMs: now } } }, { merge: true })\n return true\n })\n if (!claimed) return 'already'\n const outcome = await sendPosHardwareEmail(kind, orderId, order)\n await ref\n .set({ buyerEmails: { [key]: { state: outcome === 'sent' ? 'sent' : outcome, atMs: Date.now() } } }, { merge: true })\n .catch((error: unknown) => console.error('[pos-hardware] email claim not settled', kind, orderId, error))\n return outcome\n } catch (error) {\n console.error('[pos-hardware] email claim failed', kind, orderId, error)\n return 'failed'\n }\n}\n\n/**\n * The invitation to sign up (AGL-4038), for someone who bought a card reader\n * in person at the platform's own store with no account yet: create the\n * account with this address and the order joins their workspace on its own.\n * Sent in the selling workspace's brand, which is the platform's. Never\n * throws; the caller has already claimed the send.\n */\n/** The invitation's merge values. Exported for the render spec. */\nexport function posHardwareInviteMerge(orderId: string, order: PosHardwareOrder): Record<string, string> {\n return {\n 'order.number': posHardwareOrderNumber(orderId),\n 'order.items': itemsText(order),\n 'order.total': formatPosHardwareCents(order.totalCents ?? 0),\n 'order.signUpUrl': `${platformConsoleOrigin()}/signup`,\n }\n}\n\nexport async function sendPosHardwareInvite(orderId: string, order: PosHardwareOrder): Promise<void> {\n try {\n const to = String(order.attachment?.email ?? '').trim()\n if (!to) return\n const [recipient] = await filterSuppressedEmails([to])\n if (!recipient) return\n const merge = posHardwareInviteMerge(orderId, order)\n const signUpUrl = merge['order.signUpUrl']\n const subject = FALLBACK.invited(merge['order.number'])\n const brand = await orgSystemEmailBrand(order.posSale?.orgId ?? order.orgId)\n const content = await renderSystemEmailContent(POS_HARDWARE_EMAIL_KEYS.invited, merge, brand, {\n subject,\n text: `${subject}\\n\\n${merge['order.items']}\\n\\nCreate your account with this email address: ${signUpUrl}`,\n })\n const result = await sendEmail({\n to: recipient,\n ...content,\n ...(brand.fromName ? { fromName: brand.fromName } : {}),\n context: POS_HARDWARE_EMAIL_KEYS.invited,\n })\n if (result.sent) await meterPlatformEmail(1)\n } catch (error) {\n console.error('[pos-hardware] invitation failed', orderId, error)\n }\n}\n\n/**\n * A closure canceled an order staff had already placed with Stripe: the\n * merchant is refunded, and Stripe will still ship it unless someone cancels\n * it there. Once per order.\n */\nexport async function raisePosHardwareCanceledAfterOrderingAlert(\n orderId: string,\n order: PosHardwareOrder,\n reason: PosHardwareCancelReason,\n): Promise<void> {\n try {\n const stripeOrderId = String(order.stripeHardwareOrderId ?? '').trim()\n await raiseOperatorAlert(COMMERCE_POS_HARDWARE_CANCELED_AFTER_ORDERING, {\n dedupeKey: orderId,\n orgId: order.orgId,\n hostId: order.hostId,\n context: {\n orderNumber: posHardwareOrderNumber(orderId),\n amount: formatOperatorAlertAmount(order.totalCents ?? 0),\n items: (order.lines ?? []).map((line) => `${line.quantity} × ${line.name}`).join(', '),\n reason: staffReasonText(reason, order.orgId),\n stripeOrder: stripeOrderId ? ` (Stripe order ${stripeOrderId})` : '',\n },\n })\n } catch (error) {\n console.error('[pos-hardware] canceled-after-ordering alert failed', orderId, error)\n }\n}\n\n/**\n * Stripe refused a closure's refund, and the closure went ahead without it.\n * Carries the payment to refund by hand, never the buyer.\n */\nexport async function raisePosHardwareRefundFailedAlert(\n orderId: string,\n order: PosHardwareOrder,\n reason: PosHardwareCancelReason,\n error: string,\n): Promise<void> {\n try {\n const stripeOrderId = String(order.stripeHardwareOrderId ?? '').trim()\n await raiseOperatorAlert(COMMERCE_POS_HARDWARE_REFUND_FAILED, {\n dedupeKey: orderId,\n orgId: order.orgId,\n hostId: order.hostId,\n context: {\n orderNumber: posHardwareOrderNumber(orderId),\n amount: formatOperatorAlertAmount(order.totalCents ?? 0),\n reason: staffReasonText(reason, order.orgId),\n error: error || 'no reason given',\n paymentIntentId: order.stripePaymentIntentId ?? 'for this order (no payment id is recorded on it)',\n orderedNote:\n order.status === 'ordered'\n ? `. It had already been placed with Stripe${stripeOrderId ? ` as ${stripeOrderId}` : ''}, so cancel it there too before it ships`\n : '',\n },\n })\n } catch (failure) {\n console.error('[pos-hardware] refund-failed alert failed', orderId, failure)\n }\n}\n\n/** \"New hardware order\", once per order. */\nexport async function raisePosHardwareOrderAlert(orderId: string, order: PosHardwareOrder): Promise<void> {\n try {\n const names = await siteAndOrgNames(order)\n await raiseOperatorAlert(COMMERCE_POS_HARDWARE_ORDER, {\n dedupeKey: orderId,\n orgId: order.orgId,\n hostId: order.hostId,\n context: {\n orderNumber: posHardwareOrderNumber(orderId),\n amount: formatOperatorAlertAmount(order.totalCents ?? 0),\n site: `${names.site} (${order.hostId})`,\n items: (order.lines ?? []).map((line) => `${line.quantity} × ${line.name}`).join(', '),\n shipping: order.shipping?.label ?? 'shipping',\n },\n })\n } catch (error) {\n console.error('[pos-hardware] operator alert failed', orderId, error)\n }\n}\n"],"names":["formatOperatorAlertAmount","isAccountBanLockdownReason","normalizeOrgLockdown","POS_HARDWARE_EMAIL_KEYS","sendEmail","platformConsoleOrigin","firebaseAdmin","hostDisplayName","meterPlatformEmail","raiseOperatorAlert","filterSuppressedEmails","orgSystemEmailBrand","renderSystemEmailContent","COMMERCE_POS_HARDWARE_CANCELED_AFTER_ORDERING","COMMERCE_POS_HARDWARE_ORDER","COMMERCE_POS_HARDWARE_REFUND_FAILED","carrierLabelFor","formatPosHardwareCents","POS_HARDWARE_ANCHOR","hardwareOrdersRef","posHardwareOrderNumber","posSettingsUrl","itemsText","order","lines","map","line","name","quantity","join","shipToText","address","shipping","cityLine","city","state","postalCode","filter","Boolean","line1","line2","siteAndOrgNames","firestore","app","host","org","Promise","all","collection","doc","hostId","get","catch","orgId","lock","data","site","exists","String","trim","UNNAMED_WORKSPACE","ban","reason","FALLBACK","received","number","shipped","delivered","canceled","refunded","invited","returnRefunded","cancelReasonText","staffReasonText","posHardwareEmailMerge","orderId","names","base","path","split","ordersUrl","totalCents","label","tracking","carrier","url","refundedCents","refunds","slice","cents","cancelReason","Math","max","sendPosHardwareEmail","kind","to","contactEmail","recipient","merge","subject","brand","posSale","last","content","text","result","fromName","context","sent","error","console","EMAIL_CLAIM_STALE_MS","sendPosHardwareEmailOnce","key","ref","claimed","runTransaction","transaction","held","snapshot","buyerEmails","now","Date","Number","atMs","set","outcome","posHardwareInviteMerge","sendPosHardwareInvite","attachment","email","signUpUrl","raisePosHardwareCanceledAfterOrderingAlert","stripeOrderId","stripeHardwareOrderId","dedupeKey","orderNumber","amount","items","stripeOrder","raisePosHardwareRefundFailedAlert","paymentIntentId","stripePaymentIntentId","orderedNote","status","failure","raisePosHardwareOrderAlert"],"mappings":"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"}
@@ -0,0 +1,115 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import { type PosHardwareInPersonConfig, type PosHardwareOrder } from '../model/pos-hardware';
18
+ import type { PosTerminalAddress } from './pos-terminal';
19
+ export declare class PosHardwareReaderRefusal extends Error {
20
+ readonly status: number;
21
+ /** A refusal the register answers with a step of its own: `needs-address` asks for the store's address. */
22
+ readonly reason?: 'needs-address';
23
+ constructor(message: string, status: number,
24
+ /** A refusal the register answers with a step of its own: `needs-address` asks for the store's address. */
25
+ reason?: 'needs-address');
26
+ }
27
+ /**
28
+ * A store address typed at the booth, read the way the POS devices card
29
+ * sends it (AGL-4038): each field a trimmed string within the lengths the
30
+ * reader registration keeps, the country as two capitals. Anything that is
31
+ * not an object reads as no address.
32
+ */
33
+ export declare function boothStoreAddress(raw: unknown): PosTerminalAddress | null;
34
+ /**
35
+ * A reader was just registered to a store: the in-person order that sold it
36
+ * by this serial moves on. Attached to this workspace, or pending (then
37
+ * attached to it now); an order attached to another workspace is left as it
38
+ * is. Returns the orders it changed.
39
+ */
40
+ export declare function matchRegisteredPosHardwareReader(input: {
41
+ hostId: string;
42
+ orgId: string;
43
+ uid: string;
44
+ readerId: string;
45
+ serialNumber: string;
46
+ now?: number;
47
+ }): Promise<{
48
+ matched: string[];
49
+ }>;
50
+ /**
51
+ * The serial numbers of a sale's readers, taken at the sale: on the hardware
52
+ * order once it is recorded, or on the register sale until it is (the
53
+ * recorder takes them from there). Each is normalized, none may repeat, and
54
+ * none may already be on another sale.
55
+ */
56
+ export declare function recordPosHardwareSerials(input: {
57
+ config: PosHardwareInPersonConfig;
58
+ registerOrderId?: string | null;
59
+ orderId?: string | null;
60
+ serials: unknown;
61
+ }): Promise<{
62
+ orderId: string;
63
+ serials: string[];
64
+ recorded: boolean;
65
+ }>;
66
+ /**
67
+ * The store a reader bought in person is for, chosen at setup by someone
68
+ * who may set up devices there. The store must be the workspace's.
69
+ */
70
+ export declare function choosePosHardwareStore(input: {
71
+ orgId: string;
72
+ orderId: string;
73
+ hostId: string;
74
+ }): Promise<PosHardwareOrder>;
75
+ /**
76
+ * "Mark set up": a reader bought in person was paired by its code or by
77
+ * Bluetooth with no serial taken at the sale, so nothing matched it. The
78
+ * workspace says so, and the order moves to Set up.
79
+ */
80
+ export declare function markPosHardwareSetUp(input: {
81
+ orgId: string;
82
+ orderId: string;
83
+ }): Promise<PosHardwareOrder>;
84
+ /** A store's readiness for a reader: its plan and its Location. */
85
+ export declare function posHardwareStoreReadiness(hostId: string): Promise<{
86
+ posPlan: boolean;
87
+ hasLocation: boolean;
88
+ }>;
89
+ /**
90
+ * Registers a reader sold at the booth to the buyer's chosen store, by the
91
+ * code it shows, while the buyer is there (AGL-4038). The sale must be
92
+ * attached to them with a store chosen, and the store's plan must include
93
+ * the point of sale.
94
+ *
95
+ * A store with no reader Location yet needs its address, which is where
96
+ * Stripe sets the reader up for. Booth staff may type it with the buyer
97
+ * (`address`): it goes exactly where the store's POS devices card would put
98
+ * it, through the same registration, which creates the store's Location from
99
+ * it and records it on the store's terminal settings. Without one the booth
100
+ * refuses with `needs-address`, and the buyer can add it later on that card.
101
+ * A store that already has its Location keeps it: an address sent for it is
102
+ * never used.
103
+ */
104
+ export declare function registerPosHardwareAtBooth(input: {
105
+ config: PosHardwareInPersonConfig;
106
+ orderId: string;
107
+ registrationCode: unknown;
108
+ label?: unknown;
109
+ address?: unknown;
110
+ uid: string;
111
+ }): Promise<{
112
+ order: PosHardwareOrder;
113
+ readerId: string;
114
+ storeAddress: PosTerminalAddress | null;
115
+ }>;
@@ -0,0 +1,430 @@
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 { firebaseAdmin, getOrgForHost } from "@aglyn/tenant-data-admin";
19
+ import { normalizePosHardwareSerial, POS_HARDWARE_ORDER_ID, POS_HARDWARE_ORDERS_COLLECTION, posHardwareSaleRecord, posHardwareSaleSetOptions, posHardwareSku } from "../model/pos-hardware.js";
20
+ import { posHardwareAttachmentOf } from "../model/pos-hardware-in-person.js";
21
+ import { fillPosHardwareBuyerAddress } from "./pos-hardware-buyer-record.js";
22
+ import { hardwareOrdersRef, posHardwareInPersonOrderId, posHardwareSaleRef } from "./pos-hardware.js";
23
+ /*==========================================
24
+ * A CARD READER SOLD IN PERSON, ONTO THE BUYER'S STORE (AGL-4038).
25
+ *
26
+ * Three ways, and every one ends with the order at Set up:
27
+ *
28
+ * 1. The serial number taken at the sale. Staff scan or type each reader's
29
+ * serial on the sale; when the buyer registers a reader with that
30
+ * serial (by its code, on the POS devices card), the reader is matched
31
+ * to its unit here and the order moves to Set up once every reader on
32
+ * it is — no step for the buyer. A sale nobody had attached yet is
33
+ * attached to the workspace that registered its reader: only whoever
34
+ * holds the reader can show its code.
35
+ * 2. Registered at the booth. A register user registers the reader to the
36
+ * store the buyer chose, by its code, while the buyer stands there:
37
+ * the store's plan must include the point of sale and the store must
38
+ * have a reader Location (its address), as for any registration.
39
+ * 3. Paired later with no serial. The buyer registers it by code (or pairs
40
+ * an M2 by Bluetooth, which no server sees) and says "Mark set up" on
41
+ * the Hardware card; staff can mark it too.
42
+ *=========================================*/ export class PosHardwareReaderRefusal extends Error {
43
+ constructor(message, status, /** A refusal the register answers with a step of its own: `needs-address` asks for the store's address. */ reason){
44
+ super(message), this.status = status, this.reason = reason;
45
+ }
46
+ }
47
+ /**
48
+ * A store address typed at the booth, read the way the POS devices card
49
+ * sends it (AGL-4038): each field a trimmed string within the lengths the
50
+ * reader registration keeps, the country as two capitals. Anything that is
51
+ * not an object reads as no address.
52
+ */ export function boothStoreAddress(raw) {
53
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return null;
54
+ const field = (key, max)=>{
55
+ var _raw_key;
56
+ return String((_raw_key = raw[key]) != null ? _raw_key : '').trim().slice(0, max);
57
+ };
58
+ const line2 = field('line2', 200);
59
+ const state = field('state', 100);
60
+ return _extends({
61
+ line1: field('line1', 200)
62
+ }, line2 ? {
63
+ line2
64
+ } : {}, {
65
+ city: field('city', 100)
66
+ }, state ? {
67
+ state
68
+ } : {}, {
69
+ postalCode: field('postalCode', 20),
70
+ country: field('country', 2).toUpperCase()
71
+ });
72
+ }
73
+ function firestore() {
74
+ return firebaseAdmin.app().firestore();
75
+ }
76
+ /** Whether every reader on the order is registered: then it is Set up. */ function everyReaderRegistered(units) {
77
+ return units.length > 0 && units.every((unit)=>Boolean(unit.readerId));
78
+ }
79
+ /** The order's units with `serial` registered as `readerId` on `hostId`, or null when no unit has it. */ function withRegisteredUnit(units, serial, readerId, hostId, now) {
80
+ const at = units.findIndex((unit)=>unit.serialNumber === serial);
81
+ if (at < 0) return null;
82
+ if (units[at].readerId === readerId) return [
83
+ ...units
84
+ ];
85
+ return units.map((unit, index)=>index === at ? _extends({}, unit, {
86
+ readerId,
87
+ hostId,
88
+ registeredAtMs: now
89
+ }) : unit);
90
+ }
91
+ /**
92
+ * A reader was just registered to a store: the in-person order that sold it
93
+ * by this serial moves on. Attached to this workspace, or pending (then
94
+ * attached to it now); an order attached to another workspace is left as it
95
+ * is. Returns the orders it changed.
96
+ */ export async function matchRegisteredPosHardwareReader(input) {
97
+ const serial = normalizePosHardwareSerial(input.serialNumber);
98
+ if (!serial || !input.orgId) return {
99
+ matched: []
100
+ };
101
+ const found = await firestore().collectionGroup(POS_HARDWARE_ORDERS_COLLECTION).where('serialNumbers', 'array-contains', serial).limit(5).get();
102
+ const matched = [];
103
+ for (const doc of found.docs){
104
+ var _input_now;
105
+ const orderId = String(doc.id);
106
+ const now = (_input_now = input.now) != null ? _input_now : Date.now();
107
+ const changed = await firestore().runTransaction(async (transaction)=>{
108
+ var _ref, _sale_get, _before_units, _ref1, _ref2, _ref3;
109
+ var _before_attachment, _before_attachment1, _before_attachment2, _before_attachment3;
110
+ const saleRef = posHardwareSaleRef(orderId);
111
+ const sale = await transaction.get(saleRef);
112
+ const fromOrgId = String((_ref = (_sale_get = sale.get('orgId')) != null ? _sale_get : doc.data().orgId) != null ? _ref : '');
113
+ const fromRef = hardwareOrdersRef(fromOrgId).doc(orderId);
114
+ const from = await transaction.get(fromRef);
115
+ if (!from.exists) return false;
116
+ const before = from.data();
117
+ if (before.source !== 'in_person' || before.status === 'canceled' || before.status === 'refunded') return false;
118
+ const pending = ((_before_attachment = before.attachment) == null ? void 0 : _before_attachment.state) !== 'attached';
119
+ if (!pending && fromOrgId !== input.orgId) return false;
120
+ const units = withRegisteredUnit((_before_units = before.units) != null ? _before_units : [], serial, input.readerId, input.hostId, now);
121
+ if (!units) return false;
122
+ const done = everyReaderRegistered(units);
123
+ const after = _extends({}, before, pending ? {
124
+ orgId: input.orgId,
125
+ hostId: input.hostId,
126
+ createdBy: input.uid,
127
+ attachment: _extends({}, posHardwareAttachmentOf({
128
+ uid: input.uid,
129
+ orgId: input.orgId,
130
+ hostId: input.hostId,
131
+ email: (_ref1 = (_before_attachment1 = before.attachment) == null ? void 0 : _before_attachment1.email) != null ? _ref1 : null,
132
+ attachedBy: '',
133
+ attachedAtMs: now,
134
+ // What the register typed of the buyer stays (AGL-4038).
135
+ name: (_ref2 = (_before_attachment2 = before.attachment) == null ? void 0 : _before_attachment2.name) != null ? _ref2 : null,
136
+ address: (_ref3 = (_before_attachment3 = before.attachment) == null ? void 0 : _before_attachment3.address) != null ? _ref3 : null
137
+ }))
138
+ } : {
139
+ hostId: before.hostId || input.hostId
140
+ }, {
141
+ units
142
+ }, done && before.status === 'delivered' ? {
143
+ status: 'registered',
144
+ registeredAtMs: now
145
+ } : {}, {
146
+ updatedAtMs: now
147
+ });
148
+ if (after.orgId === fromOrgId) {
149
+ transaction.set(fromRef, after);
150
+ } else {
151
+ transaction.create(hardwareOrdersRef(after.orgId).doc(orderId), after);
152
+ transaction.delete(fromRef);
153
+ }
154
+ transaction.set(saleRef, posHardwareSaleRecord(orderId, after), posHardwareSaleSetOptions(after));
155
+ return true;
156
+ });
157
+ if (changed) matched.push(orderId);
158
+ }
159
+ // The buyer's address for the reseller's records, from the store the
160
+ // reader is now on, where the sale has none yet.
161
+ for (const orderId of matched)await fillPosHardwareBuyerAddress({
162
+ orgId: input.orgId,
163
+ orderId
164
+ });
165
+ return {
166
+ matched
167
+ };
168
+ }
169
+ /**
170
+ * The serial numbers of a sale's readers, taken at the sale: on the hardware
171
+ * order once it is recorded, or on the register sale until it is (the
172
+ * recorder takes them from there). Each is normalized, none may repeat, and
173
+ * none may already be on another sale.
174
+ */ export async function recordPosHardwareSerials(input) {
175
+ var _input_registerOrderId, _input_orderId;
176
+ const serials = (Array.isArray(input.serials) ? input.serials : []).map(normalizePosHardwareSerial).filter(Boolean);
177
+ if (new Set(serials).size !== serials.length) {
178
+ throw new PosHardwareReaderRefusal('A serial number is listed twice.', 400);
179
+ }
180
+ const registerOrderId = String((_input_registerOrderId = input.registerOrderId) != null ? _input_registerOrderId : '');
181
+ const orderId = registerOrderId ? posHardwareInPersonOrderId(input.config.sellerHostId, registerOrderId) : String((_input_orderId = input.orderId) != null ? _input_orderId : '');
182
+ if (!POS_HARDWARE_ORDER_ID.test(orderId)) throw new PosHardwareReaderRefusal('Name the sale.', 400);
183
+ for (const serial of serials){
184
+ const elsewhere = await firestore().collectionGroup(POS_HARDWARE_ORDERS_COLLECTION).where('serialNumbers', 'array-contains', serial).limit(2).get();
185
+ if (elsewhere.docs.some((doc)=>String(doc.id) !== orderId)) {
186
+ throw new PosHardwareReaderRefusal(`Serial number ${serial} is already on another sale.`, 409);
187
+ }
188
+ }
189
+ const saleRef = posHardwareSaleRef(orderId);
190
+ return firestore().runTransaction(async (transaction)=>{
191
+ var _sale_get, _before_units;
192
+ var _before_posSale;
193
+ const sale = await transaction.get(saleRef);
194
+ if (!sale.exists) {
195
+ var _register_get;
196
+ if (!registerOrderId) throw new PosHardwareReaderRefusal('No such card reader sale.', 404);
197
+ const registerRef = firestore().collection('hosts').doc(input.config.sellerHostId).collection('orders').doc(registerOrderId);
198
+ const register = await transaction.get(registerRef);
199
+ const status = String((_register_get = register.get('status')) != null ? _register_get : '');
200
+ if (!register.exists || status !== 'pending' && status !== 'paid') {
201
+ throw new PosHardwareReaderRefusal('No open or paid sale on this register by that number.', 404);
202
+ }
203
+ transaction.set(registerRef, {
204
+ hardwareSerials: serials
205
+ }, {
206
+ merge: true
207
+ });
208
+ return {
209
+ orderId,
210
+ serials,
211
+ recorded: false
212
+ };
213
+ }
214
+ const ref = hardwareOrdersRef(String((_sale_get = sale.get('orgId')) != null ? _sale_get : '')).doc(orderId);
215
+ const snapshot = await transaction.get(ref);
216
+ if (!snapshot.exists) throw new PosHardwareReaderRefusal('No such card reader sale.', 404);
217
+ const before = snapshot.data();
218
+ if (before.source !== 'in_person' || ((_before_posSale = before.posSale) == null ? void 0 : _before_posSale.hostId) !== input.config.sellerHostId) {
219
+ throw new PosHardwareReaderRefusal('Only a card reader sold in person here takes serial numbers.', 409);
220
+ }
221
+ const units = (_before_units = before.units) != null ? _before_units : [];
222
+ if (serials.length > units.length) {
223
+ throw new PosHardwareReaderRefusal(`This sale has ${units.length} reader${units.length === 1 ? '' : 's'}.`, 400);
224
+ }
225
+ // Serials fill the readers not yet set up, in order; a registered one keeps its own.
226
+ const open = units.map((unit, index)=>({
227
+ unit,
228
+ index
229
+ })).filter(({ unit })=>!unit.readerId);
230
+ const next = [
231
+ ...units
232
+ ];
233
+ open.forEach(({ index }, position)=>{
234
+ var _serials_position;
235
+ next[index] = _extends({}, units[index], {
236
+ serialNumber: (_serials_position = serials[position]) != null ? _serials_position : null
237
+ });
238
+ });
239
+ transaction.update(ref, {
240
+ units: next,
241
+ serialNumbers: next.flatMap((unit)=>unit.serialNumber ? [
242
+ unit.serialNumber
243
+ ] : []),
244
+ updatedAtMs: Date.now()
245
+ });
246
+ return {
247
+ orderId,
248
+ serials,
249
+ recorded: true
250
+ };
251
+ });
252
+ }
253
+ /** An in-person order of this workspace, for a change by its own people. */ function workspaceOrder(orgId, orderId) {
254
+ if (!POS_HARDWARE_ORDER_ID.test(orderId)) throw new PosHardwareReaderRefusal('No such order.', 404);
255
+ return {
256
+ ref: hardwareOrdersRef(orgId).doc(orderId)
257
+ };
258
+ }
259
+ /**
260
+ * The store a reader bought in person is for, chosen at setup by someone
261
+ * who may set up devices there. The store must be the workspace's.
262
+ */ export async function choosePosHardwareStore(input) {
263
+ const { ref } = workspaceOrder(input.orgId, input.orderId);
264
+ const chosen = await firestore().runTransaction(async (transaction)=>{
265
+ const snapshot = await transaction.get(ref);
266
+ if (!snapshot.exists) throw new PosHardwareReaderRefusal('No such order.', 404);
267
+ const before = snapshot.data();
268
+ if (before.source !== 'in_person') throw new PosHardwareReaderRefusal('Only a reader bought in person waits for a store.', 409);
269
+ const after = _extends({}, before, {
270
+ hostId: input.hostId
271
+ }, before.attachment ? {
272
+ attachment: _extends({}, before.attachment, {
273
+ hostId: input.hostId
274
+ })
275
+ } : {}, {
276
+ updatedAtMs: Date.now()
277
+ });
278
+ transaction.set(ref, after);
279
+ transaction.set(posHardwareSaleRef(input.orderId), posHardwareSaleRecord(input.orderId, after), posHardwareSaleSetOptions(after));
280
+ return after;
281
+ });
282
+ await fillPosHardwareBuyerAddress({
283
+ orgId: input.orgId,
284
+ orderId: input.orderId
285
+ });
286
+ return chosen;
287
+ }
288
+ /**
289
+ * "Mark set up": a reader bought in person was paired by its code or by
290
+ * Bluetooth with no serial taken at the sale, so nothing matched it. The
291
+ * workspace says so, and the order moves to Set up.
292
+ */ export async function markPosHardwareSetUp(input) {
293
+ const { ref } = workspaceOrder(input.orgId, input.orderId);
294
+ return firestore().runTransaction(async (transaction)=>{
295
+ const snapshot = await transaction.get(ref);
296
+ if (!snapshot.exists) throw new PosHardwareReaderRefusal('No such order.', 404);
297
+ const before = snapshot.data();
298
+ if (before.source !== 'in_person') throw new PosHardwareReaderRefusal('Only a reader bought in person is marked set up here.', 409);
299
+ if (before.status === 'registered') return before;
300
+ if (before.status !== 'delivered') throw new PosHardwareReaderRefusal('This order can no longer be set up.', 409);
301
+ const now = Date.now();
302
+ const after = _extends({}, before, {
303
+ status: 'registered',
304
+ registeredAtMs: now,
305
+ updatedAtMs: now
306
+ });
307
+ transaction.set(ref, after);
308
+ transaction.set(posHardwareSaleRef(input.orderId), posHardwareSaleRecord(input.orderId, after), posHardwareSaleSetOptions(after));
309
+ return after;
310
+ });
311
+ }
312
+ /** A store's readiness for a reader: its plan and its Location. */ export async function posHardwareStoreReadiness(hostId) {
313
+ const [owner, config] = await Promise.all([
314
+ getOrgForHost(hostId).catch(()=>null),
315
+ firestore().collection('hosts').doc(hostId).collection('terminal').doc('config').get()
316
+ ]);
317
+ return {
318
+ posPlan: Aglyn.checkEntitlement(owner == null ? void 0 : owner.org, 'pos'),
319
+ hasLocation: Boolean(config.exists && config.get('stripeLocationId'))
320
+ };
321
+ }
322
+ /**
323
+ * Registers a reader sold at the booth to the buyer's chosen store, by the
324
+ * code it shows, while the buyer is there (AGL-4038). The sale must be
325
+ * attached to them with a store chosen, and the store's plan must include
326
+ * the point of sale.
327
+ *
328
+ * A store with no reader Location yet needs its address, which is where
329
+ * Stripe sets the reader up for. Booth staff may type it with the buyer
330
+ * (`address`): it goes exactly where the store's POS devices card would put
331
+ * it, through the same registration, which creates the store's Location from
332
+ * it and records it on the store's terminal settings. Without one the booth
333
+ * refuses with `needs-address`, and the buyer can add it later on that card.
334
+ * A store that already has its Location keeps it: an address sent for it is
335
+ * never used.
336
+ */ export async function registerPosHardwareAtBooth(input) {
337
+ var _sale_get;
338
+ var _order_posSale, _order_attachment;
339
+ if (!POS_HARDWARE_ORDER_ID.test(input.orderId)) throw new PosHardwareReaderRefusal('Name the sale.', 400);
340
+ const sale = await posHardwareSaleRef(input.orderId).get();
341
+ if (!sale.exists) {
342
+ throw new PosHardwareReaderRefusal('Take payment for the sale first, then register its reader.', 409);
343
+ }
344
+ const orgId = String((_sale_get = sale.get('orgId')) != null ? _sale_get : '');
345
+ const snapshot = await hardwareOrdersRef(orgId).doc(input.orderId).get();
346
+ const order = snapshot.data();
347
+ if (!order || order.source !== 'in_person' || ((_order_posSale = order.posSale) == null ? void 0 : _order_posSale.hostId) !== input.config.sellerHostId) {
348
+ throw new PosHardwareReaderRefusal('No such card reader sale.', 404);
349
+ }
350
+ if (((_order_attachment = order.attachment) == null ? void 0 : _order_attachment.state) !== 'attached' || !order.attachment.orgId) {
351
+ throw new PosHardwareReaderRefusal('Attach the sale to the buyer first.', 409);
352
+ }
353
+ const hostId = order.hostId;
354
+ if (!hostId) throw new PosHardwareReaderRefusal('Choose the buyer’s store first.', 409);
355
+ const readiness = await posHardwareStoreReadiness(hostId);
356
+ if (!readiness.posPlan) {
357
+ throw new PosHardwareReaderRefusal('Their workspace needs a plan with the point of sale before a reader can be added. They can add it, then set the reader up themselves.', 409);
358
+ }
359
+ // The store's address, only for a store with no Location: one that has
360
+ // its Location keeps it, whatever was sent.
361
+ const storeAddress = readiness.hasLocation ? null : boothStoreAddress(input.address);
362
+ if (!readiness.hasLocation) {
363
+ if (!storeAddress) {
364
+ throw new PosHardwareReaderRefusal('Their store has no address for card readers yet. Enter the store’s address to register the reader now, or they add it when they set the reader up on the POS devices card.', 409, 'needs-address');
365
+ }
366
+ const problem = (await import("./pos-terminal.js")).posTerminalAddressProblem(storeAddress);
367
+ if (problem) throw new PosHardwareReaderRefusal(problem, 400, 'needs-address');
368
+ }
369
+ const { registerPosTerminalReader } = await import("./pos-readers.js");
370
+ const registered = await registerPosTerminalReader(_extends({
371
+ hostId,
372
+ orgId,
373
+ uid: input.uid,
374
+ registrationCode: input.registrationCode,
375
+ label: input.label
376
+ }, storeAddress ? {
377
+ address: storeAddress
378
+ } : {}));
379
+ if ('error' in registered) throw new PosHardwareReaderRefusal(registered.error, registered.status);
380
+ // A reader with a serial matched its unit as it registered. One without
381
+ // (or not on the sale) takes the first reader of the sale not set up yet.
382
+ const ref = hardwareOrdersRef(orgId).doc(input.orderId);
383
+ const after = await firestore().runTransaction(async (transaction)=>{
384
+ var _now_units;
385
+ const now = (await transaction.get(ref)).data();
386
+ const units = (_now_units = now.units) != null ? _now_units : [];
387
+ if (units.some((unit)=>unit.readerId === registered.id)) return now;
388
+ const at = units.findIndex((unit)=>{
389
+ var _posHardwareSku;
390
+ return !unit.readerId && ((_posHardwareSku = posHardwareSku(unit.sku)) == null ? void 0 : _posHardwareSku.kind) === 'reader';
391
+ });
392
+ if (at < 0) return now;
393
+ const stamp = Date.now();
394
+ const next = units.map((unit, index)=>{
395
+ var _unit_serialNumber;
396
+ return index === at ? _extends({}, unit, {
397
+ serialNumber: (_unit_serialNumber = unit.serialNumber) != null ? _unit_serialNumber : registered.reader.serialNumber ? normalizePosHardwareSerial(registered.reader.serialNumber) : null,
398
+ readerId: registered.id,
399
+ hostId,
400
+ registeredAtMs: stamp
401
+ }) : unit;
402
+ });
403
+ const done = everyReaderRegistered(next);
404
+ const updated = _extends({}, now, {
405
+ units: next,
406
+ serialNumbers: next.flatMap((unit)=>unit.serialNumber ? [
407
+ unit.serialNumber
408
+ ] : [])
409
+ }, done && now.status === 'delivered' ? {
410
+ status: 'registered',
411
+ registeredAtMs: stamp
412
+ } : {}, {
413
+ updatedAtMs: stamp
414
+ });
415
+ transaction.set(ref, updated);
416
+ transaction.set(posHardwareSaleRef(input.orderId), posHardwareSaleRecord(input.orderId, updated), posHardwareSaleSetOptions(updated));
417
+ return updated;
418
+ });
419
+ await fillPosHardwareBuyerAddress({
420
+ orgId,
421
+ orderId: input.orderId
422
+ });
423
+ return {
424
+ order: after,
425
+ readerId: registered.id,
426
+ storeAddress
427
+ };
428
+ }
429
+
430
+ //# sourceMappingURL=pos-hardware-readers.js.map