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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (430) 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/order-webhooks-card.component.js +1 -1
  10. package/src/lib/components/console/order-webhooks-card.component.js.map +1 -1
  11. package/src/lib/components/console/payment-methods-card.component.js +1 -1
  12. package/src/lib/components/console/payment-methods-card.component.js.map +1 -1
  13. package/src/lib/components/console/pos/pos-cart-panel.component.d.ts +5 -0
  14. package/src/lib/components/console/pos/pos-cart-panel.component.js +18 -12
  15. package/src/lib/components/console/pos/pos-cart-panel.component.js.map +1 -1
  16. package/src/lib/components/console/pos/pos-hardware-api.d.ts +76 -5
  17. package/src/lib/components/console/pos/pos-hardware-api.js +53 -11
  18. package/src/lib/components/console/pos/pos-hardware-api.js.map +1 -1
  19. package/src/lib/components/console/pos/pos-hardware-buyer.component.d.ts +18 -0
  20. package/src/lib/components/console/pos/pos-hardware-buyer.component.js +629 -0
  21. package/src/lib/components/console/pos/pos-hardware-buyer.component.js.map +1 -0
  22. package/src/lib/components/console/pos/pos-hardware-sale-api.d.ts +162 -0
  23. package/src/lib/components/console/pos/pos-hardware-sale-api.js +122 -0
  24. package/src/lib/components/console/pos/pos-hardware-sale-api.js.map +1 -0
  25. package/src/lib/components/console/pos/pos-hardware-sale-terms.component.d.ts +39 -0
  26. package/src/lib/components/console/pos/pos-hardware-sale-terms.component.js +251 -0
  27. package/src/lib/components/console/pos/pos-hardware-sale-terms.component.js.map +1 -0
  28. package/src/lib/components/console/pos/use-pos-display.js +50 -0
  29. package/src/lib/components/console/pos/use-pos-display.js.map +1 -1
  30. package/src/lib/components/console/pos-cellular-control.component.d.ts +41 -0
  31. package/src/lib/components/console/pos-cellular-control.component.js +211 -0
  32. package/src/lib/components/console/pos-cellular-control.component.js.map +1 -0
  33. package/src/lib/components/console/pos-devices-card.component.d.ts +9 -1
  34. package/src/lib/components/console/pos-devices-card.component.js +47 -15
  35. package/src/lib/components/console/pos-devices-card.component.js.map +1 -1
  36. package/src/lib/components/console/pos-display/pos-display-api.d.ts +6 -0
  37. package/src/lib/components/console/pos-display/pos-display-api.js +8 -1
  38. package/src/lib/components/console/pos-display/pos-display-api.js.map +1 -1
  39. package/src/lib/components/console/pos-display-page.component.d.ts +13 -0
  40. package/src/lib/components/console/pos-display-page.component.js +44 -2
  41. package/src/lib/components/console/pos-display-page.component.js.map +1 -1
  42. package/src/lib/components/console/pos-hardware-card.component.d.ts +12 -4
  43. package/src/lib/components/console/pos-hardware-card.component.js +157 -36
  44. package/src/lib/components/console/pos-hardware-card.component.js.map +1 -1
  45. package/src/lib/components/console/pos-hardware-orders-staff-page.component.js +360 -80
  46. package/src/lib/components/console/pos-hardware-orders-staff-page.component.js.map +1 -1
  47. package/src/lib/components/console/pos-hardware-terms-page.component.d.ts +34 -0
  48. package/src/lib/components/console/pos-hardware-terms-page.component.js +257 -0
  49. package/src/lib/components/console/pos-hardware-terms-page.component.js.map +1 -0
  50. package/src/lib/components/console/pos-hardware-terms-sign-page.component.d.ts +27 -0
  51. package/src/lib/components/console/pos-hardware-terms-sign-page.component.js +104 -0
  52. package/src/lib/components/console/pos-hardware-terms-sign-page.component.js.map +1 -0
  53. package/src/lib/components/console/pos-hardware-waiting-card.component.d.ts +24 -0
  54. package/src/lib/components/console/pos-hardware-waiting-card.component.js +205 -0
  55. package/src/lib/components/console/pos-hardware-waiting-card.component.js.map +1 -0
  56. package/src/lib/components/console/pos-ops/pos-check-in-dialog.component.js +297 -201
  57. package/src/lib/components/console/pos-ops/pos-check-in-dialog.component.js.map +1 -1
  58. package/src/lib/components/console/pos-ops/pos-check-ins-card.component.d.ts +3 -0
  59. package/src/lib/components/console/pos-ops/pos-check-ins-card.component.js +260 -92
  60. package/src/lib/components/console/pos-ops/pos-check-ins-card.component.js.map +1 -1
  61. package/src/lib/components/console/pos-ops/pos-operations-bar.component.d.ts +9 -0
  62. package/src/lib/components/console/pos-ops/pos-operations-bar.component.js +15 -6
  63. package/src/lib/components/console/pos-ops/pos-operations-bar.component.js.map +1 -1
  64. package/src/lib/components/console/pos-ops/pos-rain-check-dialog.component.d.ts +25 -0
  65. package/src/lib/components/console/pos-ops/pos-rain-check-dialog.component.js +136 -0
  66. package/src/lib/components/console/pos-ops/pos-rain-check-dialog.component.js.map +1 -0
  67. package/src/lib/components/console/pos-ops/pos-shift-panel.component.d.ts +6 -0
  68. package/src/lib/components/console/pos-ops/pos-shift-panel.component.js +48 -31
  69. package/src/lib/components/console/pos-ops/pos-shift-panel.component.js.map +1 -1
  70. package/src/lib/components/console/pos-page.component.d.ts +1 -1
  71. package/src/lib/components/console/pos-page.component.js +63 -12
  72. package/src/lib/components/console/pos-page.component.js.map +1 -1
  73. package/src/lib/components/console/pos-reader-splash-setting.component.js +1 -1
  74. package/src/lib/components/console/pos-reader-splash-setting.component.js.map +1 -1
  75. package/src/lib/components/console/product-check-in-fields.component.d.ts +4 -2
  76. package/src/lib/components/console/product-check-in-fields.component.js +60 -14
  77. package/src/lib/components/console/product-check-in-fields.component.js.map +1 -1
  78. package/src/lib/components/console/product-editor-dialog.component.js +44 -1
  79. package/src/lib/components/console/product-editor-dialog.component.js.map +1 -1
  80. package/src/lib/components/console/product-hardware-sku-field.component.d.ts +19 -0
  81. package/src/lib/components/console/product-hardware-sku-field.component.js +92 -0
  82. package/src/lib/components/console/product-hardware-sku-field.component.js.map +1 -0
  83. package/src/lib/components/console/product-kiosk-offer-field.component.d.ts +22 -0
  84. package/src/lib/components/console/product-kiosk-offer-field.component.js +94 -0
  85. package/src/lib/components/console/product-kiosk-offer-field.component.js.map +1 -0
  86. package/src/lib/components/console/product-register-fields.component.d.ts +4 -0
  87. package/src/lib/components/console/product-register-fields.component.js +31 -2
  88. package/src/lib/components/console/product-register-fields.component.js.map +1 -1
  89. package/src/lib/components/console/products-hub-card.component.js +11 -2
  90. package/src/lib/components/console/products-hub-card.component.js.map +1 -1
  91. package/src/lib/components/console/register-hardware-card.component.d.ts +11 -0
  92. package/src/lib/components/console/register-hardware-card.component.js +56 -27
  93. package/src/lib/components/console/register-hardware-card.component.js.map +1 -1
  94. package/src/lib/components/console/reservation-guests-dialog.component.d.ts +28 -0
  95. package/src/lib/components/console/reservation-guests-dialog.component.js +189 -0
  96. package/src/lib/components/console/reservation-guests-dialog.component.js.map +1 -0
  97. package/src/lib/components/console/reservations-card.component.d.ts +9 -0
  98. package/src/lib/components/console/reservations-card.component.js +158 -23
  99. package/src/lib/components/console/reservations-card.component.js.map +1 -1
  100. package/src/lib/components/console/shippingeasy-card.component.js +1 -1
  101. package/src/lib/components/console/shippingeasy-card.component.js.map +1 -1
  102. package/src/lib/components/console/shipstation-card.component.d.ts +1 -1
  103. package/src/lib/components/console/shipstation-card.component.js +3 -3
  104. package/src/lib/components/console/shipstation-card.component.js.map +1 -1
  105. package/src/lib/components/product-detail.d.ts +4 -0
  106. package/src/lib/components/product-detail.js +40 -5
  107. package/src/lib/components/product-detail.js.map +1 -1
  108. package/src/lib/components/product-reviews.js +28 -11
  109. package/src/lib/components/product-reviews.js.map +1 -1
  110. package/src/lib/components/reservation-widget.js +28 -5
  111. package/src/lib/components/reservation-widget.js.map +1 -1
  112. package/src/lib/components/use-day-picker.d.ts +25 -0
  113. package/src/lib/components/use-day-picker.js +57 -0
  114. package/src/lib/components/use-day-picker.js.map +1 -0
  115. package/src/lib/constants/operator-alerts.d.ts +55 -0
  116. package/src/lib/constants/operator-alerts.js +156 -1
  117. package/src/lib/constants/operator-alerts.js.map +1 -1
  118. package/src/lib/declarations.console-server.js +54 -1
  119. package/src/lib/declarations.console-server.js.map +1 -1
  120. package/src/lib/declarations.d.ts +4 -2
  121. package/src/lib/declarations.js +15 -4
  122. package/src/lib/declarations.js.map +1 -1
  123. package/src/lib/declarations.server.js +9 -0
  124. package/src/lib/declarations.server.js.map +1 -1
  125. package/src/lib/model/commerce-cart.d.ts +9 -1
  126. package/src/lib/model/commerce-cart.js +4 -3
  127. package/src/lib/model/commerce-cart.js.map +1 -1
  128. package/src/lib/model/commerce-check-in-product.d.ts +26 -0
  129. package/src/lib/model/commerce-check-in-product.js +64 -2
  130. package/src/lib/model/commerce-check-in-product.js.map +1 -1
  131. package/src/lib/model/commerce-check-in-record.d.ts +127 -0
  132. package/src/lib/model/commerce-check-in-record.js +36 -0
  133. package/src/lib/model/commerce-check-in-record.js.map +1 -0
  134. package/src/lib/model/commerce-check-in.d.ts +91 -87
  135. package/src/lib/model/commerce-check-in.js +186 -62
  136. package/src/lib/model/commerce-check-in.js.map +1 -1
  137. package/src/lib/model/commerce-kiosk-offer.d.ts +31 -0
  138. package/src/lib/model/commerce-kiosk-offer.js +35 -0
  139. package/src/lib/model/commerce-kiosk-offer.js.map +1 -0
  140. package/src/lib/model/commerce-orders.d.ts +76 -0
  141. package/src/lib/model/commerce-orders.js +6 -0
  142. package/src/lib/model/commerce-orders.js.map +1 -1
  143. package/src/lib/model/commerce-pos-day-report.d.ts +54 -1
  144. package/src/lib/model/commerce-pos-day-report.js +39 -2
  145. package/src/lib/model/commerce-pos-day-report.js.map +1 -1
  146. package/src/lib/model/commerce-pos-offline.d.ts +1 -1
  147. package/src/lib/model/commerce-pos-offline.js +6 -1
  148. package/src/lib/model/commerce-pos-offline.js.map +1 -1
  149. package/src/lib/model/commerce-pos-ops.js +3 -2
  150. package/src/lib/model/commerce-pos-ops.js.map +1 -1
  151. package/src/lib/model/commerce-pos.d.ts +36 -3
  152. package/src/lib/model/commerce-pos.js +14 -6
  153. package/src/lib/model/commerce-pos.js.map +1 -1
  154. package/src/lib/model/commerce-receipt.js +3 -2
  155. package/src/lib/model/commerce-receipt.js.map +1 -1
  156. package/src/lib/model/commerce-reservations.d.ts +69 -4
  157. package/src/lib/model/commerce-reservations.js +57 -5
  158. package/src/lib/model/commerce-reservations.js.map +1 -1
  159. package/src/lib/model/commerce.d.ts +66 -0
  160. package/src/lib/model/commerce.js +15 -0
  161. package/src/lib/model/commerce.js.map +1 -1
  162. package/src/lib/model/order-list-fields.d.ts +11 -0
  163. package/src/lib/model/order-list-fields.js +17 -1
  164. package/src/lib/model/order-list-fields.js.map +1 -1
  165. package/src/lib/model/own-store-tax-summary.d.ts +152 -0
  166. package/src/lib/model/own-store-tax-summary.js +288 -0
  167. package/src/lib/model/own-store-tax-summary.js.map +1 -0
  168. package/src/lib/model/plugin-permissions.d.ts +74 -0
  169. package/src/lib/model/plugin-permissions.js +224 -7
  170. package/src/lib/model/plugin-permissions.js.map +1 -1
  171. package/src/lib/model/pos-cellular.d.ts +223 -0
  172. package/src/lib/model/pos-cellular.js +293 -0
  173. package/src/lib/model/pos-cellular.js.map +1 -0
  174. package/src/lib/model/pos-hardware-in-person.d.ts +98 -0
  175. package/src/lib/model/pos-hardware-in-person.js +224 -0
  176. package/src/lib/model/pos-hardware-in-person.js.map +1 -0
  177. package/src/lib/model/pos-hardware-tax-summary.d.ts +166 -0
  178. package/src/lib/model/pos-hardware-tax-summary.js +225 -0
  179. package/src/lib/model/pos-hardware-tax-summary.js.map +1 -0
  180. package/src/lib/model/pos-hardware-terms.d.ts +74 -0
  181. package/src/lib/model/pos-hardware-terms.js +115 -0
  182. package/src/lib/model/pos-hardware-terms.js.map +1 -0
  183. package/src/lib/model/pos-hardware.d.ts +349 -7
  184. package/src/lib/model/pos-hardware.js +291 -20
  185. package/src/lib/model/pos-hardware.js.map +1 -1
  186. package/src/lib/model/product-write.d.ts +10 -0
  187. package/src/lib/model/product-write.js +4 -2
  188. package/src/lib/model/product-write.js.map +1 -1
  189. package/src/lib/model/workspace-site-permissions.d.ts +26 -0
  190. package/src/lib/model/workspace-site-permissions.js +81 -0
  191. package/src/lib/model/workspace-site-permissions.js.map +1 -0
  192. package/src/lib/plugin.js +16 -0
  193. package/src/lib/plugin.js.map +1 -1
  194. package/src/lib/server/billing-webhook.js +25 -1
  195. package/src/lib/server/billing-webhook.js.map +1 -1
  196. package/src/lib/server/cancel-order.js +7 -5
  197. package/src/lib/server/cancel-order.js.map +1 -1
  198. package/src/lib/server/cart-checkout.js +20 -8
  199. package/src/lib/server/cart-checkout.js.map +1 -1
  200. package/src/lib/server/cart.js +29 -0
  201. package/src/lib/server/cart.js.map +1 -1
  202. package/src/lib/server/checkout.js +42 -13
  203. package/src/lib/server/checkout.js.map +1 -1
  204. package/src/lib/server/collection-membership.d.ts +4 -0
  205. package/src/lib/server/collection-membership.js +5 -10
  206. package/src/lib/server/collection-membership.js.map +1 -1
  207. package/src/lib/server/commerce-site-keys.d.ts +48 -0
  208. package/src/lib/server/commerce-site-keys.js +61 -0
  209. package/src/lib/server/commerce-site-keys.js.map +1 -0
  210. package/src/lib/server/draft-order.js +8 -5
  211. package/src/lib/server/draft-order.js.map +1 -1
  212. package/src/lib/server/fulfill-order.js +7 -5
  213. package/src/lib/server/fulfill-order.js.map +1 -1
  214. package/src/lib/server/gift-cards.js +8 -5
  215. package/src/lib/server/gift-cards.js.map +1 -1
  216. package/src/lib/server/local-fulfillment-status.js +9 -6
  217. package/src/lib/server/local-fulfillment-status.js.map +1 -1
  218. package/src/lib/server/member-post.js +6 -5
  219. package/src/lib/server/member-post.js.map +1 -1
  220. package/src/lib/server/membership-admin-password.d.ts +4 -2
  221. package/src/lib/server/membership-admin-password.js +10 -8
  222. package/src/lib/server/membership-admin-password.js.map +1 -1
  223. package/src/lib/server/membership-admin-remove.d.ts +7 -5
  224. package/src/lib/server/membership-admin-remove.js +9 -9
  225. package/src/lib/server/membership-admin-remove.js.map +1 -1
  226. package/src/lib/server/order-notifications.js +5 -2
  227. package/src/lib/server/order-notifications.js.map +1 -1
  228. package/src/lib/server/order-print.js +7 -5
  229. package/src/lib/server/order-print.js.map +1 -1
  230. package/src/lib/server/order-receipt-send.js +8 -5
  231. package/src/lib/server/order-receipt-send.js.map +1 -1
  232. package/src/lib/server/order-webhooks.js +8 -8
  233. package/src/lib/server/order-webhooks.js.map +1 -1
  234. package/src/lib/server/orders-shipping-prepare.js +9 -6
  235. package/src/lib/server/orders-shipping-prepare.js.map +1 -1
  236. package/src/lib/server/own-store-tax-return-source.d.ts +47 -0
  237. package/src/lib/server/own-store-tax-return-source.js +312 -0
  238. package/src/lib/server/own-store-tax-return-source.js.map +1 -0
  239. package/src/lib/server/payment-methods.js +13 -9
  240. package/src/lib/server/payment-methods.js.map +1 -1
  241. package/src/lib/server/pos-auth.d.ts +37 -6
  242. package/src/lib/server/pos-auth.js +40 -15
  243. package/src/lib/server/pos-auth.js.map +1 -1
  244. package/src/lib/server/pos-cellular-billing.d.ts +81 -0
  245. package/src/lib/server/pos-cellular-billing.js +711 -0
  246. package/src/lib/server/pos-cellular-billing.js.map +1 -0
  247. package/src/lib/server/pos-cellular-notify.d.ts +47 -0
  248. package/src/lib/server/pos-cellular-notify.js +150 -0
  249. package/src/lib/server/pos-cellular-notify.js.map +1 -0
  250. package/src/lib/server/pos-cellular.d.ts +88 -0
  251. package/src/lib/server/pos-cellular.js +339 -0
  252. package/src/lib/server/pos-cellular.js.map +1 -0
  253. package/src/lib/server/pos-check-in.d.ts +5 -1
  254. package/src/lib/server/pos-check-in.js +296 -28
  255. package/src/lib/server/pos-check-in.js.map +1 -1
  256. package/src/lib/server/pos-day-report.js +29 -3
  257. package/src/lib/server/pos-day-report.js.map +1 -1
  258. package/src/lib/server/pos-display.d.ts +16 -0
  259. package/src/lib/server/pos-display.js +129 -2
  260. package/src/lib/server/pos-display.js.map +1 -1
  261. package/src/lib/server/pos-hardware-admin.d.ts +10 -1
  262. package/src/lib/server/pos-hardware-admin.js +250 -84
  263. package/src/lib/server/pos-hardware-admin.js.map +1 -1
  264. package/src/lib/server/pos-hardware-attach.d.ts +105 -0
  265. package/src/lib/server/pos-hardware-attach.js +443 -0
  266. package/src/lib/server/pos-hardware-attach.js.map +1 -0
  267. package/src/lib/server/pos-hardware-buyer-lookup.d.ts +58 -0
  268. package/src/lib/server/pos-hardware-buyer-lookup.js +180 -0
  269. package/src/lib/server/pos-hardware-buyer-lookup.js.map +1 -0
  270. package/src/lib/server/pos-hardware-buyer-record.d.ts +29 -0
  271. package/src/lib/server/pos-hardware-buyer-record.js +86 -0
  272. package/src/lib/server/pos-hardware-buyer-record.js.map +1 -0
  273. package/src/lib/server/pos-hardware-cancel.d.ts +58 -0
  274. package/src/lib/server/pos-hardware-cancel.js +147 -0
  275. package/src/lib/server/pos-hardware-cancel.js.map +1 -0
  276. package/src/lib/server/pos-hardware-closure-notices.d.ts +27 -0
  277. package/src/lib/server/pos-hardware-closure-notices.js +85 -0
  278. package/src/lib/server/pos-hardware-closure-notices.js.map +1 -0
  279. package/src/lib/server/pos-hardware-closure.d.ts +60 -0
  280. package/src/lib/server/pos-hardware-closure.js +153 -0
  281. package/src/lib/server/pos-hardware-closure.js.map +1 -0
  282. package/src/lib/server/pos-hardware-in-person.d.ts +61 -0
  283. package/src/lib/server/pos-hardware-in-person.js +236 -0
  284. package/src/lib/server/pos-hardware-in-person.js.map +1 -0
  285. package/src/lib/server/pos-hardware-notify.d.ts +40 -2
  286. package/src/lib/server/pos-hardware-notify.js +195 -14
  287. package/src/lib/server/pos-hardware-notify.js.map +1 -1
  288. package/src/lib/server/pos-hardware-readers.d.ts +115 -0
  289. package/src/lib/server/pos-hardware-readers.js +430 -0
  290. package/src/lib/server/pos-hardware-readers.js.map +1 -0
  291. package/src/lib/server/pos-hardware-returns.d.ts +116 -0
  292. package/src/lib/server/pos-hardware-returns.js +502 -0
  293. package/src/lib/server/pos-hardware-returns.js.map +1 -0
  294. package/src/lib/server/pos-hardware-sale-fields.d.ts +28 -0
  295. package/src/lib/server/pos-hardware-sale-fields.js +44 -0
  296. package/src/lib/server/pos-hardware-sale-fields.js.map +1 -0
  297. package/src/lib/server/pos-hardware-sale.d.ts +54 -0
  298. package/src/lib/server/pos-hardware-sale.js +369 -0
  299. package/src/lib/server/pos-hardware-sale.js.map +1 -0
  300. package/src/lib/server/pos-hardware-tax-return-source.d.ts +99 -0
  301. package/src/lib/server/pos-hardware-tax-return-source.js +462 -0
  302. package/src/lib/server/pos-hardware-tax-return-source.js.map +1 -0
  303. package/src/lib/server/pos-hardware-terms.d.ts +64 -0
  304. package/src/lib/server/pos-hardware-terms.js +154 -0
  305. package/src/lib/server/pos-hardware-terms.js.map +1 -0
  306. package/src/lib/server/pos-hardware-user-eraser.d.ts +3 -0
  307. package/src/lib/server/pos-hardware-user-eraser.js +31 -7
  308. package/src/lib/server/pos-hardware-user-eraser.js.map +1 -1
  309. package/src/lib/server/pos-hardware-webhook.d.ts +5 -0
  310. package/src/lib/server/pos-hardware-webhook.js +51 -6
  311. package/src/lib/server/pos-hardware-webhook.js.map +1 -1
  312. package/src/lib/server/pos-hardware.d.ts +74 -1
  313. package/src/lib/server/pos-hardware.js +175 -10
  314. package/src/lib/server/pos-hardware.js.map +1 -1
  315. package/src/lib/server/pos-kiosk.d.ts +2 -0
  316. package/src/lib/server/pos-kiosk.js +17 -12
  317. package/src/lib/server/pos-kiosk.js.map +1 -1
  318. package/src/lib/server/pos-offline-card-order.d.ts +64 -0
  319. package/src/lib/server/pos-offline-card-order.js +102 -0
  320. package/src/lib/server/pos-offline-card-order.js.map +1 -0
  321. package/src/lib/server/pos-offline-card-reconcile.d.ts +67 -1
  322. package/src/lib/server/pos-offline-card-reconcile.js +215 -18
  323. package/src/lib/server/pos-offline-card-reconcile.js.map +1 -1
  324. package/src/lib/server/pos-offline-sync.d.ts +39 -0
  325. package/src/lib/server/pos-offline-sync.js +190 -55
  326. package/src/lib/server/pos-offline-sync.js.map +1 -1
  327. package/src/lib/server/pos-ops-gate.d.ts +28 -9
  328. package/src/lib/server/pos-ops-gate.js +50 -19
  329. package/src/lib/server/pos-ops-gate.js.map +1 -1
  330. package/src/lib/server/pos-ops-routes.js +24 -0
  331. package/src/lib/server/pos-ops-routes.js.map +1 -1
  332. package/src/lib/server/pos-order-refund-ids.d.ts +28 -0
  333. package/src/lib/server/pos-order-refund-ids.js +31 -0
  334. package/src/lib/server/pos-order-refund-ids.js.map +1 -0
  335. package/src/lib/server/pos-order.js +52 -49
  336. package/src/lib/server/pos-order.js.map +1 -1
  337. package/src/lib/server/pos-payment.js +1 -1
  338. package/src/lib/server/pos-payment.js.map +1 -1
  339. package/src/lib/server/pos-reader-splash-admin.js +30 -32
  340. package/src/lib/server/pos-reader-splash-admin.js.map +1 -1
  341. package/src/lib/server/pos-reader-splash-images-route.d.ts +17 -0
  342. package/src/lib/server/pos-reader-splash-images-route.js +113 -0
  343. package/src/lib/server/pos-reader-splash-images-route.js.map +1 -0
  344. package/src/lib/server/pos-reader-splash-images.d.ts +51 -0
  345. package/src/lib/server/pos-reader-splash-images.js +123 -0
  346. package/src/lib/server/pos-reader-splash-images.js.map +1 -0
  347. package/src/lib/server/pos-reader-splash.d.ts +68 -1
  348. package/src/lib/server/pos-reader-splash.js +182 -11
  349. package/src/lib/server/pos-reader-splash.js.map +1 -1
  350. package/src/lib/server/pos-readers.d.ts +29 -0
  351. package/src/lib/server/pos-readers.js +134 -35
  352. package/src/lib/server/pos-readers.js.map +1 -1
  353. package/src/lib/server/pos-refund-authority.d.ts +3 -1
  354. package/src/lib/server/pos-refund-authority.js +3 -2
  355. package/src/lib/server/pos-refund-authority.js.map +1 -1
  356. package/src/lib/server/pos-return.d.ts +10 -0
  357. package/src/lib/server/pos-return.js +29 -7
  358. package/src/lib/server/pos-return.js.map +1 -1
  359. package/src/lib/server/pos-sale.js +6 -1
  360. package/src/lib/server/pos-sale.js.map +1 -1
  361. package/src/lib/server/pos-shift.js +11 -0
  362. package/src/lib/server/pos-shift.js.map +1 -1
  363. package/src/lib/server/pos-staff-pin.js +29 -24
  364. package/src/lib/server/pos-staff-pin.js.map +1 -1
  365. package/src/lib/server/pos-terminal.d.ts +14 -4
  366. package/src/lib/server/pos-terminal.js +34 -38
  367. package/src/lib/server/pos-terminal.js.map +1 -1
  368. package/src/lib/server/printers.d.ts +7 -3
  369. package/src/lib/server/printers.js +18 -12
  370. package/src/lib/server/printers.js.map +1 -1
  371. package/src/lib/server/product-drafts.d.ts +11 -1
  372. package/src/lib/server/product-drafts.js +12 -8
  373. package/src/lib/server/product-drafts.js.map +1 -1
  374. package/src/lib/server/product.d.ts +15 -1
  375. package/src/lib/server/product.js +16 -3
  376. package/src/lib/server/product.js.map +1 -1
  377. package/src/lib/server/products-write.d.ts +26 -2
  378. package/src/lib/server/products-write.js +19 -7
  379. package/src/lib/server/products-write.js.map +1 -1
  380. package/src/lib/server/refund.js +55 -42
  381. package/src/lib/server/refund.js.map +1 -1
  382. package/src/lib/server/reservation-availability-query.d.ts +8 -0
  383. package/src/lib/server/reservation-availability-query.js +11 -1
  384. package/src/lib/server/reservation-availability-query.js.map +1 -1
  385. package/src/lib/server/reservation-availability.d.ts +1 -1
  386. package/src/lib/server/reservation-availability.js +7 -2
  387. package/src/lib/server/reservation-availability.js.map +1 -1
  388. package/src/lib/server/reservation-guests.d.ts +32 -0
  389. package/src/lib/server/reservation-guests.js +285 -0
  390. package/src/lib/server/reservation-guests.js.map +1 -0
  391. package/src/lib/server/reservation-walk-in.d.ts +11 -1
  392. package/src/lib/server/reservation-walk-in.js +56 -12
  393. package/src/lib/server/reservation-walk-in.js.map +1 -1
  394. package/src/lib/server/reserve.js +18 -5
  395. package/src/lib/server/reserve.js.map +1 -1
  396. package/src/lib/server/returns.js +9 -6
  397. package/src/lib/server/returns.js.map +1 -1
  398. package/src/lib/server/reviews.d.ts +22 -2
  399. package/src/lib/server/reviews.js +88 -20
  400. package/src/lib/server/reviews.js.map +1 -1
  401. package/src/lib/server/shipping-connectors.js +10 -11
  402. package/src/lib/server/shipping-connectors.js.map +1 -1
  403. package/src/lib/server/site-page-resolver.js +20 -3
  404. package/src/lib/server/site-page-resolver.js.map +1 -1
  405. package/src/lib/server/store-day.d.ts +33 -0
  406. package/src/lib/server/store-day.js +46 -0
  407. package/src/lib/server/store-day.js.map +1 -0
  408. package/src/lib/server/store-setup-ai-writer.d.ts +2 -1
  409. package/src/lib/server/store-setup-ai-writer.js +5 -6
  410. package/src/lib/server/store-setup-ai-writer.js.map +1 -1
  411. package/src/lib/server/storefront-tax.d.ts +13 -0
  412. package/src/lib/server/storefront-tax.js +8 -1
  413. package/src/lib/server/storefront-tax.js.map +1 -1
  414. package/src/lib/server/tax-return-source.d.ts +32 -3
  415. package/src/lib/server/tax-return-source.js +99 -20
  416. package/src/lib/server/tax-return-source.js.map +1 -1
  417. package/src/lib/server.js +100 -2
  418. package/src/lib/server.js.map +1 -1
  419. package/src/lib/testing/fake-firestore.js +58 -16
  420. package/src/lib/testing/fake-firestore.js.map +1 -1
  421. package/src/lib/testing/pos-ops-memory-firestore.js +18 -4
  422. package/src/lib/testing/pos-ops-memory-firestore.js.map +1 -1
  423. package/src/lib/testing/site-register-permissions.d.ts +29 -0
  424. package/src/lib/testing/site-register-permissions.js +38 -0
  425. package/src/lib/testing/site-register-permissions.js.map +1 -0
  426. package/src/lib/transfer/tracking.server.js +8 -5
  427. package/src/lib/transfer/tracking.server.js.map +1 -1
  428. package/src/lib/utils/add-to-cart.d.ts +2 -0
  429. package/src/lib/utils/add-to-cart.js +6 -3
  430. package/src/lib/utils/add-to-cart.js.map +1 -1
@@ -0,0 +1,236 @@
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
+ */ import { firebaseAdmin, getOrgForHost } from "@aglyn/tenant-data-admin";
17
+ import * as CommerceModel from "../model/index.js";
18
+ import { isPosHardwareSkuId, normalizePosHardwareSerial } from "../model/pos-hardware.js";
19
+ import { inPersonPosHardwareOrder, posHardwareRegisterShare } from "../model/pos-hardware-in-person.js";
20
+ import { hardwareOrdersRef, posHardwareInPersonConfig, posHardwareInPersonOrderId } from "./pos-hardware.js";
21
+ import { recordPosHardwareOrder } from "./pos-hardware-webhook.js";
22
+ import { posStripeTestMode } from "./pos-stripe.js";
23
+ /** How many marked sales one sweep records at most. */ export const IN_PERSON_SWEEP_LIMIT = 25;
24
+ /** Statuses after which a marked sale can never be paid, so the mark is dropped. */ const NEVER_PAID = new Set([
25
+ 'cancelled',
26
+ 'canceled',
27
+ 'voided',
28
+ 'refunded',
29
+ 'expired'
30
+ ]);
31
+ const text = (value)=>typeof value === 'string' && value.trim() ? value.trim() : null;
32
+ function firestore() {
33
+ return firebaseAdmin.app().firestore();
34
+ }
35
+ function registerOrderRef(hostId, orderId) {
36
+ return firestore().collection('hosts').doc(hostId).collection('orders').doc(orderId);
37
+ }
38
+ /** Where the store taxes from, and its rate there, from its own tax settings. */ async function storeTax(hostId) {
39
+ var _settings_get, _tax_origin, _ref, _ref1;
40
+ var _text, _text1;
41
+ const settings = await firestore().collection('hosts').doc(hostId).collection('settings').doc('store').get();
42
+ const tax = (_settings_get = settings.get('tax')) != null ? _settings_get : {};
43
+ const origin = (_tax_origin = tax.origin) != null ? _tax_origin : {};
44
+ const country = (_ref = (_text = text(origin.country)) == null ? void 0 : _text.toUpperCase()) != null ? _ref : null;
45
+ const rate = country ? CommerceModel.resolveTaxRate(tax, origin) : null;
46
+ return {
47
+ region: country ? {
48
+ country,
49
+ state: (_ref1 = (_text1 = text(origin.state)) == null ? void 0 : _text1.toUpperCase()) != null ? _ref1 : null,
50
+ postalCode: null
51
+ } : null,
52
+ ratePct: rate && Number.isFinite(rate.pct) ? rate.pct : null
53
+ };
54
+ }
55
+ /** The store owner's connected Stripe account, where the store's card money goes. */ async function storeStripeAccount(hostId) {
56
+ var _owner_org;
57
+ const owner = await getOrgForHost(hostId).catch(()=>null);
58
+ const ownerUid = text(owner == null ? void 0 : (_owner_org = owner.org) == null ? void 0 : _owner_org.ownerUid);
59
+ if (!ownerUid) return null;
60
+ const profile = await firestore().collection('profiles').doc(ownerUid).get();
61
+ return text(profile.get('stripeAccountId'));
62
+ }
63
+ /**
64
+ * Records the hardware order of one register sale on the seller store, once.
65
+ * Never throws for a sale that is not one: it says why it did nothing.
66
+ */ export async function recordInPersonPosHardwareSale(hostId, registerOrderId, options = {}) {
67
+ var _ref, _ref1, _ref2, _ref3, _order_paidAtMs, _text, _ref4, _order_currency;
68
+ var _order_totals, _order_totals1, _payments_find, _text1, _hardwareOrder_attachment, _hardwareOrder_attachment1;
69
+ const config = options.config === undefined ? posHardwareInPersonConfig() : options.config;
70
+ if (!config) return {
71
+ outcome: 'off'
72
+ };
73
+ if (hostId !== config.sellerHostId) return {
74
+ outcome: 'not-seller'
75
+ };
76
+ const orderRef = registerOrderRef(hostId, registerOrderId);
77
+ const snapshot = await orderRef.get();
78
+ if (!snapshot.exists) return {
79
+ outcome: 'missing'
80
+ };
81
+ const order = snapshot.data();
82
+ if (order.status !== 'paid') return {
83
+ outcome: 'not-paid'
84
+ };
85
+ const lineItems = Array.isArray(order.lineItems) ? order.lineItems : [];
86
+ const productIds = [
87
+ ...new Set(lineItems.map((line)=>{
88
+ var _line_productId;
89
+ return String((_line_productId = line.productId) != null ? _line_productId : '');
90
+ }).filter(Boolean))
91
+ ];
92
+ const products = new Map((await Promise.all(productIds.map((id)=>firestore().collection('hosts').doc(hostId).collection('products').doc(id).get()))).map((doc)=>[
93
+ String(doc.id),
94
+ doc.exists ? doc.data() : null
95
+ ]));
96
+ const lines = lineItems.map((line)=>{
97
+ var _products_get;
98
+ const sku = (_products_get = products.get(String(line.productId))) == null ? void 0 : _products_get.hardwareSku;
99
+ return {
100
+ sku: isPosHardwareSkuId(sku) ? sku : null,
101
+ quantity: Number(line.quantity),
102
+ unitAmountCents: Number(line.unitAmountCents)
103
+ };
104
+ });
105
+ const share = posHardwareRegisterShare({
106
+ lines,
107
+ discountCents: Number((_ref = (_order_totals = order.totals) == null ? void 0 : _order_totals.discountCents) != null ? _ref : 0),
108
+ taxCents: Number((_ref1 = (_order_totals1 = order.totals) == null ? void 0 : _order_totals1.taxCents) != null ? _ref1 : 0)
109
+ });
110
+ if (!share) {
111
+ // Marked when it was rung, but no line is hardware now: nothing to record.
112
+ if (order.hardwareSalePending) {
113
+ await orderRef.set({
114
+ hardwareSalePending: firebaseAdmin.firestore.FieldValue.delete()
115
+ }, {
116
+ merge: true
117
+ });
118
+ }
119
+ return {
120
+ outcome: 'no-hardware'
121
+ };
122
+ }
123
+ const orderId = posHardwareInPersonOrderId(hostId, registerOrderId);
124
+ const payments = CommerceModel.orderPayments(order).filter((payment)=>payment.status === 'succeeded');
125
+ const livemodes = payments.map((payment)=>payment.livemode).filter((mode)=>typeof mode === 'boolean');
126
+ const [tax, stripeAccountId] = await Promise.all([
127
+ storeTax(hostId),
128
+ storeStripeAccount(hostId)
129
+ ]);
130
+ const paidAtMs = Number((_ref2 = (_ref3 = (_order_paidAtMs = order.paidAtMs) != null ? _order_paidAtMs : order.createdAtMs) != null ? _ref3 : options.now) != null ? _ref2 : Date.now());
131
+ const hardwareOrder = inPersonPosHardwareOrder({
132
+ sellerHostId: config.sellerHostId,
133
+ sellerOrgId: config.sellerOrgId,
134
+ registerOrderId,
135
+ number: Number.isFinite(Number(order.number)) ? Number(order.number) : null,
136
+ registerId: text(order.registerId),
137
+ kiosk: order.posSource === 'kiosk',
138
+ offline: options.offline === true || Boolean(order.offline),
139
+ share,
140
+ paidAtMs,
141
+ tenders: payments.map((payment)=>payment.method),
142
+ paymentLinkSessionId: (_text = text((_payments_find = payments.find((payment)=>payment.checkoutSessionId)) == null ? void 0 : _payments_find.checkoutSessionId)) != null ? _text : text(order.checkoutSessionId),
143
+ receiptEmail: (_ref4 = (_text1 = text(order.customerEmail)) == null ? void 0 : _text1.toLowerCase()) != null ? _ref4 : null,
144
+ buyer: order.hardwareBuyer,
145
+ termsAcceptance: order.hardwareTermsAcceptance,
146
+ serials: (Array.isArray(order.hardwareSerials) ? order.hardwareSerials : []).map(normalizePosHardwareSerial).filter(Boolean),
147
+ taxRegion: tax.region,
148
+ ratePct: tax.ratePct,
149
+ stripeAccountId,
150
+ // A card payment says which mode it was in; a cash sale takes the
151
+ // deployment's, so a test deployment's booth is never a real sale.
152
+ livemode: livemodes.length ? livemodes.every(Boolean) : !posStripeTestMode(),
153
+ currency: String((_order_currency = order.currency) != null ? _order_currency : 'usd').toLowerCase()
154
+ });
155
+ const { created } = await recordPosHardwareOrder(orderId, hardwareOrder);
156
+ // The mark comes off once the order exists, by this call or an earlier one.
157
+ await orderRef.set({
158
+ hardwareOrderId: orderId,
159
+ hardwareSalePending: firebaseAdmin.firestore.FieldValue.delete()
160
+ }, {
161
+ merge: true
162
+ });
163
+ // A buyer with no account, named at the register while the sale was open,
164
+ // is invited to sign up now that there is an order to point them at.
165
+ if (created && ((_hardwareOrder_attachment = hardwareOrder.attachment) == null ? void 0 : _hardwareOrder_attachment.state) === 'pending' && hardwareOrder.attachment.email) {
166
+ await (await import("./pos-hardware-attach.js")).invitePendingBuyer(orderId, hardwareOrder.orgId, hardwareOrder);
167
+ }
168
+ return {
169
+ outcome: created ? 'recorded' : 'already',
170
+ orderId,
171
+ orgId: hardwareOrder.orgId,
172
+ pending: ((_hardwareOrder_attachment1 = hardwareOrder.attachment) == null ? void 0 : _hardwareOrder_attachment1.state) === 'pending'
173
+ };
174
+ }
175
+ /**
176
+ * Records every paid sale on the seller store that is still marked, at most
177
+ * {@link IN_PERSON_SWEEP_LIMIT} a time, and drops the mark from a sale that
178
+ * can no longer be paid. Never throws: a sale it cannot record stays marked
179
+ * for the next sweep.
180
+ */ export async function sweepInPersonPosHardwareSales(config = posHardwareInPersonConfig()) {
181
+ if (!config) return {
182
+ recorded: 0,
183
+ failed: 0
184
+ };
185
+ const marked = await firestore().collection('hosts').doc(config.sellerHostId).collection('orders').where('hardwareSalePending', '==', true).limit(IN_PERSON_SWEEP_LIMIT).get();
186
+ let recorded = 0;
187
+ let failed = 0;
188
+ for (const doc of marked.docs){
189
+ var _doc_get;
190
+ const status = String((_doc_get = doc.get('status')) != null ? _doc_get : '');
191
+ try {
192
+ if (NEVER_PAID.has(status)) {
193
+ await doc.ref.set({
194
+ hardwareSalePending: firebaseAdmin.firestore.FieldValue.delete()
195
+ }, {
196
+ merge: true
197
+ });
198
+ continue;
199
+ }
200
+ if (status !== 'paid') continue;
201
+ const outcome = await recordInPersonPosHardwareSale(config.sellerHostId, String(doc.id), {
202
+ config
203
+ });
204
+ if (outcome.outcome === 'recorded') recorded += 1;
205
+ } catch (error) {
206
+ failed += 1;
207
+ console.error('[pos-hardware-in-person] a marked sale could not be recorded', doc.id, error);
208
+ }
209
+ }
210
+ return {
211
+ recorded,
212
+ failed
213
+ };
214
+ }
215
+ /** The "To attach" list: the selling workspace's pending in-person orders, newest first. */ export async function pendingInPersonPosHardwareOrders(config, limit = 50) {
216
+ const snapshot = await hardwareOrdersRef(config.sellerOrgId).where('attachment.state', '==', 'pending').orderBy('createdAtMs', 'desc').limit(limit).get();
217
+ return snapshot.docs.map((doc)=>({
218
+ id: String(doc.id),
219
+ order: doc.data()
220
+ }));
221
+ }
222
+ /**
223
+ * What the completion listener runs for a sale on the seller store. Never
224
+ * throws into a sale: a failure is logged and the sale stays marked for the
225
+ * sweep.
226
+ */ export async function recordCompletedSaleHardware(event) {
227
+ try {
228
+ await recordInPersonPosHardwareSale(event.hostId, event.orderId, {
229
+ offline: event.offline === true
230
+ });
231
+ } catch (error) {
232
+ console.error('[pos-hardware-in-person] sale not recorded; the sweep will', event.orderId, error);
233
+ }
234
+ }
235
+
236
+ //# sourceMappingURL=pos-hardware-in-person.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/pos-hardware-in-person.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 { firebaseAdmin, getOrgForHost } from '@aglyn/tenant-data-admin'\nimport * as CommerceModel from '../model'\nimport {\n isPosHardwareSkuId,\n normalizePosHardwareSerial,\n type PosHardwareInPersonConfig,\n type PosHardwareOrder,\n type PosHardwareTaxRegion,\n} from '../model/pos-hardware'\nimport {\n inPersonPosHardwareOrder,\n posHardwareRegisterShare,\n type PosHardwareRegisterLine,\n} from '../model/pos-hardware-in-person'\nimport { hardwareOrdersRef, posHardwareInPersonConfig, posHardwareInPersonOrderId } from './pos-hardware'\nimport { recordPosHardwareOrder } from './pos-hardware-webhook'\nimport { posStripeTestMode } from './pos-stripe'\n\n/*==========================================\n * RECORDING A REGISTER SALE OF HARDWARE (AGL-4038).\n *\n * The platform's own store sells a card reader at its register; once the\n * sale is paid this writes the hardware order it becomes — attached to the\n * buyer's workspace when a register user attached one, PENDING on the\n * selling workspace's \"To attach\" list otherwise — and its retained sale\n * record, through the shop's own recorder.\n *\n * ONE SALE IS ONE ORDER. The order's id is derived from the register sale\n * (`posHardwareInPersonOrderId`) and the recorder writes it once by that id,\n * so the completion listener, a replayed webhook, an offline sync and the\n * sweep below can all reach the same sale and only the first writes.\n *\n * NOTHING IS LOST TO A FAILED LISTENER. Listeners on a completed sale are\n * logged and swallowed (the money is already taken), so the sale is marked\n * `hardwareSalePending` when it is written (`pos-hardware-sale-fields.ts`)\n * and the mark is cleared only once the order exists. The sweep records\n * every paid sale still marked, each time the To attach list is read.\n *=========================================*/\n\nexport type InPersonRecordOutcome =\n | { outcome: 'off' | 'not-seller' | 'missing' | 'not-paid' | 'no-hardware' }\n | { outcome: 'recorded' | 'already'; orderId: string; orgId: string; pending: boolean }\n\n/** How many marked sales one sweep records at most. */\nexport const IN_PERSON_SWEEP_LIMIT = 25\n\n/** Statuses after which a marked sale can never be paid, so the mark is dropped. */\nconst NEVER_PAID = new Set(['cancelled', 'canceled', 'voided', 'refunded', 'expired'])\n\nconst text = (value: unknown): string | null =>\n typeof value === 'string' && value.trim() ? value.trim() : null\n\nfunction firestore() {\n return firebaseAdmin.app().firestore()\n}\n\nfunction registerOrderRef(hostId: string, orderId: string) {\n return firestore().collection('hosts').doc(hostId).collection('orders').doc(orderId)\n}\n\n/** Where the store taxes from, and its rate there, from its own tax settings. */\nasync function storeTax(hostId: string): Promise<{ region: PosHardwareTaxRegion | null; ratePct: number | null }> {\n const settings = await firestore().collection('hosts').doc(hostId).collection('settings').doc('store').get()\n const tax = (settings.get('tax') ?? {}) as CommerceModel.TaxSettings\n const origin = tax.origin ?? {}\n const country = text(origin.country)?.toUpperCase() ?? null\n const rate = country ? CommerceModel.resolveTaxRate(tax, origin) : null\n return {\n region: country ? { country, state: text(origin.state)?.toUpperCase() ?? null, postalCode: null } : null,\n ratePct: rate && Number.isFinite(rate.pct) ? rate.pct : null,\n }\n}\n\n/** The store owner's connected Stripe account, where the store's card money goes. */\nasync function storeStripeAccount(hostId: string): Promise<string | null> {\n const owner = await getOrgForHost(hostId).catch(() => null)\n const ownerUid = text((owner?.org as { ownerUid?: unknown } | undefined)?.ownerUid)\n if (!ownerUid) return null\n const profile = await firestore().collection('profiles').doc(ownerUid).get()\n return text(profile.get('stripeAccountId'))\n}\n\n/**\n * Records the hardware order of one register sale on the seller store, once.\n * Never throws for a sale that is not one: it says why it did nothing.\n */\nexport async function recordInPersonPosHardwareSale(\n hostId: string,\n registerOrderId: string,\n options: { offline?: boolean; config?: PosHardwareInPersonConfig | null; now?: number } = {},\n): Promise<InPersonRecordOutcome> {\n const config = options.config === undefined ? posHardwareInPersonConfig() : options.config\n if (!config) return { outcome: 'off' }\n if (hostId !== config.sellerHostId) return { outcome: 'not-seller' }\n const orderRef = registerOrderRef(hostId, registerOrderId)\n const snapshot = await orderRef.get()\n if (!snapshot.exists) return { outcome: 'missing' }\n const order = snapshot.data() as CommerceModel.HostOrder & {\n paidAtMs?: number\n checkoutSessionId?: string\n customerEmail?: string | null\n }\n if (order.status !== 'paid') return { outcome: 'not-paid' }\n\n const lineItems = Array.isArray(order.lineItems) ? order.lineItems : []\n const productIds = [...new Set(lineItems.map((line) => String(line.productId ?? '')).filter(Boolean))]\n const products = new Map(\n (\n await Promise.all(\n productIds.map((id) => firestore().collection('hosts').doc(hostId).collection('products').doc(id).get()),\n )\n ).map((doc: any) => [String(doc.id), doc.exists ? (doc.data() as CommerceModel.HostProduct) : null]),\n )\n const lines: PosHardwareRegisterLine[] = lineItems.map((line) => {\n const sku = products.get(String(line.productId))?.hardwareSku\n return {\n sku: isPosHardwareSkuId(sku) ? sku : null,\n quantity: Number(line.quantity),\n unitAmountCents: Number(line.unitAmountCents),\n }\n })\n const share = posHardwareRegisterShare({\n lines,\n discountCents: Number(order.totals?.discountCents ?? 0),\n taxCents: Number(order.totals?.taxCents ?? 0),\n })\n if (!share) {\n // Marked when it was rung, but no line is hardware now: nothing to record.\n if (order.hardwareSalePending) {\n await orderRef.set({ hardwareSalePending: firebaseAdmin.firestore.FieldValue.delete() }, { merge: true })\n }\n return { outcome: 'no-hardware' }\n }\n\n const orderId = posHardwareInPersonOrderId(hostId, registerOrderId)\n const payments = CommerceModel.orderPayments(order).filter((payment) => payment.status === 'succeeded')\n const livemodes = payments.map((payment) => payment.livemode).filter((mode): mode is boolean => typeof mode === 'boolean')\n const [tax, stripeAccountId] = await Promise.all([storeTax(hostId), storeStripeAccount(hostId)])\n const paidAtMs = Number(order.paidAtMs ?? order.createdAtMs ?? options.now ?? Date.now())\n const hardwareOrder: PosHardwareOrder = inPersonPosHardwareOrder({\n sellerHostId: config.sellerHostId,\n sellerOrgId: config.sellerOrgId,\n registerOrderId,\n number: Number.isFinite(Number(order.number)) ? Number(order.number) : null,\n registerId: text(order.registerId),\n kiosk: order.posSource === 'kiosk',\n offline: options.offline === true || Boolean((order as { offline?: unknown }).offline),\n share,\n paidAtMs,\n tenders: payments.map((payment) => payment.method),\n paymentLinkSessionId:\n text(payments.find((payment) => payment.checkoutSessionId)?.checkoutSessionId) ?? text(order.checkoutSessionId),\n receiptEmail: text(order.customerEmail)?.toLowerCase() ?? null,\n buyer: order.hardwareBuyer,\n termsAcceptance: order.hardwareTermsAcceptance,\n serials: (Array.isArray(order.hardwareSerials) ? order.hardwareSerials : [])\n .map(normalizePosHardwareSerial)\n .filter(Boolean),\n taxRegion: tax.region,\n ratePct: tax.ratePct,\n stripeAccountId,\n // A card payment says which mode it was in; a cash sale takes the\n // deployment's, so a test deployment's booth is never a real sale.\n livemode: livemodes.length ? livemodes.every(Boolean) : !posStripeTestMode(),\n currency: String((order as { currency?: unknown }).currency ?? 'usd').toLowerCase(),\n })\n\n const { created } = await recordPosHardwareOrder(orderId, hardwareOrder)\n // The mark comes off once the order exists, by this call or an earlier one.\n await orderRef.set(\n { hardwareOrderId: orderId, hardwareSalePending: firebaseAdmin.firestore.FieldValue.delete() },\n { merge: true },\n )\n // A buyer with no account, named at the register while the sale was open,\n // is invited to sign up now that there is an order to point them at.\n if (created && hardwareOrder.attachment?.state === 'pending' && hardwareOrder.attachment.email) {\n await (await import('./pos-hardware-attach')).invitePendingBuyer(orderId, hardwareOrder.orgId, hardwareOrder)\n }\n return {\n outcome: created ? 'recorded' : 'already',\n orderId,\n orgId: hardwareOrder.orgId,\n pending: hardwareOrder.attachment?.state === 'pending',\n }\n}\n\n/**\n * Records every paid sale on the seller store that is still marked, at most\n * {@link IN_PERSON_SWEEP_LIMIT} a time, and drops the mark from a sale that\n * can no longer be paid. Never throws: a sale it cannot record stays marked\n * for the next sweep.\n */\nexport async function sweepInPersonPosHardwareSales(\n config: PosHardwareInPersonConfig | null = posHardwareInPersonConfig(),\n): Promise<{ recorded: number; failed: number }> {\n if (!config) return { recorded: 0, failed: 0 }\n const marked = await firestore()\n .collection('hosts')\n .doc(config.sellerHostId)\n .collection('orders')\n .where('hardwareSalePending', '==', true)\n .limit(IN_PERSON_SWEEP_LIMIT)\n .get()\n let recorded = 0\n let failed = 0\n for (const doc of marked.docs as Array<{ id: string; ref: any; get: (field: string) => unknown }>) {\n const status = String(doc.get('status') ?? '')\n try {\n if (NEVER_PAID.has(status)) {\n await doc.ref.set({ hardwareSalePending: firebaseAdmin.firestore.FieldValue.delete() }, { merge: true })\n continue\n }\n if (status !== 'paid') continue\n const outcome = await recordInPersonPosHardwareSale(config.sellerHostId, String(doc.id), { config })\n if (outcome.outcome === 'recorded') recorded += 1\n } catch (error) {\n failed += 1\n console.error('[pos-hardware-in-person] a marked sale could not be recorded', doc.id, error)\n }\n }\n return { recorded, failed }\n}\n\n/** The \"To attach\" list: the selling workspace's pending in-person orders, newest first. */\nexport async function pendingInPersonPosHardwareOrders(\n config: PosHardwareInPersonConfig,\n limit = 50,\n): Promise<Array<{ id: string; order: PosHardwareOrder }>> {\n const snapshot = await hardwareOrdersRef(config.sellerOrgId)\n .where('attachment.state', '==', 'pending')\n .orderBy('createdAtMs', 'desc')\n .limit(limit)\n .get()\n return snapshot.docs.map((doc: any) => ({ id: String(doc.id), order: doc.data() as PosHardwareOrder }))\n}\n\n/**\n * What the completion listener runs for a sale on the seller store. Never\n * throws into a sale: a failure is logged and the sale stays marked for the\n * sweep.\n */\nexport async function recordCompletedSaleHardware(event: {\n hostId: string\n orderId: string\n offline?: boolean\n}): Promise<void> {\n try {\n await recordInPersonPosHardwareSale(event.hostId, event.orderId, { offline: event.offline === true })\n } catch (error) {\n console.error('[pos-hardware-in-person] sale not recorded; the sweep will', event.orderId, error)\n }\n}\n"],"names":["firebaseAdmin","getOrgForHost","CommerceModel","isPosHardwareSkuId","normalizePosHardwareSerial","inPersonPosHardwareOrder","posHardwareRegisterShare","hardwareOrdersRef","posHardwareInPersonConfig","posHardwareInPersonOrderId","recordPosHardwareOrder","posStripeTestMode","IN_PERSON_SWEEP_LIMIT","NEVER_PAID","Set","text","value","trim","firestore","app","registerOrderRef","hostId","orderId","collection","doc","storeTax","settings","tax","get","origin","country","toUpperCase","rate","resolveTaxRate","region","state","postalCode","ratePct","Number","isFinite","pct","storeStripeAccount","owner","catch","ownerUid","org","profile","recordInPersonPosHardwareSale","registerOrderId","options","order","payments","hardwareOrder","config","undefined","outcome","sellerHostId","orderRef","snapshot","exists","data","status","lineItems","Array","isArray","productIds","map","line","String","productId","filter","Boolean","products","Map","Promise","all","id","lines","sku","hardwareSku","quantity","unitAmountCents","share","discountCents","totals","taxCents","hardwareSalePending","set","FieldValue","delete","merge","orderPayments","payment","livemodes","livemode","mode","stripeAccountId","paidAtMs","createdAtMs","now","Date","sellerOrgId","number","registerId","kiosk","posSource","offline","tenders","method","paymentLinkSessionId","find","checkoutSessionId","receiptEmail","customerEmail","toLowerCase","buyer","hardwareBuyer","termsAcceptance","hardwareTermsAcceptance","serials","hardwareSerials","taxRegion","length","every","currency","created","hardwareOrderId","attachment","email","invitePendingBuyer","orgId","pending","sweepInPersonPosHardwareSales","recorded","failed","marked","where","limit","docs","has","ref","error","console","pendingInPersonPosHardwareOrders","orderBy","recordCompletedSaleHardware","event"],"mappings":"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"}
@@ -15,13 +15,51 @@
15
15
  * limitations under the License.
16
16
  */
17
17
  import { POS_HARDWARE_EMAIL_KEYS } from '@aglyn/shared-util-email';
18
- import { type PosHardwareOrder } from '../model/pos-hardware';
18
+ import { type PosHardwareCancelReason, type PosHardwareOrder } from '../model/pos-hardware';
19
19
  export type PosHardwareEmailKind = keyof typeof POS_HARDWARE_EMAIL_KEYS;
20
20
  /** The merge values for one order's emails. Exported for the render spec. */
21
21
  export declare function posHardwareEmailMerge(orderId: string, order: PosHardwareOrder, names: {
22
22
  site: string;
23
23
  org: string;
24
24
  }): Promise<Record<string, string>>;
25
- export declare function sendPosHardwareEmail(kind: PosHardwareEmailKind, orderId: string, order: PosHardwareOrder): Promise<void>;
25
+ /** What became of one email. */
26
+ export type PosHardwareEmailOutcome =
27
+ /** Sent. */
28
+ 'sent'
29
+ /** Nobody to send it to: no address, suppressed, or the account is banned. */
30
+ | 'skipped'
31
+ /** The send failed, and may be tried again. */
32
+ | 'failed';
33
+ export declare function sendPosHardwareEmail(kind: PosHardwareEmailKind, orderId: string, order: PosHardwareOrder): Promise<PosHardwareEmailOutcome>;
34
+ /**
35
+ * Sends one email for an order ONCE, under `key` (the kind by default; one
36
+ * per refund for a refund in parts). The claim is a field on the order,
37
+ * `buyerEmails.{key}`, taken in a transaction before the send, so the staff
38
+ * page and a closure, a retried press or two staff at once, send it once
39
+ * between them. A send that failed can be claimed again; one that found
40
+ * nobody to send to is not tried again. Never throws.
41
+ */
42
+ export declare function sendPosHardwareEmailOnce(kind: PosHardwareEmailKind, orderId: string, order: PosHardwareOrder, key?: string): Promise<PosHardwareEmailOutcome | 'already'>;
43
+ /**
44
+ * The invitation to sign up (AGL-4038), for someone who bought a card reader
45
+ * in person at the platform's own store with no account yet: create the
46
+ * account with this address and the order joins their workspace on its own.
47
+ * Sent in the selling workspace's brand, which is the platform's. Never
48
+ * throws; the caller has already claimed the send.
49
+ */
50
+ /** The invitation's merge values. Exported for the render spec. */
51
+ export declare function posHardwareInviteMerge(orderId: string, order: PosHardwareOrder): Record<string, string>;
52
+ export declare function sendPosHardwareInvite(orderId: string, order: PosHardwareOrder): Promise<void>;
53
+ /**
54
+ * A closure canceled an order staff had already placed with Stripe: the
55
+ * merchant is refunded, and Stripe will still ship it unless someone cancels
56
+ * it there. Once per order.
57
+ */
58
+ export declare function raisePosHardwareCanceledAfterOrderingAlert(orderId: string, order: PosHardwareOrder, reason: PosHardwareCancelReason): Promise<void>;
59
+ /**
60
+ * Stripe refused a closure's refund, and the closure went ahead without it.
61
+ * Carries the payment to refund by hand, never the buyer.
62
+ */
63
+ export declare function raisePosHardwareRefundFailedAlert(orderId: string, order: PosHardwareOrder, reason: PosHardwareCancelReason, error: string): Promise<void>;
26
64
  /** "New hardware order", once per order. */
27
65
  export declare function raisePosHardwareOrderAlert(orderId: string, order: PosHardwareOrder): Promise<void>;
@@ -17,13 +17,14 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
17
17
  */ import { formatOperatorAlertAmount } from "@aglyn/aglyn/app-utils/operator-alerts";
18
18
  import { isAccountBanLockdownReason, normalizeOrgLockdown } from "@aglyn/aglyn/app-utils/lockdown";
19
19
  import { POS_HARDWARE_EMAIL_KEYS, sendEmail } from "@aglyn/shared-util-email";
20
+ import { platformConsoleOrigin } from "@aglyn/aglyn/app-utils/platform-brand";
20
21
  import { firebaseAdmin, hostDisplayName, meterPlatformEmail, raiseOperatorAlert } from "@aglyn/tenant-data-admin";
21
22
  import { filterSuppressedEmails } from "@aglyn/tenant-data-admin/server/email-suppression";
22
23
  import { orgSystemEmailBrand, renderSystemEmailContent } from "@aglyn/tenant-data-admin/server/render-system-email";
23
- import { COMMERCE_POS_HARDWARE_ORDER } from "../constants/operator-alerts.js";
24
+ import { COMMERCE_POS_HARDWARE_CANCELED_AFTER_ORDERING, COMMERCE_POS_HARDWARE_ORDER, COMMERCE_POS_HARDWARE_REFUND_FAILED } from "../constants/operator-alerts.js";
24
25
  import { carrierLabelFor } from "../model/tracking-url.js";
25
26
  import { formatPosHardwareCents, POS_HARDWARE_ANCHOR } from "../model/pos-hardware.js";
26
- import { posHardwareOrderNumber, posSettingsUrl } from "./pos-hardware.js";
27
+ import { hardwareOrdersRef, posHardwareOrderNumber, posSettingsUrl } from "./pos-hardware.js";
27
28
  /** The lines as the emails list them, one per item. */ function itemsText(order) {
28
29
  var _order_lines;
29
30
  return ((_order_lines = order.lines) != null ? _order_lines : []).map((line)=>`${line.name} × ${line.quantity}`).join('\n');
@@ -55,18 +56,38 @@ async function siteAndOrgNames(order) {
55
56
  const lock = normalizeOrgLockdown(org == null ? void 0 : org.data());
56
57
  return {
57
58
  site: (host == null ? void 0 : host.exists) ? hostDisplayName(host.data(), order.hostId) : 'your site',
58
- org: String((_ref = org == null ? void 0 : org.get('name')) != null ? _ref : '').trim() || 'your workspace',
59
+ org: String((_ref = org == null ? void 0 : org.get('name')) != null ? _ref : '').trim() || UNNAMED_WORKSPACE,
59
60
  ban: Boolean(lock && isAccountBanLockdownReason(lock.reason))
60
61
  };
61
62
  }
62
63
  /** The fallback subject and first line, when no design renders. */ const FALLBACK = {
63
64
  received: (number)=>`We have your card reader order ${number}`,
64
65
  shipped: (number)=>`Your card reader order ${number} has shipped`,
65
- delivered: (number)=>`Your card reader order ${number} was delivered`
66
+ delivered: (number)=>`Your card reader order ${number} was delivered`,
67
+ canceled: (number)=>`Your card reader order ${number} was canceled and refunded`,
68
+ refunded: (number)=>`Your refund for card reader order ${number}`,
69
+ invited: (number)=>`Your card reader order ${number} is waiting for your account`,
70
+ returnRefunded: (number)=>`We refunded your returned card reader order ${number}`
66
71
  };
72
+ /** The fallback a workspace with no name gets in a sentence. */ const UNNAMED_WORKSPACE = 'your workspace';
73
+ /**
74
+ * Who canceled the order and why, as the email's first sentence; the
75
+ * template goes on "It had not shipped yet, so we refunded …".
76
+ */ function cancelReasonText(reason, org) {
77
+ if (reason === 'workspace-closed') {
78
+ return org && org !== UNNAMED_WORKSPACE ? `We canceled your order because the ${org} workspace was deleted.` : 'We canceled your order because your workspace was deleted.';
79
+ }
80
+ if (reason === 'account-closed') return 'We canceled your order because the account that placed it was closed.';
81
+ return 'Our team canceled your order.';
82
+ }
83
+ /** Why, for staff: the closure that canceled it, never who the buyer was. */ function staffReasonText(reason, orgId) {
84
+ if (reason === 'workspace-closed') return `its workspace ${orgId} was deleted`;
85
+ if (reason === 'account-closed') return 'the account that placed it was closed';
86
+ return 'staff canceled it';
87
+ }
67
88
  /** The merge values for one order's emails. Exported for the render spec. */ export async function posHardwareEmailMerge(orderId, order, names) {
68
- var _order_totalCents, _ref, _ref1, _ref2;
69
- var _order_shipping, _order_tracking, _order_tracking1, _order_tracking2;
89
+ var _order_totalCents, _ref, _ref1, _ref2, _ref3, _order_refundedCents, _ref4, _ref5, _ref6, _order_refunds, _order_totalCents1, _order_refundedCents1;
90
+ var _order_shipping, _order_tracking, _order_tracking1, _order_tracking2, _slice_;
70
91
  const base = await posSettingsUrl(order.hostId);
71
92
  const [path] = base.split('#');
72
93
  const ordersUrl = `${path}#${POS_HARDWARE_ANCHOR}`;
@@ -83,27 +104,40 @@ async function siteAndOrgNames(order) {
83
104
  // An unknown carrier has no tracker to link; the card shows the number.
84
105
  'order.trackingUrl': (_ref2 = (_order_tracking2 = order.tracking) == null ? void 0 : _order_tracking2.url) != null ? _ref2 : ordersUrl,
85
106
  'order.ordersUrl': ordersUrl,
86
- 'order.setupUrl': `${path}#pos-devices`
107
+ 'order.setupUrl': `${path}#pos-devices`,
108
+ // What Stripe reported refunding, or the whole charge where it has not.
109
+ 'order.refunded': formatPosHardwareCents((_ref3 = (_order_refundedCents = order.refundedCents) != null ? _order_refundedCents : order.totalCents) != null ? _ref3 : 0),
110
+ // This refund alone, for an order refunded in parts; the whole of it otherwise.
111
+ 'order.refundedNow': formatPosHardwareCents((_ref4 = (_ref5 = (_ref6 = (_slice_ = ((_order_refunds = order.refunds) != null ? _order_refunds : []).slice(-1)[0]) == null ? void 0 : _slice_.cents) != null ? _ref6 : order.refundedCents) != null ? _ref5 : order.totalCents) != null ? _ref4 : 0),
112
+ 'order.cancelReason': cancelReasonText(order.cancelReason, names.org),
113
+ // What a return kept back: the original shipping and any restocking fee.
114
+ 'order.kept': formatPosHardwareCents(Math.max(0, ((_order_totalCents1 = order.totalCents) != null ? _order_totalCents1 : 0) - ((_order_refundedCents1 = order.refundedCents) != null ? _order_refundedCents1 : 0)))
87
115
  };
88
116
  }
89
117
  export async function sendPosHardwareEmail(kind, orderId, order) {
90
118
  try {
91
- var _order_contactEmail;
119
+ var _order_contactEmail, _ref;
120
+ var _order_posSale;
92
121
  const to = String((_order_contactEmail = order.contactEmail) != null ? _order_contactEmail : '').trim();
93
- if (!to) return;
122
+ if (!to) return 'skipped';
94
123
  const names = await siteAndOrgNames(order);
95
124
  // A ban is a ban (AGL-3420): after its notice the account is sent nothing.
96
- if (names.ban) return;
125
+ if (names.ban) return 'skipped';
97
126
  const [recipient] = await filterSuppressedEmails([
98
127
  to
99
128
  ]);
100
- if (!recipient) return;
129
+ if (!recipient) return 'skipped';
101
130
  const merge = await posHardwareEmailMerge(orderId, order, names);
102
131
  const subject = FALLBACK[kind](merge['order.number']);
103
- const brand = await orgSystemEmailBrand(order.orgId);
132
+ // A refund in person is in the selling workspace's brand, as its
133
+ // invitation is; the rest in the buyer's.
134
+ const brand = await orgSystemEmailBrand(kind === 'refunded' ? (_ref = (_order_posSale = order.posSale) == null ? void 0 : _order_posSale.orgId) != null ? _ref : order.orgId : order.orgId);
135
+ // A canceled order's workspace may be gone, so its fallback names the
136
+ // refund rather than linking a card that no longer opens.
137
+ const last = kind === 'canceled' ? `Refunded: ${merge['order.refunded']}` : kind === 'refunded' ? `Refunded now: ${merge['order.refundedNow']}` : merge['order.ordersUrl'];
104
138
  const content = await renderSystemEmailContent(POS_HARDWARE_EMAIL_KEYS[kind], merge, brand, {
105
139
  subject,
106
- text: `${subject}\n\n${merge['order.items']}\n\n${merge['order.ordersUrl']}`
140
+ text: `${subject}\n\n${merge['order.items']}\n\n${last}`
107
141
  });
108
142
  const result = await sendEmail(_extends({
109
143
  to: recipient
@@ -112,9 +146,156 @@ export async function sendPosHardwareEmail(kind, orderId, order) {
112
146
  } : {}, {
113
147
  context: POS_HARDWARE_EMAIL_KEYS[kind]
114
148
  }));
115
- if (result.sent) await meterPlatformEmail(1);
149
+ if (!result.sent) return 'failed';
150
+ await meterPlatformEmail(1);
151
+ return 'sent';
116
152
  } catch (error) {
117
153
  console.error('[pos-hardware] email failed', kind, orderId, error);
154
+ return 'failed';
155
+ }
156
+ }
157
+ /** How long a claimed send that never finished holds the next one back. */ const EMAIL_CLAIM_STALE_MS = 10 * 60 * 1000;
158
+ /**
159
+ * Sends one email for an order ONCE, under `key` (the kind by default; one
160
+ * per refund for a refund in parts). The claim is a field on the order,
161
+ * `buyerEmails.{key}`, taken in a transaction before the send, so the staff
162
+ * page and a closure, a retried press or two staff at once, send it once
163
+ * between them. A send that failed can be claimed again; one that found
164
+ * nobody to send to is not tried again. Never throws.
165
+ */ export async function sendPosHardwareEmailOnce(kind, orderId, order, key = kind) {
166
+ try {
167
+ const firestore = firebaseAdmin.app().firestore();
168
+ const ref = hardwareOrdersRef(order.orgId).doc(orderId);
169
+ const claimed = await firestore.runTransaction(async (transaction)=>{
170
+ var _ref, _held_atMs;
171
+ var _snapshot_data;
172
+ const snapshot = await transaction.get(ref);
173
+ if (!snapshot.exists) return false;
174
+ const held = ((_ref = (_snapshot_data = snapshot.data()) == null ? void 0 : _snapshot_data.buyerEmails) != null ? _ref : {})[key];
175
+ const now = Date.now();
176
+ if ((held == null ? void 0 : held.state) === 'sent' || (held == null ? void 0 : held.state) === 'skipped') return false;
177
+ if ((held == null ? void 0 : held.state) === 'sending' && now - Number((_held_atMs = held.atMs) != null ? _held_atMs : 0) < EMAIL_CLAIM_STALE_MS) return false;
178
+ transaction.set(ref, {
179
+ buyerEmails: {
180
+ [key]: {
181
+ state: 'sending',
182
+ atMs: now
183
+ }
184
+ }
185
+ }, {
186
+ merge: true
187
+ });
188
+ return true;
189
+ });
190
+ if (!claimed) return 'already';
191
+ const outcome = await sendPosHardwareEmail(kind, orderId, order);
192
+ await ref.set({
193
+ buyerEmails: {
194
+ [key]: {
195
+ state: outcome === 'sent' ? 'sent' : outcome,
196
+ atMs: Date.now()
197
+ }
198
+ }
199
+ }, {
200
+ merge: true
201
+ }).catch((error)=>console.error('[pos-hardware] email claim not settled', kind, orderId, error));
202
+ return outcome;
203
+ } catch (error) {
204
+ console.error('[pos-hardware] email claim failed', kind, orderId, error);
205
+ return 'failed';
206
+ }
207
+ }
208
+ /**
209
+ * The invitation to sign up (AGL-4038), for someone who bought a card reader
210
+ * in person at the platform's own store with no account yet: create the
211
+ * account with this address and the order joins their workspace on its own.
212
+ * Sent in the selling workspace's brand, which is the platform's. Never
213
+ * throws; the caller has already claimed the send.
214
+ */ /** The invitation's merge values. Exported for the render spec. */ export function posHardwareInviteMerge(orderId, order) {
215
+ var _order_totalCents;
216
+ return {
217
+ 'order.number': posHardwareOrderNumber(orderId),
218
+ 'order.items': itemsText(order),
219
+ 'order.total': formatPosHardwareCents((_order_totalCents = order.totalCents) != null ? _order_totalCents : 0),
220
+ 'order.signUpUrl': `${platformConsoleOrigin()}/signup`
221
+ };
222
+ }
223
+ export async function sendPosHardwareInvite(orderId, order) {
224
+ try {
225
+ var _ref, _ref1;
226
+ var _order_attachment, _order_posSale;
227
+ const to = String((_ref = (_order_attachment = order.attachment) == null ? void 0 : _order_attachment.email) != null ? _ref : '').trim();
228
+ if (!to) return;
229
+ const [recipient] = await filterSuppressedEmails([
230
+ to
231
+ ]);
232
+ if (!recipient) return;
233
+ const merge = posHardwareInviteMerge(orderId, order);
234
+ const signUpUrl = merge['order.signUpUrl'];
235
+ const subject = FALLBACK.invited(merge['order.number']);
236
+ const brand = await orgSystemEmailBrand((_ref1 = (_order_posSale = order.posSale) == null ? void 0 : _order_posSale.orgId) != null ? _ref1 : order.orgId);
237
+ const content = await renderSystemEmailContent(POS_HARDWARE_EMAIL_KEYS.invited, merge, brand, {
238
+ subject,
239
+ text: `${subject}\n\n${merge['order.items']}\n\nCreate your account with this email address: ${signUpUrl}`
240
+ });
241
+ const result = await sendEmail(_extends({
242
+ to: recipient
243
+ }, content, brand.fromName ? {
244
+ fromName: brand.fromName
245
+ } : {}, {
246
+ context: POS_HARDWARE_EMAIL_KEYS.invited
247
+ }));
248
+ if (result.sent) await meterPlatformEmail(1);
249
+ } catch (error) {
250
+ console.error('[pos-hardware] invitation failed', orderId, error);
251
+ }
252
+ }
253
+ /**
254
+ * A closure canceled an order staff had already placed with Stripe: the
255
+ * merchant is refunded, and Stripe will still ship it unless someone cancels
256
+ * it there. Once per order.
257
+ */ export async function raisePosHardwareCanceledAfterOrderingAlert(orderId, order, reason) {
258
+ try {
259
+ var _order_stripeHardwareOrderId, _order_totalCents, _order_lines;
260
+ const stripeOrderId = String((_order_stripeHardwareOrderId = order.stripeHardwareOrderId) != null ? _order_stripeHardwareOrderId : '').trim();
261
+ await raiseOperatorAlert(COMMERCE_POS_HARDWARE_CANCELED_AFTER_ORDERING, {
262
+ dedupeKey: orderId,
263
+ orgId: order.orgId,
264
+ hostId: order.hostId,
265
+ context: {
266
+ orderNumber: posHardwareOrderNumber(orderId),
267
+ amount: formatOperatorAlertAmount((_order_totalCents = order.totalCents) != null ? _order_totalCents : 0),
268
+ items: ((_order_lines = order.lines) != null ? _order_lines : []).map((line)=>`${line.quantity} × ${line.name}`).join(', '),
269
+ reason: staffReasonText(reason, order.orgId),
270
+ stripeOrder: stripeOrderId ? ` (Stripe order ${stripeOrderId})` : ''
271
+ }
272
+ });
273
+ } catch (error) {
274
+ console.error('[pos-hardware] canceled-after-ordering alert failed', orderId, error);
275
+ }
276
+ }
277
+ /**
278
+ * Stripe refused a closure's refund, and the closure went ahead without it.
279
+ * Carries the payment to refund by hand, never the buyer.
280
+ */ export async function raisePosHardwareRefundFailedAlert(orderId, order, reason, error) {
281
+ try {
282
+ var _order_stripeHardwareOrderId, _order_totalCents, _order_stripePaymentIntentId;
283
+ const stripeOrderId = String((_order_stripeHardwareOrderId = order.stripeHardwareOrderId) != null ? _order_stripeHardwareOrderId : '').trim();
284
+ await raiseOperatorAlert(COMMERCE_POS_HARDWARE_REFUND_FAILED, {
285
+ dedupeKey: orderId,
286
+ orgId: order.orgId,
287
+ hostId: order.hostId,
288
+ context: {
289
+ orderNumber: posHardwareOrderNumber(orderId),
290
+ amount: formatOperatorAlertAmount((_order_totalCents = order.totalCents) != null ? _order_totalCents : 0),
291
+ reason: staffReasonText(reason, order.orgId),
292
+ error: error || 'no reason given',
293
+ paymentIntentId: (_order_stripePaymentIntentId = order.stripePaymentIntentId) != null ? _order_stripePaymentIntentId : 'for this order (no payment id is recorded on it)',
294
+ orderedNote: order.status === 'ordered' ? `. It had already been placed with Stripe${stripeOrderId ? ` as ${stripeOrderId}` : ''}, so cancel it there too before it ships` : ''
295
+ }
296
+ });
297
+ } catch (failure) {
298
+ console.error('[pos-hardware] refund-failed alert failed', orderId, failure);
118
299
  }
119
300
  }
120
301
  /** "New hardware order", once per order. */ export async function raisePosHardwareOrderAlert(orderId, order) {