@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-return.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 { claimAttempt, type PluginApiHandler, type PluginApiRequest } from '@aglyn/aglyn/server'\nimport { createResourceUid } from '@aglyn/aglyn/app-utils/create-resource-uid'\nimport { nameSearchKey } from '@aglyn/aglyn/app-utils/name-search'\nimport { recordPluginPersonRefund } from '@aglyn/aglyn/plugin-manager/plugin-person-records'\nimport { reverseOrderConversion } from '@aglyn/aglyn/plugin-manager/plugin-conversion-credit'\nimport { checkoutCreditProvider } from '@aglyn/aglyn/plugin-manager/plugin-checkout-credits'\nimport * as CommerceModel from '../model'\nimport {\n planPosReturn,\n posMoney,\n posRefundableByTender,\n posReturnedQuantities,\n posReturnLineValues,\n posTenderLabel,\n POS_STRIPE_TENDERS,\n splitPosRefund,\n type PosCashEvent,\n type PosRefundAllocation,\n type PosRegisterReturn,\n type PosReturnPick,\n type PosReturnSource,\n} from '../model/commerce-pos-ops'\nimport { ORDER_REFUNDED_EVENT, RETURN_REFUNDED_EVENT } from '../model/order-events'\nimport { raiseOrderEvent } from './order-events'\nimport { applyGiftCardRiskToOrder } from './gift-card-risk'\nimport { notifyOrderBuyer } from './order-notifications'\nimport { decidePosRefundAuthority } from './pos-refund-authority'\nimport {\n authorizePosOps,\n defaultPosOpsDeps,\n posOpsBody,\n posOpsCleanId,\n posOpsIdempotencyKey,\n readPosRegister,\n isPosManager,\n resolvePosCashier,\n type PosOpsDeps,\n} from './pos-ops-gate'\nimport { createStripeRefund } from './stripe-refund'\n\n/*==========================================\n * RETURNS AT THE REGISTER (AGL-3609): `POST /api/commerce/pos-return`.\n *\n * find an order by its number (typed or scanned off the receipt's\n * barcode), its id, or the customer's email\n * refund picked lines and quantities back, restocked to the register's\n * location, the money sent back to the sale's OWN payments\n *\n * Each payment gets its money back the way it came: a card through Stripe\n * (the same refund the order dialog sends), cash out of the drawer — a cash\n * event on the open shift, so the count still balances — a gift card\n * re-credited, and a room charge reversed on the stay's folio.\n *\n * THE ORDER OF WORK is what keeps a failure honest:\n * 1. every refusal that needs no money to move (role, limit, quantities,\n * the split, the shift rule) — before anything is written;\n * 2. the attempt claim, so a retried tap replays instead of refunding twice;\n * 3. the RESERVATION on the order, in a transaction that re-reads it: the\n * cents, the units and each payment's share are taken before any money\n * moves, so two registers returning the same line cannot both succeed;\n * 4. the Stripe refunds first, because they are the ones that can say no —\n * if the first one does, nothing has moved and the reservation is\n * handed back whole;\n * 5. then the tenders that cannot fail for a reason outside this database.\n * A card that fails after another payment already went back leaves a\n * PARTIAL return: what moved is recorded, what did not is handed back on\n * the order, and the cashier is told the amount still owed.\n *=========================================*/\n\nexport interface PosReturnSideEffects {\n hostId: string\n orderId: string\n /** The return's id, the same under the register and in the store's returns. */\n returnId: string\n /** The return as the store's returns list holds it, for the return event. */\n storeReturn: CommerceModel.HostReturn\n /** The Stripe refunds the return made, if any, for the refund event. */\n refundIds: string[]\n email: string | null | undefined\n refundCents: number\n closedTheOrder: boolean\n returnedProductIds: string[]\n fullyRefunded: boolean\n lineIndexes: number[]\n /** The lines this return finished taking back in full. */\n fullLineIndexes: number[]\n}\n\nexport interface PosReturnDeps extends PosOpsDeps {\n /** What every refund tells the rest of the workspace, after the money moved. Never throws. */\n afterRefund(input: PosReturnSideEffects): Promise<void>\n}\n\nexport function defaultPosReturnDeps(): PosReturnDeps {\n const base = defaultPosOpsDeps()\n return {\n ...base,\n afterRefund: async (input) => {\n const settle = async (label: string, work: () => Promise<unknown>) => {\n try {\n await work()\n } catch (error) {\n console.error(`[pos-return] ${label} failed`, input.orderId, error)\n }\n }\n const hostRef = base.firestore().collection('hosts').doc(input.hostId)\n if (input.returnedProductIds.length) {\n await settle('gift card void', () =>\n applyGiftCardRiskToOrder({\n firestore: base.firestore(),\n hostRef,\n orderId: input.orderId,\n action: {\n kind: 'void',\n reason: 'refund',\n ...(input.fullyRefunded ? {} : { productIds: input.returnedProductIds }),\n },\n }),\n )\n }\n await settle('person refund', () =>\n recordPluginPersonRefund({\n hostId: input.hostId,\n refId: input.orderId,\n email: input.email,\n amountCents: input.refundCents,\n closedTheSale: input.closedTheOrder,\n }),\n )\n await settle('conversion reversal', () =>\n reverseOrderConversion({\n hostId: input.hostId,\n orderId: input.orderId,\n amountCents: input.refundCents,\n closedTheOrder: input.closedTheOrder,\n }),\n )\n // The same events a refund from the order dialog and a refunded online\n // return raise, so accounting and the merchant's webhooks hear a\n // register return too (AGL-3611's events).\n await settle('refund event', () =>\n raiseOrderEvent(ORDER_REFUNDED_EVENT, {\n hostId: input.hostId,\n orderId: input.orderId,\n key: `pos-return:${input.returnId}`,\n extra: {\n refund: {\n id: input.refundIds[0] ?? null,\n amountCents: input.refundCents,\n lineItemIds: input.fullLineIndexes,\n full: input.fullyRefunded,\n },\n },\n }),\n )\n await settle('return event', () =>\n raiseOrderEvent(RETURN_REFUNDED_EVENT, {\n hostId: input.hostId,\n orderId: input.orderId,\n key: `return-refunded:${input.returnId}`,\n extra: {\n return: {\n id: input.returnId,\n status: input.storeReturn.status,\n lines: input.storeReturn.lines.map((line) => ({ ...line })),\n refundCents: input.storeReturn.refundCents ?? null,\n },\n },\n }),\n )\n await settle('buyer notice', () =>\n notifyOrderBuyer({ hostId: input.hostId, orderId: input.orderId }, 'refunded', {\n refundId: '',\n refundCents: input.refundCents,\n refundLineIndexes: input.lineIndexes,\n fullyRefunded: input.fullyRefunded,\n }),\n )\n },\n }\n}\n\ntype Outcome = { status: number; body: Record<string, unknown> }\n\n/** The statuses a return may be taken against. */\nconst RETURNABLE: ReadonlySet<string> = new Set([\n 'paid',\n 'partially_fulfilled',\n 'fulfilled',\n 'delivered',\n])\n\n/** One order as the return dialog lists it. */\nfunction returnSummary(id: string, raw: Record<string, any>, held: readonly number[] = []) {\n const order = CommerceModel.liftLegacyOrder(raw as any) as unknown as PosReturnSource &\n Record<string, any>\n const values = posReturnLineValues(order)\n const returned = posReturnedQuantities(order)\n return {\n id,\n number: order['number'] ?? null,\n label: CommerceModel.formatOrderNumber(order as any, id),\n status: order['status'],\n channel: order['channel'] ?? 'online',\n createdAtMs: Number(order['createdAtMs'] ?? 0),\n customerEmail: order['customerEmail'] ?? null,\n customerName: order['customerName'] ?? null,\n totalCents: Number(order.totals?.totalCents ?? order.amountCents ?? 0),\n refundedCents: Number(order.refundedCents ?? 0),\n returnable: RETURNABLE.has(String(order['status'])),\n lines: (order.lineItems ?? []).map((line: any, index: number) => ({\n index,\n name: String(line?.name ?? ''),\n variantLabel: line?.variantLabel ?? null,\n quantity: Math.max(1, Math.round(Number(line?.quantity ?? 1))),\n returned: returned[index] ?? 0,\n // Units an online return holds or already took (AGL-3611).\n held: held[index] ?? 0,\n valueCents: values[index] ?? 0,\n })),\n tenders: posRefundableByTender(order).map((tender) => ({\n id: tender.id,\n method: tender.method,\n label: posTenderLabel(tender),\n amountCents: tender.amountCents,\n refundableCents: tender.refundableCents,\n })),\n }\n}\n\nasync function findOrders(\n hostRef: FirebaseFirestore.DocumentReference,\n rawText: unknown,\n): Promise<Array<{ id: string; data: Record<string, any> }>> {\n const text = String(rawText ?? '').trim().slice(0, 200)\n if (!text) return []\n const orders = hostRef.collection('orders')\n const digits = text.replace(/^#/, '')\n if (/^\\d{1,12}$/.test(digits)) {\n const snapshot = await orders.where('number', '==', Number(digits)).limit(5).get()\n return snapshot.docs.map((doc) => ({ id: doc.id, data: (doc.data() ?? {}) as Record<string, any> }))\n }\n if (text.includes('@')) {\n const snapshot = await orders\n .where('customerEmailLower', '==', nameSearchKey(text))\n .orderBy('createdAtMs', 'desc')\n .limit(10)\n .get()\n return snapshot.docs.map((doc) => ({ id: doc.id, data: (doc.data() ?? {}) as Record<string, any> }))\n }\n const id = posOpsCleanId(text)\n if (!id) return []\n const snapshot = await orders.doc(id).get()\n return snapshot.exists ? [{ id, data: (snapshot.data() ?? {}) as Record<string, any> }] : []\n}\n\nfunction parsePicks(raw: unknown): PosReturnPick[] {\n if (!Array.isArray(raw)) return []\n return raw.slice(0, 200).map((entry: any) => ({\n index: Number(entry?.index),\n quantity: Number(entry?.quantity),\n }))\n}\n\nfunction parseSplit(raw: unknown): Array<{ paymentId: string; amountCents: number }> | null {\n if (!Array.isArray(raw) || !raw.length) return null\n return raw.slice(0, 20).map((entry: any) => ({\n paymentId: String(entry?.paymentId ?? ''),\n amountCents: Number(entry?.amountCents),\n }))\n}\n\n/** What a refunded tender moved, and how to hand back a reservation it did not. */\ninterface TenderResult {\n allocation: PosRefundAllocation\n status: 'refunded' | 'failed'\n refundId?: string\n error?: string\n}\n\nexport async function handlePosReturn(deps: PosReturnDeps, req: PluginApiRequest): Promise<Outcome> {\n if (req.method !== 'POST') return { status: 405, body: { error: 'Method not allowed' } }\n const body = posOpsBody(req)\n const gate = await authorizePosOps(deps, req, body['hostId'])\n if ('error' in gate) return { status: gate.status, body: { error: gate.error } }\n const staff = gate.staff\n const action = String(body['action'] ?? '')\n\n if (action === 'find') {\n const found = await findOrders(staff.hostRef, body['text'])\n const held = await Promise.all(\n found.map(async (entry) =>\n unitsHeldByOnlineReturns(\n (await staff.hostRef.collection('returns').where('orderId', '==', entry.id).get()).docs,\n ),\n ),\n )\n return {\n status: 200,\n body: { orders: found.map((entry, at) => returnSummary(entry.id, entry.data, held[at])) },\n }\n }\n if (action !== 'refund') return { status: 400, body: { error: 'Unknown action' } }\n\n const register = await readPosRegister(staff, body['registerId'])\n if ('error' in register) return { status: register.status, body: { error: register.error } }\n const registerId = register.ref.id\n const orderId = posOpsCleanId(body['orderId'])\n if (!orderId) return { status: 400, body: { error: 'Missing orderId' } }\n const idempotencyKey = posOpsIdempotencyKey(req)\n if (!idempotencyKey) {\n return { status: 400, body: { error: 'A refund needs an Idempotency-Key header.' } }\n }\n const picks = parsePicks(body['lines'])\n const requestedSplit = parseSplit(body['tenders'])\n const restock = body['restock'] !== false\n const reason = String(body['reason'] ?? '').trim().slice(0, 200)\n const reasonCode: CommerceModel.ReturnReason = CommerceModel.RETURN_REASONS.includes(\n body['reasonCode'] as CommerceModel.ReturnReason,\n )\n ? (body['reasonCode'] as CommerceModel.ReturnReason)\n : 'other'\n const firestore = deps.firestore()\n const orderRef = staff.hostRef.collection('orders').doc(orderId)\n const storeReturns = staff.hostRef.collection('returns').where('orderId', '==', orderId)\n\n // 1. Every refusal that needs no money to move.\n const snapshot = await orderRef.get()\n if (!snapshot.exists) return { status: 404, body: { error: 'Unknown order' } }\n const order = CommerceModel.liftLegacyOrder(snapshot.data() as any) as unknown as PosReturnSource &\n Record<string, any>\n if (!RETURNABLE.has(String(order['status']))) {\n return { status: 409, body: { error: `Orders in \"${order['status']}\" cannot be returned.` } }\n }\n if (CommerceModel.orderDisputeBlocksRefund(order as any)) {\n return {\n status: 409,\n body: {\n error:\n 'A chargeback is open on this order, so it was not refunded. Respond to the ' +\n 'dispute or accept it in the Stripe dashboard first.',\n },\n }\n }\n const plan = planPosReturn(order, picks, unitsHeldByOnlineReturns((await storeReturns.get()).docs))\n if ('error' in plan) return { status: 400, body: { error: plan.error } }\n const split = splitPosRefund(order, plan.refundCents, requestedSplit)\n if ('error' in split) return { status: 400, body: { error: split.error } }\n\n const cashier = await resolvePosCashier(deps, staff, registerId, body['cashierAssertion'])\n // The limit is the person at the till's: a PIN-switched cashier is held\n // to it even on a device a workspace admin signed in on.\n const cashierIsManager =\n cashier.cashierId === staff.uid\n ? staff.isManager\n : await memberIsPosManager(deps, staff.hostRef, staff.hostId, cashier.cashierId)\n const authority = await decidePosRefundAuthority(deps, {\n hostId: staff.hostId,\n hostRef: staff.hostRef,\n registerId,\n refundCents: plan.refundCents,\n limitCents: staff.settings.refundLimitCents,\n isManager: cashierIsManager,\n managerAssertion: body['managerAssertion'],\n })\n if ('body' in authority) return { status: 403, body: authority.body }\n\n const needsCash = split.allocations.some((slice) => slice.method === 'cash')\n const needsStripe = split.allocations.some((slice) => POS_STRIPE_TENDERS.has(slice.method))\n const openShiftId = String(register.data['openShiftId'] ?? '') || null\n if (needsCash && !openShiftId && staff.settings.requireOpenShift) {\n return { status: 409, body: { error: 'Open a shift before paying cash out of the drawer.' } }\n }\n if (needsStripe && !process.env.STRIPE_SECRET_KEY) {\n return { status: 501, body: { error: 'Payments are not configured.' } }\n }\n\n // 2. The attempt claim.\n const claimed = await claimAttempt(firestore as any, {\n kind: 'pos-return',\n scopeId: staff.hostId,\n orgId: staff.orgId,\n key: `${orderId}:${idempotencyKey}`,\n busyMessage: 'This return is already being refunded',\n })\n if ('replay' in claimed) return { status: claimed.replay.status, body: claimed.replay.body as any }\n const claim = claimed.claim\n\n // 3. The reservation, re-read under the transaction.\n type Reserved = {\n refundCents: number\n lineCents: number[]\n completedLines: number[]\n allocations: PosRefundAllocation[]\n prior: { refundedCents: number; returnedQuantities: Record<string, number>; posPaymentRefunds: Record<string, number> }\n }\n let reserved: Reserved\n try {\n reserved = await firestore.runTransaction(async (transaction) => {\n const fresh = CommerceModel.liftLegacyOrder(\n ((await transaction.get(orderRef)).data() ?? {}) as any,\n ) as unknown as PosReturnSource & Record<string, any>\n if (!RETURNABLE.has(String(fresh['status']))) {\n throw new ReturnRefusal(409, `Orders in \"${fresh['status']}\" cannot be returned.`)\n }\n const freshPlan = planPosReturn(\n fresh,\n picks,\n unitsHeldByOnlineReturns((await transaction.get(storeReturns)).docs),\n )\n if ('error' in freshPlan) throw new ReturnRefusal(409, freshPlan.error)\n const freshSplit = splitPosRefund(fresh, freshPlan.refundCents, requestedSplit)\n if ('error' in freshSplit) throw new ReturnRefusal(409, freshSplit.error)\n const prior = {\n refundedCents: Number(fresh.refundedCents ?? 0),\n returnedQuantities: { ...(fresh.returnedQuantities ?? {}) },\n posPaymentRefunds: { ...(fresh.posPaymentRefunds ?? {}) },\n }\n const posPaymentRefunds = { ...prior.posPaymentRefunds }\n for (const slice of freshSplit.allocations) {\n posPaymentRefunds[slice.paymentId] = (posPaymentRefunds[slice.paymentId] ?? 0) + slice.amountCents\n }\n transaction.update(orderRef, {\n refundedCents: prior.refundedCents + freshPlan.refundCents,\n returnedQuantities: freshPlan.returnedQuantities,\n posPaymentRefunds,\n })\n return {\n refundCents: freshPlan.refundCents,\n lineCents: freshPlan.lineCents,\n completedLines: freshPlan.completedLines,\n allocations: freshSplit.allocations,\n prior,\n }\n })\n } catch (error) {\n await claim.release()\n if (error instanceof ReturnRefusal) return { status: error.status, body: { error: error.message } }\n throw error\n }\n\n // 4–5. The money, Stripe first.\n const tenders = posRefundableByTender(order)\n const tenderOf = (paymentId: string) => tenders.find((tender) => tender.id === paymentId)\n const ordered = [...reserved.allocations].sort(\n (a, b) => Number(POS_STRIPE_TENDERS.has(b.method)) - Number(POS_STRIPE_TENDERS.has(a.method)),\n )\n const results: TenderResult[] = []\n for (const allocation of ordered) {\n const tender = tenderOf(allocation.paymentId)\n const anyMoved = results.some((result) => result.status === 'refunded')\n try {\n if (POS_STRIPE_TENDERS.has(allocation.method)) {\n const paymentIntentId = tender?.paymentIntentId ?? String(order['paymentIntentId'] ?? '')\n if (!paymentIntentId) throw new ReturnRefusal(409, 'That card payment has nothing Stripe can refund.')\n const refund = await createStripeRefund({\n paymentIntentId,\n amountCents: allocation.amountCents,\n idempotencyKey: claim.stripeKey ? `${claim.stripeKey}:${allocation.paymentId}` : null,\n metadata: { hostId: staff.hostId, orderId, registerId, kind: 'pos-return' },\n fetch: deps.fetch,\n })\n if ('error' in refund) throw new ReturnRefusal(refund.status, refund.error)\n results.push({ allocation, status: 'refunded', refundId: refund.refundId })\n } else if (allocation.method === 'gift_card') {\n await creditGiftCard(firestore, staff.hostRef, tender?.giftCardId ?? '', allocation.amountCents, orderId, deps.now())\n results.push({ allocation, status: 'refunded' })\n } else if (allocation.method === 'folio') {\n await reverseFolio(staff.hostRef, tender?.reservationId ?? String(order['reservationId'] ?? ''), allocation.amountCents, orderId, deps.now())\n results.push({ allocation, status: 'refunded' })\n } else if (allocation.method === 'credit') {\n await restorePluginCredit(\n staff.hostRef.id,\n tender,\n allocation.amountCents,\n orderId,\n `pos-return:${orderId}:${allocation.paymentId}:${reserved.prior.posPaymentRefunds[allocation.paymentId] ?? 0}`,\n )\n results.push({ allocation, status: 'refunded' })\n } else {\n // Cash: recorded on the drawer with the return itself, below.\n results.push({ allocation, status: 'refunded' })\n }\n } catch (error) {\n const message = error instanceof ReturnRefusal ? error.message : 'Refund failed'\n if (!(error instanceof ReturnRefusal)) console.error('[pos-return] tender failed', allocation, error)\n if (!anyMoved) {\n // Nothing has moved: hand the whole reservation back and let the\n // same attempt be tried again.\n await firestore\n .runTransaction(async (transaction) => {\n await transaction.get(orderRef)\n transaction.update(orderRef, reserved.prior)\n })\n .catch((rollback) => console.error('[pos-return] rollback failed', orderId, rollback))\n await claim.release()\n return {\n status: error instanceof ReturnRefusal ? error.status : 502,\n body: { error: message },\n }\n }\n results.push({ allocation, status: 'failed', error: message })\n }\n }\n\n const failed = results.filter((result) => result.status === 'failed')\n const refundedCents = results\n .filter((result) => result.status === 'refunded')\n .reduce((sum, result) => sum + result.allocation.amountCents, 0)\n const cashCents = results\n .filter((result) => result.status === 'refunded' && result.allocation.method === 'cash')\n .reduce((sum, result) => sum + result.allocation.amountCents, 0)\n const now = deps.now()\n // One id names the return under the register (its tenders and shift) and\n // in the store's returns list beside the online ones (AGL-3611).\n const returnId = createResourceUid()\n const returnRef = register.ref.collection('returns').doc(returnId)\n const storeReturnRef = staff.hostRef.collection('returns').doc(returnId)\n const orderLabel = CommerceModel.formatOrderNumber(order as any, orderId)\n const lines = picks.map((pick, at) => ({\n index: pick.index,\n quantity: pick.quantity,\n name: String(order.lineItems?.[pick.index]?.name ?? ''),\n refundCents: reserved.lineCents[at] ?? 0,\n }))\n\n // The record, the drawer, the order: one transaction.\n let closedTheOrder = false\n let fullyRefunded = false\n let shiftIdForReturn: string | null = null\n let storeReturn: CommerceModel.HostReturn | null = null\n await firestore.runTransaction(async (transaction) => {\n const freshRegister = await transaction.get(register.ref)\n const shiftId = String(freshRegister.get('openShiftId') ?? '') || null\n const shiftRef = shiftId ? register.ref.collection('shifts').doc(shiftId) : null\n const shiftSnapshot = shiftRef ? await transaction.get(shiftRef) : null\n const fresh = CommerceModel.liftLegacyOrder(\n ((await transaction.get(orderRef)).data() ?? {}) as any,\n ) as unknown as PosReturnSource & Record<string, any>\n const shiftOpen = Boolean(shiftSnapshot?.exists && shiftSnapshot.get('status') === 'open')\n shiftIdForReturn = shiftOpen ? shiftId : null\n\n // Hand back what a failed card did not refund.\n const failedCents = failed.reduce((sum, result) => sum + result.allocation.amountCents, 0)\n const posPaymentRefunds = { ...(fresh.posPaymentRefunds ?? {}) }\n for (const result of failed) {\n posPaymentRefunds[result.allocation.paymentId] = Math.max(\n 0,\n (posPaymentRefunds[result.allocation.paymentId] ?? 0) - result.allocation.amountCents,\n )\n }\n const orderRefunded = Math.max(0, Number(fresh.refundedCents ?? 0) - failedCents)\n const totalCents = Number(fresh.totals?.totalCents ?? fresh.amountCents ?? 0)\n fullyRefunded = orderRefunded >= totalCents && totalCents > 0\n closedTheOrder =\n fullyRefunded &&\n fresh['status'] !== 'refunded' &&\n CommerceModel.canTransitionOrder(fresh['status'] as CommerceModel.OrderStatus, 'refunded')\n const completedLines = Object.entries(fresh.returnedQuantities ?? {})\n .filter(([index, count]) => count >= Math.max(1, Number(fresh.lineItems?.[Number(index)]?.quantity ?? 1)))\n .map(([index]) => Number(index))\n const tenderWords = results\n .map(\n (result) =>\n `${posMoney(result.allocation.amountCents)} to ${posTenderLabel(\n tenderOf(result.allocation.paymentId) ?? { method: result.allocation.method },\n )}${result.status === 'failed' ? ' (FAILED)' : ''}`,\n )\n .join(', ')\n const units = picks.reduce((sum, pick) => sum + pick.quantity, 0)\n transaction.update(orderRef, {\n refundedCents: orderRefunded,\n posPaymentRefunds,\n ...(closedTheOrder ? { status: 'refunded' } : {}),\n ...(completedLines.length\n ? {\n refundedLineItemIds: [\n ...new Set([...(fresh.refundedLineItemIds ?? []), ...completedLines]),\n ].sort((a, b) => a - b),\n }\n : {}),\n timeline: CommerceModel.appendOrderEvent(\n fresh as any,\n 'refund',\n `Returned at the register: ${units} ${units === 1 ? 'item' : 'items'}, ${tenderWords}` +\n (restock ? '; restocked' : '') +\n (authority.approvedBy ? '; approved by a manager' : ''),\n now,\n ),\n })\n const record: PosRegisterReturn = {\n hostId: staff.hostId,\n registerId,\n orderId,\n ...(typeof order['number'] === 'number' ? { orderNumber: order['number'] } : {}),\n ...(shiftOpen && shiftId ? { shiftId } : {}),\n lines,\n refundedCents,\n tenders: results.map((result) => ({\n ...result.allocation,\n status: result.status,\n ...(result.refundId ? { refundId: result.refundId } : {}),\n ...(result.error ? { error: result.error } : {}),\n })),\n restocked: restock,\n ...(register.data['locationId'] ? { locationId: String(register.data['locationId']) } : {}),\n cashierId: cashier.cashierId,\n ...(authority.approvedBy ? { approvedBy: authority.approvedBy } : {}),\n ...(reason ? { reason } : {}),\n status: failed.length ? 'partial' : 'refunded',\n atMs: now,\n }\n transaction.create(returnRef, record)\n const restockedLines = picks.map((pick) => ({ lineItemId: pick.index, quantity: pick.quantity }))\n const registerLocationId = register.data['locationId'] ? String(register.data['locationId']) : undefined\n storeReturn = {\n orderId,\n orderNumber: orderLabel,\n customerEmail: (order['customerEmail'] as string | undefined) ?? null,\n customerName: (order['customerName'] as string | undefined) ?? null,\n lines: picks.map((pick) => ({ lineItemId: pick.index, quantity: pick.quantity, reason: reasonCode })),\n status: 'refunded',\n requestedBy: 'merchant',\n source: 'register',\n registerId,\n ...(reason ? { merchantNote: reason } : {}),\n ...(restock\n ? {\n restock: {\n lines: restockedLines,\n ...(registerLocationId ? { locationId: registerLocationId } : {}),\n atMs: now,\n },\n }\n : {}),\n refundedAtMs: now,\n refundCents: refundedCents,\n timeline: [\n {\n atMs: now,\n event: 'refunded',\n detail: `At the register${failed.length ? `; ${posMoney(failed.reduce((sum, result) => sum + result.allocation.amountCents, 0))} still owed` : ''}`,\n },\n ],\n createdAtMs: now,\n updatedAtMs: now,\n }\n transaction.create(storeReturnRef, storeReturn)\n if (shiftOpen && shiftRef && cashCents > 0) {\n const event: PosCashEvent = {\n id: returnRef.id,\n type: 'refund',\n amountCents: cashCents,\n reason: `Return ${orderLabel}`,\n by: cashier.cashierId,\n atMs: now,\n orderId,\n }\n const cashEvents = Array.isArray(shiftSnapshot?.get('cashEvents')) ? shiftSnapshot!.get('cashEvents') : []\n transaction.update(shiftRef, { cashEvents: [...cashEvents, event] })\n }\n })\n\n // Restock what came back to the register's location.\n let restockedUnits = 0\n if (restock) {\n restockedUnits = await restockReturn(\n firestore,\n staff.hostRef,\n order,\n picks,\n String(register.data['locationId'] ?? order['locationId'] ?? '') || undefined,\n orderId,\n now,\n ).catch((error) => {\n console.error('[pos-return] restock failed', orderId, error)\n return 0\n })\n }\n\n // The drawer opens for the cash being handed back.\n if (cashCents > 0) {\n await deps.printer.kickDrawer({\n hostId: staff.hostId,\n registerId,\n reason: 'cash_refund',\n causeId: returnRef.id,\n createdBy: cashier.cashierId,\n })\n }\n\n const payload = {\n returnId: returnRef.id,\n refundedCents,\n outstandingCents: failed.reduce((sum, result) => sum + result.allocation.amountCents, 0),\n partial: failed.length > 0,\n tenders: results.map((result) => ({\n method: result.allocation.method,\n label: posTenderLabel(tenderOf(result.allocation.paymentId) ?? { method: result.allocation.method }),\n amountCents: result.allocation.amountCents,\n status: result.status,\n ...(result.error ? { error: result.error } : {}),\n })),\n cashOutCents: cashCents,\n restockedUnits,\n shiftId: shiftIdForReturn,\n fullyRefunded,\n }\n await claim.record(200, payload)\n if (refundedCents > 0) {\n await deps.afterRefund({\n hostId: staff.hostId,\n orderId,\n email: order['customerEmail'] ?? null,\n refundCents: refundedCents,\n closedTheOrder,\n fullyRefunded,\n returnedProductIds: [\n ...new Set(\n picks\n .map((pick) => String((order.lineItems?.[pick.index] as { productId?: string } | undefined)?.productId ?? ''))\n .filter(Boolean),\n ),\n ],\n lineIndexes: picks.map((pick) => pick.index),\n fullLineIndexes: reserved.completedLines,\n returnId,\n storeReturn: storeReturn as unknown as CommerceModel.HostReturn,\n refundIds: results.flatMap((result) => (result.refundId ? [result.refundId] : [])),\n })\n }\n return { status: 200, body: payload }\n}\n\n/**\n * Units per order line that the store's OTHER returns — the online returns\n * flow (AGL-3611) — hold or already took back. The register's own returns are\n * left out: `returnedQuantities` on the order already counts them.\n */\nexport function unitsHeldByOnlineReturns(\n docs: ReadonlyArray<{ data(): FirebaseFirestore.DocumentData | undefined }>,\n): number[] {\n const held: number[] = []\n for (const doc of docs) {\n const entry = (doc.data() ?? {}) as CommerceModel.HostReturn\n if (entry.source === 'register' || !CommerceModel.returnHoldsUnits(entry)) continue\n for (const line of entry.lines ?? []) {\n const index = Number(line?.lineItemId)\n if (!Number.isInteger(index) || index < 0) continue\n held[index] = (held[index] ?? 0) + Math.max(0, Math.floor(Number(line?.quantity) || 0))\n }\n }\n return held\n}\n\n/** Whether a member is a workspace admin and this site's admin, asked now. */\nasync function memberIsPosManager(\n deps: PosOpsDeps,\n hostRef: FirebaseFirestore.DocumentReference,\n hostId: string,\n uid: string,\n): Promise<boolean> {\n const host = await hostRef.get()\n const role = (host.get('memberRoles') ?? {})[uid]\n return isPosManager(role, await deps.membership(uid, hostId))\n}\n\nclass ReturnRefusal extends Error {\n constructor(\n readonly status: number,\n message: string,\n ) {\n super(message)\n }\n}\n\n/**\n * Store credit back on the card it came off. A voided or frozen card takes\n * nothing: a void is a fraud or refund decision, and re-crediting it would\n * undo that decision by the back door.\n */\nasync function creditGiftCard(\n firestore: FirebaseFirestore.Firestore,\n hostRef: FirebaseFirestore.DocumentReference,\n code: string,\n amountCents: number,\n orderId: string,\n now: number,\n): Promise<void> {\n const id = String(code ?? '').trim()\n if (!id || id.includes('/') || id.length > 64) throw new ReturnRefusal(409, 'That gift card payment does not name its card.')\n const ref = hostRef.collection('giftCards').doc(id)\n await firestore.runTransaction(async (transaction) => {\n const card = await transaction.get(ref)\n if (!card.exists) throw new ReturnRefusal(409, 'That gift card no longer exists.')\n if (card.get('voidedAtMs') != null || card.get('frozenAtMs') != null) {\n throw new ReturnRefusal(409, 'That gift card is voided or frozen, so it cannot take a refund.')\n }\n transaction.update(ref, {\n balanceCents: Math.max(0, Math.round(Number(card.get('balanceCents') ?? 0))) + amountCents,\n lastCreditAtMs: now,\n lastCreditOrderId: orderId,\n })\n })\n}\n\n/**\n * Store credit back to the plugin that keeps it (AGL-3640): a rewards\n * balance gets back what this payment took. Idempotent per `key`, so a\n * retried return gives back once. A friend's referral credit was a discount,\n * not a balance, and its provider gives nothing back — correctly: nobody is\n * owed money for it.\n */\nasync function restorePluginCredit(\n hostId: string,\n tender: { creditProviderId?: string; creditReference?: string } | undefined,\n amountCents: number,\n orderId: string,\n key: string,\n): Promise<void> {\n const entry = tender?.creditProviderId ? checkoutCreditProvider(tender.creditProviderId) : null\n if (!entry || !tender?.creditReference) {\n throw new ReturnRefusal(409, 'The store credit on this sale cannot take a refund right now.')\n }\n await entry.provider.restore({ hostId, reference: tender.creditReference, orderId, cents: amountCents, key })\n}\n\n/** A room charge taken back: a negative line on the same stay's folio. */\nasync function reverseFolio(\n hostRef: FirebaseFirestore.DocumentReference,\n reservationId: string,\n amountCents: number,\n orderId: string,\n now: number,\n): Promise<void> {\n const id = posOpsCleanId(reservationId)\n if (!id) throw new ReturnRefusal(409, 'That room charge does not name its stay.')\n const ref = hostRef.collection('reservations').doc(id)\n const firestore = hostRef.firestore\n await firestore.runTransaction(async (transaction) => {\n const stay = await transaction.get(ref)\n if (!stay.exists) throw new ReturnRefusal(409, 'That stay no longer exists.')\n const folio = Array.isArray(stay.get('folio')) ? stay.get('folio') : []\n transaction.update(ref, {\n folio: [...folio, { orderId, amountCents: -amountCents, note: 'Return at the register', atMs: now }],\n })\n })\n}\n\n/**\n * The returned units back on the shelf, at the register's location, with an\n * adjustment row each so the stock history says why the count went up.\n * Only variants that track stock move.\n */\nasync function restockReturn(\n firestore: FirebaseFirestore.Firestore,\n hostRef: FirebaseFirestore.DocumentReference,\n order: PosReturnSource & Record<string, any>,\n picks: readonly PosReturnPick[],\n locationId: string | undefined,\n orderId: string,\n now: number,\n): Promise<number> {\n const byProduct = new Map<string, Array<{ variantId?: string; quantity: number }>>()\n for (const pick of picks) {\n const line = (order.lineItems ?? [])[pick.index] as Record<string, any> | undefined\n const productId = String(line?.['productId'] ?? '')\n if (!productId) continue\n byProduct.set(productId, [\n ...(byProduct.get(productId) ?? []),\n { ...(line?.['variantId'] ? { variantId: String(line['variantId']) } : {}), quantity: pick.quantity },\n ])\n }\n let units = 0\n for (const [productId, lines] of byProduct) {\n const ref = hostRef.collection('products').doc(productId)\n units += await firestore.runTransaction(async (transaction) => {\n const snapshot = await transaction.get(ref)\n if (!snapshot.exists) return 0\n const product = CommerceModel.liftLegacyProduct(snapshot.data() as any)\n let variants = product.variants\n const rows: Array<{ variantId: string; quantity: number }> = []\n for (const line of lines) {\n const variantId = line.variantId ?? product.variants[0]?.id\n const variant = variants.find((candidate) => candidate.id === variantId)\n if (!variantId || !variant || variant.inventory == null) continue\n variants = CommerceModel.adjustVariantInventory({ variants }, variantId, line.quantity, locationId)\n rows.push({ variantId, quantity: line.quantity })\n }\n if (!rows.length) return 0\n transaction.update(ref, {\n variants,\n ...CommerceModel.productStockFields({ ...product, variants }),\n updatedAtMs: now,\n })\n for (const row of rows) {\n transaction.create(hostRef.collection('inventoryAdjustments').doc(createResourceUid()), {\n productId,\n variantId: row.variantId,\n delta: row.quantity,\n reason: 'refund',\n orderId,\n ...(locationId ? { locationId } : {}),\n atMs: now,\n } satisfies CommerceModel.InventoryAdjustment)\n }\n return rows.reduce((sum, row) => sum + row.quantity, 0)\n })\n }\n return units\n}\n\nexport function createPosReturnHandler(\n deps: () => PosReturnDeps = defaultPosReturnDeps,\n): PluginApiHandler {\n return async (req, res) => {\n try {\n const outcome = await handlePosReturn(deps(), req)\n return res.status(outcome.status).json(outcome.body)\n } catch (error) {\n console.error('[pos-return] failed', error)\n return res.status(500).json({ error: 'The return could not be refunded' })\n }\n }\n}\n\nexport const posReturnHandler = createPosReturnHandler()\n"],"names":["claimAttempt","createResourceUid","nameSearchKey","recordPluginPersonRefund","reverseOrderConversion","checkoutCreditProvider","CommerceModel","planPosReturn","posMoney","posRefundableByTender","posReturnedQuantities","posReturnLineValues","posTenderLabel","POS_STRIPE_TENDERS","splitPosRefund","ORDER_REFUNDED_EVENT","RETURN_REFUNDED_EVENT","raiseOrderEvent","applyGiftCardRiskToOrder","notifyOrderBuyer","decidePosRefundAuthority","authorizePosOps","defaultPosOpsDeps","posOpsBody","posOpsCleanId","posOpsIdempotencyKey","readPosRegister","isPosManager","resolvePosCashier","createStripeRefund","defaultPosReturnDeps","base","afterRefund","input","settle","label","work","error","console","orderId","hostRef","firestore","collection","doc","hostId","returnedProductIds","length","action","kind","reason","fullyRefunded","productIds","refId","email","amountCents","refundCents","closedTheSale","closedTheOrder","key","returnId","extra","refund","id","refundIds","lineItemIds","fullLineIndexes","full","return","status","storeReturn","lines","map","line","refundId","refundLineIndexes","lineIndexes","RETURNABLE","Set","returnSummary","raw","held","order","liftLegacyOrder","values","returned","number","formatOrderNumber","channel","createdAtMs","Number","customerEmail","customerName","totalCents","totals","refundedCents","returnable","has","String","lineItems","index","name","variantLabel","quantity","Math","max","round","valueCents","tenders","tender","method","refundableCents","findOrders","rawText","snapshot","text","trim","slice","orders","digits","replace","test","where","limit","get","docs","data","includes","orderBy","exists","parsePicks","Array","isArray","entry","parseSplit","paymentId","handlePosReturn","deps","req","body","register","gate","staff","found","Promise","all","unitsHeldByOnlineReturns","at","registerId","ref","idempotencyKey","picks","requestedSplit","restock","reasonCode","RETURN_REASONS","orderRef","storeReturns","orderDisputeBlocksRefund","plan","split","cashier","cashierIsManager","cashierId","uid","isManager","memberIsPosManager","authority","limitCents","settings","refundLimitCents","managerAssertion","needsCash","allocations","some","needsStripe","openShiftId","requireOpenShift","process","env","STRIPE_SECRET_KEY","claimed","scopeId","orgId","busyMessage","replay","claim","reserved","runTransaction","transaction","fresh","ReturnRefusal","freshPlan","freshSplit","prior","returnedQuantities","posPaymentRefunds","update","lineCents","completedLines","release","message","tenderOf","find","ordered","sort","a","b","results","allocation","anyMoved","result","paymentIntentId","stripeKey","metadata","fetch","push","creditGiftCard","giftCardId","now","reverseFolio","reservationId","restorePluginCredit","catch","rollback","failed","filter","reduce","sum","cashCents","returnRef","storeReturnRef","orderLabel","pick","shiftIdForReturn","freshRegister","shiftId","shiftRef","shiftSnapshot","shiftOpen","Boolean","failedCents","orderRefunded","canTransitionOrder","Object","entries","count","tenderWords","join","units","refundedLineItemIds","timeline","appendOrderEvent","approvedBy","record","orderNumber","restocked","locationId","atMs","create","restockedLines","lineItemId","registerLocationId","undefined","requestedBy","source","merchantNote","refundedAtMs","event","detail","updatedAtMs","type","by","cashEvents","restockedUnits","restockReturn","printer","kickDrawer","causeId","createdBy","payload","outstandingCents","partial","cashOutCents","productId","flatMap","returnHoldsUnits","isInteger","floor","host","role","membership","Error","code","card","balanceCents","lastCreditAtMs","lastCreditOrderId","creditProviderId","creditReference","provider","restore","reference","cents","stay","folio","note","byProduct","Map","set","variantId","product","liftLegacyProduct","variants","rows","variant","candidate","inventory","adjustVariantInventory","productStockFields","row","delta","createPosReturnHandler","res","outcome","json","posReturnHandler"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/pos-return.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 { claimAttempt, type PluginApiHandler, type PluginApiRequest } from '@aglyn/aglyn/server'\nimport { createResourceUid } from '@aglyn/aglyn/app-utils/create-resource-uid'\nimport { nameSearchKey } from '@aglyn/aglyn/app-utils/name-search'\nimport { recordPluginPersonRefund } from '@aglyn/aglyn/plugin-manager/plugin-person-records'\nimport { reverseOrderConversion } from '@aglyn/aglyn/plugin-manager/plugin-conversion-credit'\nimport { checkoutCreditProvider } from '@aglyn/aglyn/plugin-manager/plugin-checkout-credits'\nimport * as CommerceModel from '../model'\nimport {\n planPosReturn,\n posMoney,\n posRefundableByTender,\n posReturnedQuantities,\n posReturnLineValues,\n posTenderLabel,\n POS_STRIPE_TENDERS,\n splitPosRefund,\n type PosCashEvent,\n type PosRefundAllocation,\n type PosRegisterReturn,\n type PosReturnPick,\n type PosReturnSource,\n} from '../model/commerce-pos-ops'\nimport { ORDER_REFUNDED_EVENT, RETURN_REFUNDED_EVENT } from '../model/order-events'\nimport { raiseOrderEvent } from './order-events'\nimport { applyGiftCardRiskToOrder } from './gift-card-risk'\nimport { notifyOrderBuyer } from './order-notifications'\nimport { decidePosRefundAuthority } from './pos-refund-authority'\nimport {\n authorizePosOps,\n defaultPosOpsDeps,\n posOpsBody,\n posOpsCleanId,\n posOpsIdempotencyKey,\n readPosRegister,\n isPosManager,\n resolvePosCashier,\n type PosOpsDeps,\n} from './pos-ops-gate'\nimport { createStripeRefund } from './stripe-refund'\nimport { parsePosHardwareInPersonConfig } from '../model/pos-hardware'\n\n/*==========================================\n * RETURNS AT THE REGISTER (AGL-3609): `POST /api/commerce/pos-return`.\n *\n * find an order by its number (typed or scanned off the receipt's\n * barcode), its id, or the customer's email\n * refund picked lines and quantities back, restocked to the register's\n * location, the money sent back to the sale's OWN payments\n *\n * Each payment gets its money back the way it came: a card through Stripe\n * (the same refund the order dialog sends), cash out of the drawer — a cash\n * event on the open shift, so the count still balances — a gift card\n * re-credited, and a room charge reversed on the stay's folio.\n *\n * THE ORDER OF WORK is what keeps a failure honest:\n * 1. every refusal that needs no money to move (role, limit, quantities,\n * the split, the shift rule) — before anything is written;\n * 2. the attempt claim, so a retried tap replays instead of refunding twice;\n * 3. the RESERVATION on the order, in a transaction that re-reads it: the\n * cents, the units and each payment's share are taken before any money\n * moves, so two registers returning the same line cannot both succeed;\n * 4. the Stripe refunds first, because they are the ones that can say no —\n * if the first one does, nothing has moved and the reservation is\n * handed back whole;\n * 5. then the tenders that cannot fail for a reason outside this database.\n * A card that fails after another payment already went back leaves a\n * PARTIAL return: what moved is recorded, what did not is handed back on\n * the order, and the cashier is told the amount still owed.\n *=========================================*/\n\nexport interface PosReturnSideEffects {\n hostId: string\n orderId: string\n /** The return's id, the same under the register and in the store's returns. */\n returnId: string\n /** The return as the store's returns list holds it, for the return event. */\n storeReturn: CommerceModel.HostReturn\n /** The Stripe refunds the return made, if any, for the refund event. */\n refundIds: string[]\n email: string | null | undefined\n refundCents: number\n closedTheOrder: boolean\n returnedProductIds: string[]\n fullyRefunded: boolean\n lineIndexes: number[]\n /** The lines this return finished taking back in full. */\n fullLineIndexes: number[]\n /**\n * Each line taken back, with its units and its share of the refund, for\n * whatever follows a line in particular — a card reader sold in person,\n * whose hardware order is told (AGL-4038).\n */\n lines?: Array<{ index: number; quantity: number; refundCents: number }>\n}\n\nexport interface PosReturnDeps extends PosOpsDeps {\n /** What every refund tells the rest of the workspace, after the money moved. Never throws. */\n afterRefund(input: PosReturnSideEffects): Promise<void>\n}\n\nexport function defaultPosReturnDeps(): PosReturnDeps {\n const base = defaultPosOpsDeps()\n return {\n ...base,\n afterRefund: async (input) => {\n const settle = async (label: string, work: () => Promise<unknown>) => {\n try {\n await work()\n } catch (error) {\n console.error(`[pos-return] ${label} failed`, input.orderId, error)\n }\n }\n const hostRef = base.firestore().collection('hosts').doc(input.hostId)\n if (input.returnedProductIds.length) {\n await settle('gift card void', () =>\n applyGiftCardRiskToOrder({\n firestore: base.firestore(),\n hostRef,\n orderId: input.orderId,\n action: {\n kind: 'void',\n reason: 'refund',\n ...(input.fullyRefunded ? {} : { productIds: input.returnedProductIds }),\n },\n }),\n )\n }\n await settle('person refund', () =>\n recordPluginPersonRefund({\n hostId: input.hostId,\n refId: input.orderId,\n email: input.email,\n amountCents: input.refundCents,\n closedTheSale: input.closedTheOrder,\n }),\n )\n await settle('conversion reversal', () =>\n reverseOrderConversion({\n hostId: input.hostId,\n orderId: input.orderId,\n amountCents: input.refundCents,\n closedTheOrder: input.closedTheOrder,\n }),\n )\n // The same events a refund from the order dialog and a refunded online\n // return raise, so accounting and the merchant's webhooks hear a\n // register return too (AGL-3611's events).\n await settle('refund event', () =>\n raiseOrderEvent(ORDER_REFUNDED_EVENT, {\n hostId: input.hostId,\n orderId: input.orderId,\n key: `pos-return:${input.returnId}`,\n extra: {\n refund: {\n id: input.refundIds[0] ?? null,\n amountCents: input.refundCents,\n lineItemIds: input.fullLineIndexes,\n full: input.fullyRefunded,\n },\n },\n }),\n )\n await settle('return event', () =>\n raiseOrderEvent(RETURN_REFUNDED_EVENT, {\n hostId: input.hostId,\n orderId: input.orderId,\n key: `return-refunded:${input.returnId}`,\n extra: {\n return: {\n id: input.returnId,\n status: input.storeReturn.status,\n lines: input.storeReturn.lines.map((line) => ({ ...line })),\n refundCents: input.storeReturn.refundCents ?? null,\n },\n },\n }),\n )\n // A card reader the platform's own store sold in person (AGL-4038):\n // its hardware order and retained sale record take the return too.\n // Answered from the environment for every other store.\n if (input.lines?.length && parsePosHardwareInPersonConfig(process.env)?.sellerHostId === input.hostId) {\n await settle('hardware return', async () =>\n (await import('./pos-hardware-returns')).recordRegisterHardwareReturn({\n config: parsePosHardwareInPersonConfig(process.env),\n hostId: input.hostId,\n registerOrderId: input.orderId,\n returnId: input.returnId,\n refundCents: input.refundCents,\n lines: input.lines ?? [],\n }),\n )\n }\n await settle('buyer notice', () =>\n notifyOrderBuyer({ hostId: input.hostId, orderId: input.orderId }, 'refunded', {\n refundId: '',\n refundCents: input.refundCents,\n refundLineIndexes: input.lineIndexes,\n fullyRefunded: input.fullyRefunded,\n }),\n )\n },\n }\n}\n\ntype Outcome = { status: number; body: Record<string, unknown> }\n\n/** The statuses a return may be taken against. */\nconst RETURNABLE: ReadonlySet<string> = new Set([\n 'paid',\n 'partially_fulfilled',\n 'fulfilled',\n 'delivered',\n])\n\n/** One order as the return dialog lists it. */\nfunction returnSummary(id: string, raw: Record<string, any>, held: readonly number[] = []) {\n const order = CommerceModel.liftLegacyOrder(raw as any) as unknown as PosReturnSource &\n Record<string, any>\n const values = posReturnLineValues(order)\n const returned = posReturnedQuantities(order)\n return {\n id,\n number: order['number'] ?? null,\n label: CommerceModel.formatOrderNumber(order as any, id),\n status: order['status'],\n channel: order['channel'] ?? 'online',\n createdAtMs: Number(order['createdAtMs'] ?? 0),\n customerEmail: order['customerEmail'] ?? null,\n customerName: order['customerName'] ?? null,\n totalCents: Number(order.totals?.totalCents ?? order.amountCents ?? 0),\n refundedCents: Number(order.refundedCents ?? 0),\n returnable: RETURNABLE.has(String(order['status'])),\n lines: (order.lineItems ?? []).map((line: any, index: number) => ({\n index,\n name: String(line?.name ?? ''),\n variantLabel: line?.variantLabel ?? null,\n quantity: Math.max(1, Math.round(Number(line?.quantity ?? 1))),\n returned: returned[index] ?? 0,\n // Units an online return holds or already took (AGL-3611).\n held: held[index] ?? 0,\n valueCents: values[index] ?? 0,\n })),\n tenders: posRefundableByTender(order).map((tender) => ({\n id: tender.id,\n method: tender.method,\n label: posTenderLabel(tender),\n amountCents: tender.amountCents,\n refundableCents: tender.refundableCents,\n })),\n }\n}\n\nasync function findOrders(\n hostRef: FirebaseFirestore.DocumentReference,\n rawText: unknown,\n): Promise<Array<{ id: string; data: Record<string, any> }>> {\n const text = String(rawText ?? '').trim().slice(0, 200)\n if (!text) return []\n const orders = hostRef.collection('orders')\n const digits = text.replace(/^#/, '')\n if (/^\\d{1,12}$/.test(digits)) {\n const snapshot = await orders.where('number', '==', Number(digits)).limit(5).get()\n return snapshot.docs.map((doc) => ({ id: doc.id, data: (doc.data() ?? {}) as Record<string, any> }))\n }\n if (text.includes('@')) {\n const snapshot = await orders\n .where('customerEmailLower', '==', nameSearchKey(text))\n .orderBy('createdAtMs', 'desc')\n .limit(10)\n .get()\n return snapshot.docs.map((doc) => ({ id: doc.id, data: (doc.data() ?? {}) as Record<string, any> }))\n }\n const id = posOpsCleanId(text)\n if (!id) return []\n const snapshot = await orders.doc(id).get()\n return snapshot.exists ? [{ id, data: (snapshot.data() ?? {}) as Record<string, any> }] : []\n}\n\nfunction parsePicks(raw: unknown): PosReturnPick[] {\n if (!Array.isArray(raw)) return []\n return raw.slice(0, 200).map((entry: any) => ({\n index: Number(entry?.index),\n quantity: Number(entry?.quantity),\n }))\n}\n\nfunction parseSplit(raw: unknown): Array<{ paymentId: string; amountCents: number }> | null {\n if (!Array.isArray(raw) || !raw.length) return null\n return raw.slice(0, 20).map((entry: any) => ({\n paymentId: String(entry?.paymentId ?? ''),\n amountCents: Number(entry?.amountCents),\n }))\n}\n\n/** What a refunded tender moved, and how to hand back a reservation it did not. */\ninterface TenderResult {\n allocation: PosRefundAllocation\n status: 'refunded' | 'failed'\n refundId?: string\n error?: string\n}\n\nexport async function handlePosReturn(deps: PosReturnDeps, req: PluginApiRequest): Promise<Outcome> {\n if (req.method !== 'POST') return { status: 405, body: { error: 'Method not allowed' } }\n const body = posOpsBody(req)\n // Finding a sale to take back and refunding it are both the refund key's\n // (AGL-4047).\n const gate = await authorizePosOps(deps, req, body['hostId'], 'posRefund')\n if ('error' in gate) return { status: gate.status, body: { error: gate.error } }\n const staff = gate.staff\n const action = String(body['action'] ?? '')\n\n if (action === 'find') {\n const found = await findOrders(staff.hostRef, body['text'])\n const held = await Promise.all(\n found.map(async (entry) =>\n unitsHeldByOnlineReturns(\n (await staff.hostRef.collection('returns').where('orderId', '==', entry.id).get()).docs,\n ),\n ),\n )\n return {\n status: 200,\n body: { orders: found.map((entry, at) => returnSummary(entry.id, entry.data, held[at])) },\n }\n }\n if (action !== 'refund') return { status: 400, body: { error: 'Unknown action' } }\n\n const register = await readPosRegister(staff, body['registerId'])\n if ('error' in register) return { status: register.status, body: { error: register.error } }\n const registerId = register.ref.id\n const orderId = posOpsCleanId(body['orderId'])\n if (!orderId) return { status: 400, body: { error: 'Missing orderId' } }\n const idempotencyKey = posOpsIdempotencyKey(req)\n if (!idempotencyKey) {\n return { status: 400, body: { error: 'A refund needs an Idempotency-Key header.' } }\n }\n const picks = parsePicks(body['lines'])\n const requestedSplit = parseSplit(body['tenders'])\n const restock = body['restock'] !== false\n const reason = String(body['reason'] ?? '').trim().slice(0, 200)\n const reasonCode: CommerceModel.ReturnReason = CommerceModel.RETURN_REASONS.includes(\n body['reasonCode'] as CommerceModel.ReturnReason,\n )\n ? (body['reasonCode'] as CommerceModel.ReturnReason)\n : 'other'\n const firestore = deps.firestore()\n const orderRef = staff.hostRef.collection('orders').doc(orderId)\n const storeReturns = staff.hostRef.collection('returns').where('orderId', '==', orderId)\n\n // 1. Every refusal that needs no money to move.\n const snapshot = await orderRef.get()\n if (!snapshot.exists) return { status: 404, body: { error: 'Unknown order' } }\n const order = CommerceModel.liftLegacyOrder(snapshot.data() as any) as unknown as PosReturnSource &\n Record<string, any>\n if (!RETURNABLE.has(String(order['status']))) {\n return { status: 409, body: { error: `Orders in \"${order['status']}\" cannot be returned.` } }\n }\n if (CommerceModel.orderDisputeBlocksRefund(order as any)) {\n return {\n status: 409,\n body: {\n error:\n 'A chargeback is open on this order, so it was not refunded. Respond to the ' +\n 'dispute or accept it in the Stripe dashboard first.',\n },\n }\n }\n const plan = planPosReturn(order, picks, unitsHeldByOnlineReturns((await storeReturns.get()).docs))\n if ('error' in plan) return { status: 400, body: { error: plan.error } }\n const split = splitPosRefund(order, plan.refundCents, requestedSplit)\n if ('error' in split) return { status: 400, body: { error: split.error } }\n\n const cashier = await resolvePosCashier(deps, staff, registerId, body['cashierAssertion'])\n // The limit is the person at the till's: a PIN-switched cashier is held\n // to it even on a device a workspace admin signed in on.\n const cashierIsManager =\n cashier.cashierId === staff.uid\n ? staff.isManager\n : await memberIsPosManager(deps, staff.hostRef, staff.hostId, cashier.cashierId)\n const authority = await decidePosRefundAuthority(deps, {\n hostId: staff.hostId,\n hostRef: staff.hostRef,\n registerId,\n refundCents: plan.refundCents,\n limitCents: staff.settings.refundLimitCents,\n isManager: cashierIsManager,\n managerAssertion: body['managerAssertion'],\n })\n if ('body' in authority) return { status: 403, body: authority.body }\n\n const needsCash = split.allocations.some((slice) => slice.method === 'cash')\n const needsStripe = split.allocations.some((slice) => POS_STRIPE_TENDERS.has(slice.method))\n const openShiftId = String(register.data['openShiftId'] ?? '') || null\n if (needsCash && !openShiftId && staff.settings.requireOpenShift) {\n return { status: 409, body: { error: 'Open a shift before paying cash out of the drawer.' } }\n }\n if (needsStripe && !process.env.STRIPE_SECRET_KEY) {\n return { status: 501, body: { error: 'Payments are not configured.' } }\n }\n\n // 2. The attempt claim.\n const claimed = await claimAttempt(firestore as any, {\n kind: 'pos-return',\n scopeId: staff.hostId,\n orgId: staff.orgId,\n key: `${orderId}:${idempotencyKey}`,\n busyMessage: 'This return is already being refunded',\n })\n if ('replay' in claimed) return { status: claimed.replay.status, body: claimed.replay.body as any }\n const claim = claimed.claim\n\n // 3. The reservation, re-read under the transaction.\n type Reserved = {\n refundCents: number\n lineCents: number[]\n completedLines: number[]\n allocations: PosRefundAllocation[]\n prior: { refundedCents: number; returnedQuantities: Record<string, number>; posPaymentRefunds: Record<string, number> }\n }\n let reserved: Reserved\n try {\n reserved = await firestore.runTransaction(async (transaction) => {\n const fresh = CommerceModel.liftLegacyOrder(\n ((await transaction.get(orderRef)).data() ?? {}) as any,\n ) as unknown as PosReturnSource & Record<string, any>\n if (!RETURNABLE.has(String(fresh['status']))) {\n throw new ReturnRefusal(409, `Orders in \"${fresh['status']}\" cannot be returned.`)\n }\n const freshPlan = planPosReturn(\n fresh,\n picks,\n unitsHeldByOnlineReturns((await transaction.get(storeReturns)).docs),\n )\n if ('error' in freshPlan) throw new ReturnRefusal(409, freshPlan.error)\n const freshSplit = splitPosRefund(fresh, freshPlan.refundCents, requestedSplit)\n if ('error' in freshSplit) throw new ReturnRefusal(409, freshSplit.error)\n const prior = {\n refundedCents: Number(fresh.refundedCents ?? 0),\n returnedQuantities: { ...(fresh.returnedQuantities ?? {}) },\n posPaymentRefunds: { ...(fresh.posPaymentRefunds ?? {}) },\n }\n const posPaymentRefunds = { ...prior.posPaymentRefunds }\n for (const slice of freshSplit.allocations) {\n posPaymentRefunds[slice.paymentId] = (posPaymentRefunds[slice.paymentId] ?? 0) + slice.amountCents\n }\n transaction.update(orderRef, {\n refundedCents: prior.refundedCents + freshPlan.refundCents,\n returnedQuantities: freshPlan.returnedQuantities,\n posPaymentRefunds,\n })\n return {\n refundCents: freshPlan.refundCents,\n lineCents: freshPlan.lineCents,\n completedLines: freshPlan.completedLines,\n allocations: freshSplit.allocations,\n prior,\n }\n })\n } catch (error) {\n await claim.release()\n if (error instanceof ReturnRefusal) return { status: error.status, body: { error: error.message } }\n throw error\n }\n\n // 4–5. The money, Stripe first.\n const tenders = posRefundableByTender(order)\n const tenderOf = (paymentId: string) => tenders.find((tender) => tender.id === paymentId)\n const ordered = [...reserved.allocations].sort(\n (a, b) => Number(POS_STRIPE_TENDERS.has(b.method)) - Number(POS_STRIPE_TENDERS.has(a.method)),\n )\n const results: TenderResult[] = []\n for (const allocation of ordered) {\n const tender = tenderOf(allocation.paymentId)\n const anyMoved = results.some((result) => result.status === 'refunded')\n try {\n if (POS_STRIPE_TENDERS.has(allocation.method)) {\n const paymentIntentId = tender?.paymentIntentId ?? String(order['paymentIntentId'] ?? '')\n if (!paymentIntentId) throw new ReturnRefusal(409, 'That card payment has nothing Stripe can refund.')\n const refund = await createStripeRefund({\n paymentIntentId,\n amountCents: allocation.amountCents,\n idempotencyKey: claim.stripeKey ? `${claim.stripeKey}:${allocation.paymentId}` : null,\n metadata: { hostId: staff.hostId, orderId, registerId, kind: 'pos-return' },\n fetch: deps.fetch,\n })\n if ('error' in refund) throw new ReturnRefusal(refund.status, refund.error)\n results.push({ allocation, status: 'refunded', refundId: refund.refundId })\n } else if (allocation.method === 'gift_card') {\n await creditGiftCard(firestore, staff.hostRef, tender?.giftCardId ?? '', allocation.amountCents, orderId, deps.now())\n results.push({ allocation, status: 'refunded' })\n } else if (allocation.method === 'folio') {\n await reverseFolio(staff.hostRef, tender?.reservationId ?? String(order['reservationId'] ?? ''), allocation.amountCents, orderId, deps.now())\n results.push({ allocation, status: 'refunded' })\n } else if (allocation.method === 'credit') {\n await restorePluginCredit(\n staff.hostRef.id,\n tender,\n allocation.amountCents,\n orderId,\n `pos-return:${orderId}:${allocation.paymentId}:${reserved.prior.posPaymentRefunds[allocation.paymentId] ?? 0}`,\n )\n results.push({ allocation, status: 'refunded' })\n } else {\n // Cash: recorded on the drawer with the return itself, below.\n results.push({ allocation, status: 'refunded' })\n }\n } catch (error) {\n const message = error instanceof ReturnRefusal ? error.message : 'Refund failed'\n if (!(error instanceof ReturnRefusal)) console.error('[pos-return] tender failed', allocation, error)\n if (!anyMoved) {\n // Nothing has moved: hand the whole reservation back and let the\n // same attempt be tried again.\n await firestore\n .runTransaction(async (transaction) => {\n await transaction.get(orderRef)\n transaction.update(orderRef, reserved.prior)\n })\n .catch((rollback) => console.error('[pos-return] rollback failed', orderId, rollback))\n await claim.release()\n return {\n status: error instanceof ReturnRefusal ? error.status : 502,\n body: { error: message },\n }\n }\n results.push({ allocation, status: 'failed', error: message })\n }\n }\n\n const failed = results.filter((result) => result.status === 'failed')\n const refundedCents = results\n .filter((result) => result.status === 'refunded')\n .reduce((sum, result) => sum + result.allocation.amountCents, 0)\n const cashCents = results\n .filter((result) => result.status === 'refunded' && result.allocation.method === 'cash')\n .reduce((sum, result) => sum + result.allocation.amountCents, 0)\n const now = deps.now()\n // One id names the return under the register (its tenders and shift) and\n // in the store's returns list beside the online ones (AGL-3611).\n const returnId = createResourceUid()\n const returnRef = register.ref.collection('returns').doc(returnId)\n const storeReturnRef = staff.hostRef.collection('returns').doc(returnId)\n const orderLabel = CommerceModel.formatOrderNumber(order as any, orderId)\n const lines = picks.map((pick, at) => ({\n index: pick.index,\n quantity: pick.quantity,\n name: String(order.lineItems?.[pick.index]?.name ?? ''),\n refundCents: reserved.lineCents[at] ?? 0,\n }))\n\n // The record, the drawer, the order: one transaction.\n let closedTheOrder = false\n let fullyRefunded = false\n let shiftIdForReturn: string | null = null\n let storeReturn: CommerceModel.HostReturn | null = null\n await firestore.runTransaction(async (transaction) => {\n const freshRegister = await transaction.get(register.ref)\n const shiftId = String(freshRegister.get('openShiftId') ?? '') || null\n const shiftRef = shiftId ? register.ref.collection('shifts').doc(shiftId) : null\n const shiftSnapshot = shiftRef ? await transaction.get(shiftRef) : null\n const fresh = CommerceModel.liftLegacyOrder(\n ((await transaction.get(orderRef)).data() ?? {}) as any,\n ) as unknown as PosReturnSource & Record<string, any>\n const shiftOpen = Boolean(shiftSnapshot?.exists && shiftSnapshot.get('status') === 'open')\n shiftIdForReturn = shiftOpen ? shiftId : null\n\n // Hand back what a failed card did not refund.\n const failedCents = failed.reduce((sum, result) => sum + result.allocation.amountCents, 0)\n const posPaymentRefunds = { ...(fresh.posPaymentRefunds ?? {}) }\n for (const result of failed) {\n posPaymentRefunds[result.allocation.paymentId] = Math.max(\n 0,\n (posPaymentRefunds[result.allocation.paymentId] ?? 0) - result.allocation.amountCents,\n )\n }\n const orderRefunded = Math.max(0, Number(fresh.refundedCents ?? 0) - failedCents)\n const totalCents = Number(fresh.totals?.totalCents ?? fresh.amountCents ?? 0)\n fullyRefunded = orderRefunded >= totalCents && totalCents > 0\n closedTheOrder =\n fullyRefunded &&\n fresh['status'] !== 'refunded' &&\n CommerceModel.canTransitionOrder(fresh['status'] as CommerceModel.OrderStatus, 'refunded')\n const completedLines = Object.entries(fresh.returnedQuantities ?? {})\n .filter(([index, count]) => count >= Math.max(1, Number(fresh.lineItems?.[Number(index)]?.quantity ?? 1)))\n .map(([index]) => Number(index))\n const tenderWords = results\n .map(\n (result) =>\n `${posMoney(result.allocation.amountCents)} to ${posTenderLabel(\n tenderOf(result.allocation.paymentId) ?? { method: result.allocation.method },\n )}${result.status === 'failed' ? ' (FAILED)' : ''}`,\n )\n .join(', ')\n const units = picks.reduce((sum, pick) => sum + pick.quantity, 0)\n transaction.update(orderRef, {\n refundedCents: orderRefunded,\n posPaymentRefunds,\n ...(closedTheOrder ? { status: 'refunded' } : {}),\n ...(completedLines.length\n ? {\n refundedLineItemIds: [\n ...new Set([...(fresh.refundedLineItemIds ?? []), ...completedLines]),\n ].sort((a, b) => a - b),\n }\n : {}),\n timeline: CommerceModel.appendOrderEvent(\n fresh as any,\n 'refund',\n `Returned at the register: ${units} ${units === 1 ? 'item' : 'items'}, ${tenderWords}` +\n (restock ? '; restocked' : '') +\n (authority.approvedBy ? '; approved by a manager' : ''),\n now,\n ),\n })\n const record: PosRegisterReturn = {\n hostId: staff.hostId,\n registerId,\n orderId,\n ...(typeof order['number'] === 'number' ? { orderNumber: order['number'] } : {}),\n ...(shiftOpen && shiftId ? { shiftId } : {}),\n lines,\n refundedCents,\n tenders: results.map((result) => ({\n ...result.allocation,\n status: result.status,\n ...(result.refundId ? { refundId: result.refundId } : {}),\n ...(result.error ? { error: result.error } : {}),\n })),\n restocked: restock,\n ...(register.data['locationId'] ? { locationId: String(register.data['locationId']) } : {}),\n cashierId: cashier.cashierId,\n ...(authority.approvedBy ? { approvedBy: authority.approvedBy } : {}),\n ...(reason ? { reason } : {}),\n status: failed.length ? 'partial' : 'refunded',\n atMs: now,\n }\n transaction.create(returnRef, record)\n const restockedLines = picks.map((pick) => ({ lineItemId: pick.index, quantity: pick.quantity }))\n const registerLocationId = register.data['locationId'] ? String(register.data['locationId']) : undefined\n storeReturn = {\n orderId,\n orderNumber: orderLabel,\n customerEmail: (order['customerEmail'] as string | undefined) ?? null,\n customerName: (order['customerName'] as string | undefined) ?? null,\n lines: picks.map((pick) => ({ lineItemId: pick.index, quantity: pick.quantity, reason: reasonCode })),\n status: 'refunded',\n requestedBy: 'merchant',\n source: 'register',\n registerId,\n ...(reason ? { merchantNote: reason } : {}),\n ...(restock\n ? {\n restock: {\n lines: restockedLines,\n ...(registerLocationId ? { locationId: registerLocationId } : {}),\n atMs: now,\n },\n }\n : {}),\n refundedAtMs: now,\n refundCents: refundedCents,\n timeline: [\n {\n atMs: now,\n event: 'refunded',\n detail: `At the register${failed.length ? `; ${posMoney(failed.reduce((sum, result) => sum + result.allocation.amountCents, 0))} still owed` : ''}`,\n },\n ],\n createdAtMs: now,\n updatedAtMs: now,\n }\n transaction.create(storeReturnRef, storeReturn)\n if (shiftOpen && shiftRef && cashCents > 0) {\n const event: PosCashEvent = {\n id: returnRef.id,\n type: 'refund',\n amountCents: cashCents,\n reason: `Return ${orderLabel}`,\n by: cashier.cashierId,\n atMs: now,\n orderId,\n }\n const cashEvents = Array.isArray(shiftSnapshot?.get('cashEvents')) ? shiftSnapshot!.get('cashEvents') : []\n transaction.update(shiftRef, { cashEvents: [...cashEvents, event] })\n }\n })\n\n // Restock what came back to the register's location.\n let restockedUnits = 0\n if (restock) {\n restockedUnits = await restockReturn(\n firestore,\n staff.hostRef,\n order,\n picks,\n String(register.data['locationId'] ?? order['locationId'] ?? '') || undefined,\n orderId,\n now,\n ).catch((error) => {\n console.error('[pos-return] restock failed', orderId, error)\n return 0\n })\n }\n\n // The drawer opens for the cash being handed back.\n if (cashCents > 0) {\n await deps.printer.kickDrawer({\n hostId: staff.hostId,\n registerId,\n reason: 'cash_refund',\n causeId: returnRef.id,\n createdBy: cashier.cashierId,\n })\n }\n\n const payload = {\n returnId: returnRef.id,\n refundedCents,\n outstandingCents: failed.reduce((sum, result) => sum + result.allocation.amountCents, 0),\n partial: failed.length > 0,\n tenders: results.map((result) => ({\n method: result.allocation.method,\n label: posTenderLabel(tenderOf(result.allocation.paymentId) ?? { method: result.allocation.method }),\n amountCents: result.allocation.amountCents,\n status: result.status,\n ...(result.error ? { error: result.error } : {}),\n })),\n cashOutCents: cashCents,\n restockedUnits,\n shiftId: shiftIdForReturn,\n fullyRefunded,\n }\n await claim.record(200, payload)\n if (refundedCents > 0) {\n await deps.afterRefund({\n hostId: staff.hostId,\n orderId,\n email: order['customerEmail'] ?? null,\n refundCents: refundedCents,\n closedTheOrder,\n fullyRefunded,\n returnedProductIds: [\n ...new Set(\n picks\n .map((pick) => String((order.lineItems?.[pick.index] as { productId?: string } | undefined)?.productId ?? ''))\n .filter(Boolean),\n ),\n ],\n lineIndexes: picks.map((pick) => pick.index),\n fullLineIndexes: reserved.completedLines,\n lines: lines.map((line) => ({ index: line.index, quantity: line.quantity, refundCents: line.refundCents })),\n returnId,\n storeReturn: storeReturn as unknown as CommerceModel.HostReturn,\n refundIds: results.flatMap((result) => (result.refundId ? [result.refundId] : [])),\n })\n }\n return { status: 200, body: payload }\n}\n\n/**\n * Units per order line that the store's OTHER returns — the online returns\n * flow (AGL-3611) — hold or already took back. The register's own returns are\n * left out: `returnedQuantities` on the order already counts them.\n */\nexport function unitsHeldByOnlineReturns(\n docs: ReadonlyArray<{ data(): FirebaseFirestore.DocumentData | undefined }>,\n): number[] {\n const held: number[] = []\n for (const doc of docs) {\n const entry = (doc.data() ?? {}) as CommerceModel.HostReturn\n if (entry.source === 'register' || !CommerceModel.returnHoldsUnits(entry)) continue\n for (const line of entry.lines ?? []) {\n const index = Number(line?.lineItemId)\n if (!Number.isInteger(index) || index < 0) continue\n held[index] = (held[index] ?? 0) + Math.max(0, Math.floor(Number(line?.quantity) || 0))\n }\n }\n return held\n}\n\n/** Whether a member is a workspace admin and this site's admin, asked now. */\nasync function memberIsPosManager(\n deps: PosOpsDeps,\n hostRef: FirebaseFirestore.DocumentReference,\n hostId: string,\n uid: string,\n): Promise<boolean> {\n const host = await hostRef.get()\n const role = (host.get('memberRoles') ?? {})[uid]\n return isPosManager(role, await deps.membership(uid, hostId))\n}\n\nclass ReturnRefusal extends Error {\n constructor(\n readonly status: number,\n message: string,\n ) {\n super(message)\n }\n}\n\n/**\n * Store credit back on the card it came off. A voided or frozen card takes\n * nothing: a void is a fraud or refund decision, and re-crediting it would\n * undo that decision by the back door.\n */\nasync function creditGiftCard(\n firestore: FirebaseFirestore.Firestore,\n hostRef: FirebaseFirestore.DocumentReference,\n code: string,\n amountCents: number,\n orderId: string,\n now: number,\n): Promise<void> {\n const id = String(code ?? '').trim()\n if (!id || id.includes('/') || id.length > 64) throw new ReturnRefusal(409, 'That gift card payment does not name its card.')\n const ref = hostRef.collection('giftCards').doc(id)\n await firestore.runTransaction(async (transaction) => {\n const card = await transaction.get(ref)\n if (!card.exists) throw new ReturnRefusal(409, 'That gift card no longer exists.')\n if (card.get('voidedAtMs') != null || card.get('frozenAtMs') != null) {\n throw new ReturnRefusal(409, 'That gift card is voided or frozen, so it cannot take a refund.')\n }\n transaction.update(ref, {\n balanceCents: Math.max(0, Math.round(Number(card.get('balanceCents') ?? 0))) + amountCents,\n lastCreditAtMs: now,\n lastCreditOrderId: orderId,\n })\n })\n}\n\n/**\n * Store credit back to the plugin that keeps it (AGL-3640): a rewards\n * balance gets back what this payment took. Idempotent per `key`, so a\n * retried return gives back once. A friend's referral credit was a discount,\n * not a balance, and its provider gives nothing back — correctly: nobody is\n * owed money for it.\n */\nasync function restorePluginCredit(\n hostId: string,\n tender: { creditProviderId?: string; creditReference?: string } | undefined,\n amountCents: number,\n orderId: string,\n key: string,\n): Promise<void> {\n const entry = tender?.creditProviderId ? checkoutCreditProvider(tender.creditProviderId) : null\n if (!entry || !tender?.creditReference) {\n throw new ReturnRefusal(409, 'The store credit on this sale cannot take a refund right now.')\n }\n await entry.provider.restore({ hostId, reference: tender.creditReference, orderId, cents: amountCents, key })\n}\n\n/** A room charge taken back: a negative line on the same stay's folio. */\nasync function reverseFolio(\n hostRef: FirebaseFirestore.DocumentReference,\n reservationId: string,\n amountCents: number,\n orderId: string,\n now: number,\n): Promise<void> {\n const id = posOpsCleanId(reservationId)\n if (!id) throw new ReturnRefusal(409, 'That room charge does not name its stay.')\n const ref = hostRef.collection('reservations').doc(id)\n const firestore = hostRef.firestore\n await firestore.runTransaction(async (transaction) => {\n const stay = await transaction.get(ref)\n if (!stay.exists) throw new ReturnRefusal(409, 'That stay no longer exists.')\n const folio = Array.isArray(stay.get('folio')) ? stay.get('folio') : []\n transaction.update(ref, {\n folio: [...folio, { orderId, amountCents: -amountCents, note: 'Return at the register', atMs: now }],\n })\n })\n}\n\n/**\n * The returned units back on the shelf, at the register's location, with an\n * adjustment row each so the stock history says why the count went up.\n * Only variants that track stock move.\n */\nasync function restockReturn(\n firestore: FirebaseFirestore.Firestore,\n hostRef: FirebaseFirestore.DocumentReference,\n order: PosReturnSource & Record<string, any>,\n picks: readonly PosReturnPick[],\n locationId: string | undefined,\n orderId: string,\n now: number,\n): Promise<number> {\n const byProduct = new Map<string, Array<{ variantId?: string; quantity: number }>>()\n for (const pick of picks) {\n const line = (order.lineItems ?? [])[pick.index] as Record<string, any> | undefined\n const productId = String(line?.['productId'] ?? '')\n if (!productId) continue\n byProduct.set(productId, [\n ...(byProduct.get(productId) ?? []),\n { ...(line?.['variantId'] ? { variantId: String(line['variantId']) } : {}), quantity: pick.quantity },\n ])\n }\n let units = 0\n for (const [productId, lines] of byProduct) {\n const ref = hostRef.collection('products').doc(productId)\n units += await firestore.runTransaction(async (transaction) => {\n const snapshot = await transaction.get(ref)\n if (!snapshot.exists) return 0\n const product = CommerceModel.liftLegacyProduct(snapshot.data() as any)\n let variants = product.variants\n const rows: Array<{ variantId: string; quantity: number }> = []\n for (const line of lines) {\n const variantId = line.variantId ?? product.variants[0]?.id\n const variant = variants.find((candidate) => candidate.id === variantId)\n if (!variantId || !variant || variant.inventory == null) continue\n variants = CommerceModel.adjustVariantInventory({ variants }, variantId, line.quantity, locationId)\n rows.push({ variantId, quantity: line.quantity })\n }\n if (!rows.length) return 0\n transaction.update(ref, {\n variants,\n ...CommerceModel.productStockFields({ ...product, variants }),\n updatedAtMs: now,\n })\n for (const row of rows) {\n transaction.create(hostRef.collection('inventoryAdjustments').doc(createResourceUid()), {\n productId,\n variantId: row.variantId,\n delta: row.quantity,\n reason: 'refund',\n orderId,\n ...(locationId ? { locationId } : {}),\n atMs: now,\n } satisfies CommerceModel.InventoryAdjustment)\n }\n return rows.reduce((sum, row) => sum + row.quantity, 0)\n })\n }\n return units\n}\n\nexport function createPosReturnHandler(\n deps: () => PosReturnDeps = defaultPosReturnDeps,\n): PluginApiHandler {\n return async (req, res) => {\n try {\n const outcome = await handlePosReturn(deps(), req)\n return res.status(outcome.status).json(outcome.body)\n } catch (error) {\n console.error('[pos-return] failed', error)\n return res.status(500).json({ error: 'The return could not be refunded' })\n }\n }\n}\n\nexport const posReturnHandler = createPosReturnHandler()\n"],"names":["claimAttempt","createResourceUid","nameSearchKey","recordPluginPersonRefund","reverseOrderConversion","checkoutCreditProvider","CommerceModel","planPosReturn","posMoney","posRefundableByTender","posReturnedQuantities","posReturnLineValues","posTenderLabel","POS_STRIPE_TENDERS","splitPosRefund","ORDER_REFUNDED_EVENT","RETURN_REFUNDED_EVENT","raiseOrderEvent","applyGiftCardRiskToOrder","notifyOrderBuyer","decidePosRefundAuthority","authorizePosOps","defaultPosOpsDeps","posOpsBody","posOpsCleanId","posOpsIdempotencyKey","readPosRegister","isPosManager","resolvePosCashier","createStripeRefund","parsePosHardwareInPersonConfig","defaultPosReturnDeps","base","afterRefund","input","settle","label","work","error","console","orderId","hostRef","firestore","collection","doc","hostId","returnedProductIds","length","action","kind","reason","fullyRefunded","productIds","refId","email","amountCents","refundCents","closedTheSale","closedTheOrder","key","returnId","extra","refund","id","refundIds","lineItemIds","fullLineIndexes","full","return","status","storeReturn","lines","map","line","process","env","sellerHostId","recordRegisterHardwareReturn","config","registerOrderId","refundId","refundLineIndexes","lineIndexes","RETURNABLE","Set","returnSummary","raw","held","order","liftLegacyOrder","values","returned","number","formatOrderNumber","channel","createdAtMs","Number","customerEmail","customerName","totalCents","totals","refundedCents","returnable","has","String","lineItems","index","name","variantLabel","quantity","Math","max","round","valueCents","tenders","tender","method","refundableCents","findOrders","rawText","snapshot","text","trim","slice","orders","digits","replace","test","where","limit","get","docs","data","includes","orderBy","exists","parsePicks","Array","isArray","entry","parseSplit","paymentId","handlePosReturn","deps","req","body","register","gate","staff","found","Promise","all","unitsHeldByOnlineReturns","at","registerId","ref","idempotencyKey","picks","requestedSplit","restock","reasonCode","RETURN_REASONS","orderRef","storeReturns","orderDisputeBlocksRefund","plan","split","cashier","cashierIsManager","cashierId","uid","isManager","memberIsPosManager","authority","limitCents","settings","refundLimitCents","managerAssertion","needsCash","allocations","some","needsStripe","openShiftId","requireOpenShift","STRIPE_SECRET_KEY","claimed","scopeId","orgId","busyMessage","replay","claim","reserved","runTransaction","transaction","fresh","ReturnRefusal","freshPlan","freshSplit","prior","returnedQuantities","posPaymentRefunds","update","lineCents","completedLines","release","message","tenderOf","find","ordered","sort","a","b","results","allocation","anyMoved","result","paymentIntentId","stripeKey","metadata","fetch","push","creditGiftCard","giftCardId","now","reverseFolio","reservationId","restorePluginCredit","catch","rollback","failed","filter","reduce","sum","cashCents","returnRef","storeReturnRef","orderLabel","pick","shiftIdForReturn","freshRegister","shiftId","shiftRef","shiftSnapshot","shiftOpen","Boolean","failedCents","orderRefunded","canTransitionOrder","Object","entries","count","tenderWords","join","units","refundedLineItemIds","timeline","appendOrderEvent","approvedBy","record","orderNumber","restocked","locationId","atMs","create","restockedLines","lineItemId","registerLocationId","undefined","requestedBy","source","merchantNote","refundedAtMs","event","detail","updatedAtMs","type","by","cashEvents","restockedUnits","restockReturn","printer","kickDrawer","causeId","createdBy","payload","outstandingCents","partial","cashOutCents","productId","flatMap","returnHoldsUnits","isInteger","floor","host","role","membership","Error","code","card","balanceCents","lastCreditAtMs","lastCreditOrderId","creditProviderId","creditReference","provider","restore","reference","cents","stay","folio","note","byProduct","Map","set","variantId","product","liftLegacyProduct","variants","rows","variant","candidate","inventory","adjustVariantInventory","productStockFields","row","delta","createPosReturnHandler","res","outcome","json","posReturnHandler"],"mappings":"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"}
@@ -296,8 +296,13 @@ const saleCompletedListeners = new Set();
296
296
  }
297
297
  // Stock comes off exactly once, here, compounding across lines of one
298
298
  // product (AGL-1828) and atomically against other channels (AGL-2320).
299
+ //
300
+ // Except for a sale rung OFFLINE (AGL-3625): the customer left with the
301
+ // goods, so the offline sync took the stock when it recorded the sale,
302
+ // paid or not. One whose card failed and is collected later at the
303
+ // register (AGL-4039) completes here, and must not take it a second time.
299
304
  const products = new Map();
300
- for (const line of (_order_lineItems = order.lineItems) != null ? _order_lineItems : []){
305
+ for (const line of order.offline ? [] : (_order_lineItems = order.lineItems) != null ? _order_lineItems : []){
301
306
  try {
302
307
  var _line_variantId;
303
308
  var _product_variants_;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/pos-sale.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 { createHash } from 'crypto'\nimport { firebaseAdmin } from '@aglyn/tenant-data-admin'\nimport recordCapturedContact from '@aglyn/aglyn/plugin-manager/record-captured-contact'\nimport * as CommerceModel from '../model'\nimport { alertLowStockCrossing } from './low-stock'\nimport { decrementVariantStock } from './reserve-stock'\nimport { releasePromotionHold, settlePromotionSlot } from './promotion-hold'\nimport { offlineFeeMonthKey } from './pos-fee-month'\nimport { resetPosDisplay } from './pos-display'\nimport { notifyOrderBuyer, sendOrderReceipt } from './order-notifications'\nimport { raiseOrderEvent } from './order-events'\nimport { ORDER_PAID_EVENT } from '../model/order-events'\n\n/*==========================================\n * AN OPEN REGISTER SALE (AGL-3607).\n *\n * A split-tender sale is an order written `pending` with an empty\n * `payments[]`, priced once by `pos-order.ts` (`payment: 'open'`). Each tender\n * then adds one payment through {@link applyPosPayment}, which is the ONLY\n * writer of the ledger and runs every change in one transaction on the order\n * document. When the settled payments cover the total, the same transaction\n * flips the order to `paid` and accrues the invoiced part of the fee, so a\n * sale is completed exactly once however many webhooks, polls and retries\n * race to report its last payment. Stock, the promotion slot, the contact and\n * the receipt follow from that one flip ({@link completePosSale}).\n *=========================================*/\n\nexport type PosLiftedOrder = CommerceModel.HostOrder & {\n $id: string\n /** The sale's platform take, before any card processing (AGL-2111). */\n posTakeFeeCents?: number\n /** The org the invoiced part of the take accrues to. */\n posFeeOrgId?: string\n /** The promotion slot this sale holds until it completes (AGL-305). */\n discountId?: string\n discountHoldKey?: string\n paymentIntentIds?: string[]\n reservationId?: string\n}\n\n/**\n * A payment's id, derived from the register's attempt key so a retried tap\n * finds the payment it already started instead of starting a second one.\n */\nexport function posPaymentId(orderId: string, attemptKey: string): string {\n return `pay_${createHash('sha256')\n .update(`${orderId}:${attemptKey}`)\n .digest('hex')\n .slice(0, 24)}`\n}\n\n/** What one ledger change decided. */\nexport type PosPaymentStep =\n | { kind: 'refuse'; status: number; error: string }\n /** Nothing to change: the payment is already in the state asked for. */\n | { kind: 'keep' }\n | {\n kind: 'put'\n payment: CommerceModel.OrderPayment\n /** A timeline line for the order, when the change is worth one. */\n event?: { event: string; detail?: string }\n }\n\nexport type PosPaymentOutcome =\n | { ok: false; status: number; error: string }\n | {\n ok: true\n order: PosLiftedOrder\n payment: CommerceModel.OrderPayment | null\n /** True only on the call whose change completed the sale. */\n completed: boolean\n changed: boolean\n }\n\n/** The open sale's ledger, as the register reads it back after any change. */\nexport function posSaleSummary(order: PosLiftedOrder) {\n const payments = CommerceModel.orderPayments(order)\n const totalCents = Number(order.totals?.totalCents ?? 0)\n return {\n orderId: order.$id,\n status: order.status,\n totalCents,\n paidCents: CommerceModel.posSettledCents(payments),\n dueCents: CommerceModel.posBalanceDueCents(totalCents, payments),\n tenderableCents: CommerceModel.posTenderableCents(totalCents, payments),\n tipCents: CommerceModel.posTipCents(payments),\n payments: payments.map((payment) => ({\n id: payment.id,\n method: payment.method,\n amountCents: payment.amountCents,\n ...(payment.tipCents ? { tipCents: payment.tipCents } : {}),\n status: payment.status,\n ...(payment.cardBrand ? { cardBrand: payment.cardBrand } : {}),\n ...(payment.last4 ? { last4: payment.last4 } : {}),\n ...(payment.changeCents != null ? { changeCents: payment.changeCents } : {}),\n ...(payment.checkoutUrl && payment.status === 'pending'\n ? { checkoutUrl: payment.checkoutUrl }\n : {}),\n ...(payment.readerId ? { readerId: payment.readerId } : {}),\n // What a store-credit payment's provider calls it (AGL-3640).\n ...(payment.creditLabel ? { creditLabel: payment.creditLabel } : {}),\n ...(payment.failureMessage ? { failureMessage: payment.failureMessage } : {}),\n ...(payment.livemode != null ? { livemode: payment.livemode } : {}),\n })),\n }\n}\n\n/**\n * The fields that complete a sale, when its settled payments now cover the\n * total; null when the balance is still open or the sale is not pending.\n *\n * Pure, so the spec can hold the arithmetic: the fee is every card payment's\n * own `application_fee_amount` plus the take the cards did not carry, the tip\n * is summed beside the total and never inside it. Cash and gift-card parts\n * carry no take at all (AGL-4036), so they add nothing to either half.\n */\nexport function posCompletionPatch(\n order: PosLiftedOrder,\n payments: CommerceModel.OrderPayment[],\n nowMs: number,\n): {\n patch: Record<string, unknown>\n invoiceTakeCents: number\n} | null {\n if (order.status !== 'pending') return null\n const totalCents = Number(order.totals?.totalCents ?? 0)\n if (CommerceModel.posBalanceDueCents(totalCents, payments) > 0) return null\n const takeFeeCents = Math.max(0, Math.round(Number(order.posTakeFeeCents ?? 0)))\n const invoiceTakeCents = CommerceModel.posInvoiceTakeCents({ takeFeeCents, totalCents, payments })\n const settled = payments.filter((payment) => payment.status === 'succeeded')\n const cardFeeCents = settled\n .filter((payment) => CommerceModel.isCardPaymentMethod(payment.method))\n .reduce((sum, payment) => sum + Math.max(0, Math.round(Number(payment.feeCents ?? 0))), 0)\n const feeCents = cardFeeCents + invoiceTakeCents\n const tipCents = CommerceModel.posTipCents(payments)\n const intents = settled\n .map((payment) => payment.paymentIntentId)\n .filter((id): id is string => Boolean(id))\n const tenders = settled.map((payment) => CommerceModel.describeOrderPayment(payment))\n const overpaid = CommerceModel.posSettledCents(payments) - totalCents\n return {\n invoiceTakeCents,\n patch: {\n status: 'paid',\n paidAtMs: nowMs,\n totals: {\n ...(order.totals ?? {}),\n feeCents,\n ...(tipCents > 0 ? { tipCents } : {}),\n },\n ...(feeCents > 0 ? { feeCollection: CommerceModel.posFeeCollection(payments) } : {}),\n ...(intents.length ? { paymentIntentIds: intents } : {}),\n // The single-charge readers (refund, dispute lookup) key on this; a\n // sale with one card payment keeps working with every one of them.\n ...(intents.length === 1 ? { paymentIntentId: intents[0] } : {}),\n ...(settled.some((payment) => payment.livemode === false) ? { livemode: false } : {}),\n timeline: CommerceModel.appendOrderEvent(\n order,\n 'paid',\n `Paid — ${tenders.join(', ')}` +\n (overpaid > 0\n ? `. Overpaid by $${(overpaid / 100).toFixed(2)}: refund the difference.`\n : ''),\n nowMs,\n ),\n },\n }\n}\n\n/** The order document, lifted, with its id. */\nfunction liftOrder(id: string, data: unknown): PosLiftedOrder {\n return {\n ...(CommerceModel.liftLegacyOrder((data ?? {}) as any) as any),\n $id: id,\n }\n}\n\n/**\n * The ONE writer of a sale's ledger. Runs `prepare` (extra reads) and\n * `decide` inside one transaction on the order, writes the payment, and\n * completes the sale in the same commit when the balance reaches zero.\n */\nexport async function applyPosPayment<C = undefined>(options: {\n hostId: string\n orderId: string\n paymentId: string\n /** Reads beyond the order (a gift card, a stay), before any write. */\n prepare?: (transaction: any) => Promise<C>\n decide: (sale: {\n order: PosLiftedOrder\n payments: CommerceModel.OrderPayment[]\n existing: CommerceModel.OrderPayment | undefined\n context: C\n }) => PosPaymentStep\n /** Writes beyond the order, in the same transaction, for a `put`. */\n write?: (\n transaction: any,\n context: C,\n payment: CommerceModel.OrderPayment,\n previous: CommerceModel.OrderPayment | undefined,\n ) => void\n nowMs?: number\n}): Promise<PosPaymentOutcome> {\n const firestore = firebaseAdmin.app().firestore()\n const orderRef = firestore\n .collection('hosts')\n .doc(options.hostId)\n .collection('orders')\n .doc(options.orderId)\n const nowMs = options.nowMs ?? Date.now()\n const outcome = await firestore.runTransaction(async (transaction: any) => {\n const snapshot = await transaction.get(orderRef)\n if (!snapshot.exists) {\n return { ok: false as const, status: 404, error: 'Unknown sale' }\n }\n const order = liftOrder(orderRef.id, snapshot.data())\n if (order.channel !== 'pos' || !Array.isArray(order.payments)) {\n return { ok: false as const, status: 409, error: 'This order is not an open register sale' }\n }\n const context = (options.prepare\n ? await options.prepare(transaction)\n : undefined) as C\n const payments = CommerceModel.orderPayments(order)\n const existing = payments.find((payment) => payment.id === options.paymentId)\n const step = options.decide({ order, payments, existing, context })\n if (step.kind === 'refuse') {\n return { ok: false as const, status: step.status, error: step.error }\n }\n if (step.kind === 'keep') {\n return {\n ok: true as const,\n order,\n payment: existing ?? null,\n completed: false,\n changed: false,\n }\n }\n const nextPayments = existing\n ? payments.map((payment) => (payment.id === step.payment.id ? step.payment : payment))\n : [...payments, step.payment]\n let next: PosLiftedOrder = { ...order, payments: nextPayments }\n if (step.event) {\n next = {\n ...next,\n timeline: CommerceModel.appendOrderEvent(\n order,\n step.event.event,\n step.event.detail,\n nowMs,\n ),\n }\n }\n const completion = posCompletionPatch(next, nextPayments, nowMs)\n const write: Record<string, unknown> = {\n payments: nextPayments,\n ...(next.timeline !== order.timeline ? { timeline: next.timeline } : {}),\n }\n if (completion) {\n Object.assign(write, completion.patch)\n next = { ...next, ...(completion.patch as Partial<PosLiftedOrder>) }\n Object.assign(write, CommerceModel.orderListFields(next, orderRef.id))\n // ACCRUED IN THE SAME COMMIT AS THE FLIP (the AGL-2111 rule): the part\n // of the take no card payout carried goes on the org's invoice, and an\n // order and the fee it owes cannot diverge.\n const feeOrgId = String(order.posFeeOrgId ?? '')\n if (completion.invoiceTakeCents > 0 && feeOrgId) {\n const month = offlineFeeMonthKey(new Date(nowMs))\n transaction.set(\n firestore.collection('orgs').doc(feeOrgId).collection('offlineFees').doc(month),\n {\n month,\n feeCents: firebaseAdmin.firestore.FieldValue.increment(completion.invoiceTakeCents),\n orders: firebaseAdmin.firestore.FieldValue.increment(1),\n },\n { merge: true },\n )\n }\n } else if (\n order.status === 'paid' &&\n step.payment.status === 'succeeded' &&\n existing?.status !== 'succeeded'\n ) {\n // MONEY THAT ARRIVED AFTER THE SALE WAS ALREADY PAID: a QR page paid\n // after the cashier took another tender. It is recorded, never\n // dropped, and said on the order so the merchant can refund it.\n write['timeline'] = CommerceModel.appendOrderEvent(\n next,\n 'pos-overpaid',\n `${CommerceModel.describeOrderPayment(step.payment)} arrived after the ` +\n 'sale was already paid. Refund it from Stripe.',\n nowMs,\n )\n }\n transaction.set(orderRef, write, { merge: true })\n options.write?.(transaction, context, step.payment, existing)\n return {\n ok: true as const,\n order: next,\n payment: step.payment,\n completed: Boolean(completion),\n changed: true,\n }\n })\n if (outcome.ok && outcome.completed) {\n await completePosSale(options.hostId, outcome.order)\n }\n return outcome\n}\n\n/*==========================================\n * \"A REGISTER SALE COMPLETED\" — the one point every POS sale passes through\n * (AGL-3607), whichever way it was paid: the ledger's last payment\n * ({@link completePosSale}), a single-tender cash or room sale\n * (`pos-order.ts`), or a legacy QR sale paid through the `commerce-draft`\n * webhook branch. Peripherals (a cloud receipt printer, a cash drawer kick)\n * and anything else that must follow a sale subscribe here rather than\n * patching each path.\n *=========================================*/\n\nexport interface PosSaleCompletedEvent {\n hostId: string\n orderId: string\n order: CommerceModel.HostOrder\n /**\n * Rung while the register was offline and synced later (AGL-3625): the\n * customer has already left, so nothing at the counter should react now.\n */\n offline?: boolean\n}\n\nexport type PosSaleCompletedListener = (event: PosSaleCompletedEvent) => void | Promise<void>\n\nconst saleCompletedListeners = new Set<PosSaleCompletedListener>()\n\n/** Subscribes to completed register sales; returns the unsubscribe. */\nexport function onPosSaleCompleted(listener: PosSaleCompletedListener): () => void {\n saleCompletedListeners.add(listener)\n return () => saleCompletedListeners.delete(listener)\n}\n\n/**\n * Tells every listener a register sale completed. Awaited, and never throws:\n * the money is already taken, so a listener's failure is logged, not\n * returned to a cashier who would ring the sale again.\n */\nexport async function notifyPosSaleCompleted(event: PosSaleCompletedEvent): Promise<void> {\n for (const listener of [...saleCompletedListeners]) {\n try {\n await listener(event)\n } catch (error) {\n console.error('[pos-sale] sale-completed listener failed', event.orderId, error)\n }\n }\n}\n\n/** Reads the sale as it stands, for the register's status polls. */\nexport async function readPosSale(\n hostId: string,\n orderId: string,\n): Promise<PosLiftedOrder | null> {\n const snapshot = await firebaseAdmin\n .app()\n .firestore()\n .collection('hosts')\n .doc(hostId)\n .collection('orders')\n .doc(orderId)\n .get()\n if (!snapshot.exists) return null\n return liftOrder(snapshot.id, snapshot.data())\n}\n\n/**\n * Everything that follows a sale being paid, run once by the call whose\n * commit completed it. Each step is guarded on its own and none can undo the\n * sale: the money is taken, so a failure here is logged and said on the order\n * rather than thrown back at a cashier who would ring it again.\n */\nexport async function completePosSale(\n hostId: string,\n order: PosLiftedOrder,\n): Promise<void> {\n const firestore = firebaseAdmin.app().firestore()\n const hostRef = firestore.collection('hosts').doc(hostId)\n const orderRef = hostRef.collection('orders').doc(order.$id)\n const notes: Array<{ event: string; detail: string }> = []\n\n // The promotion's slot becomes a redemption only now: a sale that was\n // voided half-paid never counted against the merchant's cap (AGL-305).\n if (order.discountId && order.discountHoldKey) {\n const settled = await settlePromotionSlot({\n firestore,\n ref: hostRef.collection('discounts').doc(order.discountId),\n holdKey: order.discountHoldKey,\n label: `pos discount ${order.discountId}`,\n })\n if (settled === 'missing' || settled === 'error') {\n notes.push({\n event: 'redemption-orphaned',\n detail:\n `Discount ${order.discountId} was applied to this sale but its ` +\n 'redemption could not be counted against its limit.',\n })\n }\n }\n\n // Stock comes off exactly once, here, compounding across lines of one\n // product (AGL-1828) and atomically against other channels (AGL-2320).\n const products = new Map<string, CommerceModel.HostProduct>()\n for (const line of order.lineItems ?? []) {\n try {\n if (!products.has(line.productId)) {\n const snapshot = await hostRef.collection('products').doc(line.productId).get()\n if (!snapshot.exists) continue\n products.set(line.productId, CommerceModel.liftLegacyProduct(snapshot.data() as any))\n }\n const product = products.get(line.productId) as CommerceModel.HostProduct\n const variantId = line.variantId ?? product.variants[0]?.id\n const tracked = product.variants.some(\n (variant) => variant.id === variantId && variant.inventory != null,\n )\n if (!variantId || !tracked) continue\n const moved = await decrementVariantStock({\n firestore,\n hostRef,\n hostId,\n productId: line.productId,\n variantId,\n quantity: line.quantity,\n locationId: order.locationId || undefined,\n ledger: { reason: 'sale', orderId: order.$id },\n })\n if (!moved.before || !moved.after) continue\n products.set(line.productId, moved.after)\n alertLowStockCrossing(hostId, moved.before, moved.after)\n } catch (error) {\n console.error('[pos-sale] stock decrement failed', order.$id, line.productId, error)\n }\n }\n\n const receipt = order.receiptRequest\n const receiptEmail = receipt?.channel === 'email' ? String(receipt.to ?? '') : ''\n const contactEmail = receiptEmail || String(order.customerEmail ?? '')\n const marketingOptIn = Boolean((receipt as { marketingOptIn?: boolean } | undefined)?.marketingOptIn)\n const totalCents = Number(order.totals?.totalCents ?? 0)\n if (contactEmail) {\n await recordCapturedContact({\n orgId: '',\n hostId,\n identity: { email: contactEmail },\n surface: 'relationship',\n lifecycleFloor: 'customer',\n // The customer's own tick on the display, the same opt-in the online\n // checkout records (AGL-3608); an unticked box records nothing.\n ...(marketingOptIn ? { marketingConsent: true } : {}),\n purchaseCents: totalCents,\n interaction: {\n source: 'order',\n refId: order.$id,\n summary: `In-store purchase ($${(totalCents / 100).toFixed(2)})`,\n },\n }).catch((error: unknown) => {\n console.error('[pos-sale] contact capture failed', error)\n })\n }\n\n // The receipt and the paid event, through the same doors every sale uses\n // (AGL-3610, AGL-3611): the buyer-notification door claims each message\n // per channel, so a second completion path can never mail twice, and it\n // texts the receipt when the customer chose a text and a provider is on.\n if ((receipt?.channel === 'email' || receipt?.channel === 'sms') && receipt.to) {\n // The customer named where it goes: it goes there, whatever else the\n // order holds (AGL-3608).\n const sent = await deliverChosenPosReceipt(\n { hostId, orderId: order.$id },\n { channel: receipt.channel, to: receipt.to, orderEmail: String(order.customerEmail ?? '') },\n )\n if (sent !== 'sent') {\n notes.push({\n event: 'receipt-unsent',\n detail: `The ${receipt.channel === 'sms' ? 'text' : 'email'} receipt could not be sent.`,\n })\n }\n } else if (contactEmail) {\n await notifyOrderBuyer({ hostId, orderId: order.$id }, 'receipt', { email: contactEmail })\n }\n await raiseOrderEvent(ORDER_PAID_EVENT, { hostId, orderId: order.$id, key: 'paid' }).catch(\n (error: unknown) => console.error('[pos-sale] order.paid event failed', error),\n )\n\n if (notes.length) {\n await firestore\n .runTransaction(async (transaction: any) => {\n const fresh = liftOrder(orderRef.id, (await transaction.get(orderRef)).data())\n let timeline = fresh.timeline ?? []\n for (const note of notes) {\n timeline = CommerceModel.appendOrderEvent({ timeline }, note.event, note.detail)\n }\n transaction.set(orderRef, { timeline }, { merge: true })\n })\n .catch((error: unknown) => console.error('[pos-sale] note failed', error))\n }\n\n await notifyPosSaleCompleted({ hostId, orderId: order.$id, order })\n\n // The customer screen says thank you and forgets the customer: the state\n // is rewritten whole, so no address or phone outlives the sale (AGL-3608).\n if (order.registerId) {\n await resetPosDisplay(hostId, order.registerId).catch((error: unknown) =>\n console.error('[pos-sale] display reset failed', error),\n )\n }\n}\n\n/**\n * Sends a receipt the customer (or the cashier for them) explicitly asked\n * for, to the address or number they gave (AGL-3607, AGL-3608).\n *\n * It goes through the buyer-notification door first, so the order's\n * once-per-channel marker is claimed and a completion that races this call\n * cannot send a second copy. The door can skip it, though, for reasons that\n * do not apply to a request made at the counter: the store switched\n * automatic receipts or texts off, a receipt already went out on that\n * channel to an earlier address, or the door would use the email the order\n * was opened with rather than the one just typed. In each of those cases the\n * receipt is sent explicitly, as the order dialog's \"Resend receipt\" does.\n */\nexport async function deliverChosenPosReceipt(\n ref: { hostId: string; orderId: string },\n input: { channel: 'email' | 'sms'; to: string; orderEmail?: string },\n): Promise<'sent' | 'failed' | 'not_configured'> {\n const orderEmail = String(input.orderEmail ?? '').trim().toLowerCase()\n const to = input.to.trim()\n const doorAddressesIt = input.channel === 'sms' || !orderEmail || orderEmail === to.toLowerCase()\n if (doorAddressesIt) {\n const door = await notifyOrderBuyer(ref, 'receipt', input.channel === 'email' ? { email: to } : {})\n const entry =\n door.outcome === 'handled'\n ? door.channels.find((channel) => channel.channel === input.channel)\n : undefined\n if (entry?.outcome === 'sent') return 'sent'\n if (entry?.outcome === 'failed') return 'failed'\n // Already sent to this very address: nothing more to do.\n if (entry?.outcome === 'already' && input.channel === 'email') return 'sent'\n }\n const explicit = await sendOrderReceipt(ref, { channel: input.channel, to })\n if (explicit.outcome === 'sent') return 'sent'\n return explicit.outcome === 'not_configured' ? 'not_configured' : 'failed'\n}\n\n/**\n * Hands back a promotion slot an open sale was holding, when the sale is\n * voided rather than paid.\n */\nexport async function releasePosSaleDiscount(\n hostId: string,\n order: PosLiftedOrder,\n): Promise<void> {\n if (!order.discountId || !order.discountHoldKey) return\n await releasePromotionHold(\n firebaseAdmin\n .app()\n .firestore()\n .collection('hosts')\n .doc(hostId)\n .collection('discounts')\n .doc(order.discountId),\n order.discountHoldKey,\n )\n}\n"],"names":["createHash","firebaseAdmin","recordCapturedContact","CommerceModel","alertLowStockCrossing","decrementVariantStock","releasePromotionHold","settlePromotionSlot","offlineFeeMonthKey","resetPosDisplay","notifyOrderBuyer","sendOrderReceipt","raiseOrderEvent","ORDER_PAID_EVENT","posPaymentId","orderId","attemptKey","update","digest","slice","posSaleSummary","order","payments","orderPayments","totalCents","Number","totals","$id","status","paidCents","posSettledCents","dueCents","posBalanceDueCents","tenderableCents","posTenderableCents","tipCents","posTipCents","map","payment","id","method","amountCents","cardBrand","last4","changeCents","checkoutUrl","readerId","creditLabel","failureMessage","livemode","posCompletionPatch","nowMs","takeFeeCents","Math","max","round","posTakeFeeCents","invoiceTakeCents","posInvoiceTakeCents","settled","filter","cardFeeCents","isCardPaymentMethod","reduce","sum","feeCents","intents","paymentIntentId","Boolean","tenders","describeOrderPayment","overpaid","patch","paidAtMs","feeCollection","posFeeCollection","length","paymentIntentIds","some","timeline","appendOrderEvent","join","toFixed","liftOrder","data","liftLegacyOrder","applyPosPayment","options","firestore","app","orderRef","collection","doc","hostId","Date","now","outcome","runTransaction","transaction","snapshot","get","exists","ok","error","channel","Array","isArray","context","prepare","undefined","existing","find","paymentId","step","decide","kind","completed","changed","nextPayments","next","event","detail","completion","write","Object","assign","orderListFields","feeOrgId","String","posFeeOrgId","month","set","FieldValue","increment","orders","merge","completePosSale","saleCompletedListeners","Set","onPosSaleCompleted","listener","add","delete","notifyPosSaleCompleted","console","readPosSale","receipt","hostRef","notes","discountId","discountHoldKey","ref","holdKey","label","push","products","Map","line","lineItems","product","has","productId","liftLegacyProduct","variantId","variants","tracked","variant","inventory","moved","quantity","locationId","ledger","reason","before","after","receiptRequest","receiptEmail","to","contactEmail","customerEmail","marketingOptIn","orgId","identity","email","surface","lifecycleFloor","marketingConsent","purchaseCents","interaction","source","refId","summary","catch","sent","deliverChosenPosReceipt","orderEmail","key","fresh","note","registerId","input","trim","toLowerCase","doorAddressesIt","door","entry","channels","explicit","releasePosSaleDiscount"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/pos-sale.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 { createHash } from 'crypto'\nimport { firebaseAdmin } from '@aglyn/tenant-data-admin'\nimport recordCapturedContact from '@aglyn/aglyn/plugin-manager/record-captured-contact'\nimport * as CommerceModel from '../model'\nimport { alertLowStockCrossing } from './low-stock'\nimport { decrementVariantStock } from './reserve-stock'\nimport { releasePromotionHold, settlePromotionSlot } from './promotion-hold'\nimport { offlineFeeMonthKey } from './pos-fee-month'\nimport { resetPosDisplay } from './pos-display'\nimport { notifyOrderBuyer, sendOrderReceipt } from './order-notifications'\nimport { raiseOrderEvent } from './order-events'\nimport { ORDER_PAID_EVENT } from '../model/order-events'\n\n/*==========================================\n * AN OPEN REGISTER SALE (AGL-3607).\n *\n * A split-tender sale is an order written `pending` with an empty\n * `payments[]`, priced once by `pos-order.ts` (`payment: 'open'`). Each tender\n * then adds one payment through {@link applyPosPayment}, which is the ONLY\n * writer of the ledger and runs every change in one transaction on the order\n * document. When the settled payments cover the total, the same transaction\n * flips the order to `paid` and accrues the invoiced part of the fee, so a\n * sale is completed exactly once however many webhooks, polls and retries\n * race to report its last payment. Stock, the promotion slot, the contact and\n * the receipt follow from that one flip ({@link completePosSale}).\n *=========================================*/\n\nexport type PosLiftedOrder = CommerceModel.HostOrder & {\n $id: string\n /** The sale's platform take, before any card processing (AGL-2111). */\n posTakeFeeCents?: number\n /** The org the invoiced part of the take accrues to. */\n posFeeOrgId?: string\n /** The promotion slot this sale holds until it completes (AGL-305). */\n discountId?: string\n discountHoldKey?: string\n paymentIntentIds?: string[]\n reservationId?: string\n}\n\n/**\n * A payment's id, derived from the register's attempt key so a retried tap\n * finds the payment it already started instead of starting a second one.\n */\nexport function posPaymentId(orderId: string, attemptKey: string): string {\n return `pay_${createHash('sha256')\n .update(`${orderId}:${attemptKey}`)\n .digest('hex')\n .slice(0, 24)}`\n}\n\n/** What one ledger change decided. */\nexport type PosPaymentStep =\n | { kind: 'refuse'; status: number; error: string }\n /** Nothing to change: the payment is already in the state asked for. */\n | { kind: 'keep' }\n | {\n kind: 'put'\n payment: CommerceModel.OrderPayment\n /** A timeline line for the order, when the change is worth one. */\n event?: { event: string; detail?: string }\n }\n\nexport type PosPaymentOutcome =\n | { ok: false; status: number; error: string }\n | {\n ok: true\n order: PosLiftedOrder\n payment: CommerceModel.OrderPayment | null\n /** True only on the call whose change completed the sale. */\n completed: boolean\n changed: boolean\n }\n\n/** The open sale's ledger, as the register reads it back after any change. */\nexport function posSaleSummary(order: PosLiftedOrder) {\n const payments = CommerceModel.orderPayments(order)\n const totalCents = Number(order.totals?.totalCents ?? 0)\n return {\n orderId: order.$id,\n status: order.status,\n totalCents,\n paidCents: CommerceModel.posSettledCents(payments),\n dueCents: CommerceModel.posBalanceDueCents(totalCents, payments),\n tenderableCents: CommerceModel.posTenderableCents(totalCents, payments),\n tipCents: CommerceModel.posTipCents(payments),\n payments: payments.map((payment) => ({\n id: payment.id,\n method: payment.method,\n amountCents: payment.amountCents,\n ...(payment.tipCents ? { tipCents: payment.tipCents } : {}),\n status: payment.status,\n ...(payment.cardBrand ? { cardBrand: payment.cardBrand } : {}),\n ...(payment.last4 ? { last4: payment.last4 } : {}),\n ...(payment.changeCents != null ? { changeCents: payment.changeCents } : {}),\n ...(payment.checkoutUrl && payment.status === 'pending'\n ? { checkoutUrl: payment.checkoutUrl }\n : {}),\n ...(payment.readerId ? { readerId: payment.readerId } : {}),\n // What a store-credit payment's provider calls it (AGL-3640).\n ...(payment.creditLabel ? { creditLabel: payment.creditLabel } : {}),\n ...(payment.failureMessage ? { failureMessage: payment.failureMessage } : {}),\n ...(payment.livemode != null ? { livemode: payment.livemode } : {}),\n })),\n }\n}\n\n/**\n * The fields that complete a sale, when its settled payments now cover the\n * total; null when the balance is still open or the sale is not pending.\n *\n * Pure, so the spec can hold the arithmetic: the fee is every card payment's\n * own `application_fee_amount` plus the take the cards did not carry, the tip\n * is summed beside the total and never inside it. Cash and gift-card parts\n * carry no take at all (AGL-4036), so they add nothing to either half.\n */\nexport function posCompletionPatch(\n order: PosLiftedOrder,\n payments: CommerceModel.OrderPayment[],\n nowMs: number,\n): {\n patch: Record<string, unknown>\n invoiceTakeCents: number\n} | null {\n if (order.status !== 'pending') return null\n const totalCents = Number(order.totals?.totalCents ?? 0)\n if (CommerceModel.posBalanceDueCents(totalCents, payments) > 0) return null\n const takeFeeCents = Math.max(0, Math.round(Number(order.posTakeFeeCents ?? 0)))\n const invoiceTakeCents = CommerceModel.posInvoiceTakeCents({ takeFeeCents, totalCents, payments })\n const settled = payments.filter((payment) => payment.status === 'succeeded')\n const cardFeeCents = settled\n .filter((payment) => CommerceModel.isCardPaymentMethod(payment.method))\n .reduce((sum, payment) => sum + Math.max(0, Math.round(Number(payment.feeCents ?? 0))), 0)\n const feeCents = cardFeeCents + invoiceTakeCents\n const tipCents = CommerceModel.posTipCents(payments)\n const intents = settled\n .map((payment) => payment.paymentIntentId)\n .filter((id): id is string => Boolean(id))\n const tenders = settled.map((payment) => CommerceModel.describeOrderPayment(payment))\n const overpaid = CommerceModel.posSettledCents(payments) - totalCents\n return {\n invoiceTakeCents,\n patch: {\n status: 'paid',\n paidAtMs: nowMs,\n totals: {\n ...(order.totals ?? {}),\n feeCents,\n ...(tipCents > 0 ? { tipCents } : {}),\n },\n ...(feeCents > 0 ? { feeCollection: CommerceModel.posFeeCollection(payments) } : {}),\n ...(intents.length ? { paymentIntentIds: intents } : {}),\n // The single-charge readers (refund, dispute lookup) key on this; a\n // sale with one card payment keeps working with every one of them.\n ...(intents.length === 1 ? { paymentIntentId: intents[0] } : {}),\n ...(settled.some((payment) => payment.livemode === false) ? { livemode: false } : {}),\n timeline: CommerceModel.appendOrderEvent(\n order,\n 'paid',\n `Paid — ${tenders.join(', ')}` +\n (overpaid > 0\n ? `. Overpaid by $${(overpaid / 100).toFixed(2)}: refund the difference.`\n : ''),\n nowMs,\n ),\n },\n }\n}\n\n/** The order document, lifted, with its id. */\nfunction liftOrder(id: string, data: unknown): PosLiftedOrder {\n return {\n ...(CommerceModel.liftLegacyOrder((data ?? {}) as any) as any),\n $id: id,\n }\n}\n\n/**\n * The ONE writer of a sale's ledger. Runs `prepare` (extra reads) and\n * `decide` inside one transaction on the order, writes the payment, and\n * completes the sale in the same commit when the balance reaches zero.\n */\nexport async function applyPosPayment<C = undefined>(options: {\n hostId: string\n orderId: string\n paymentId: string\n /** Reads beyond the order (a gift card, a stay), before any write. */\n prepare?: (transaction: any) => Promise<C>\n decide: (sale: {\n order: PosLiftedOrder\n payments: CommerceModel.OrderPayment[]\n existing: CommerceModel.OrderPayment | undefined\n context: C\n }) => PosPaymentStep\n /** Writes beyond the order, in the same transaction, for a `put`. */\n write?: (\n transaction: any,\n context: C,\n payment: CommerceModel.OrderPayment,\n previous: CommerceModel.OrderPayment | undefined,\n ) => void\n nowMs?: number\n}): Promise<PosPaymentOutcome> {\n const firestore = firebaseAdmin.app().firestore()\n const orderRef = firestore\n .collection('hosts')\n .doc(options.hostId)\n .collection('orders')\n .doc(options.orderId)\n const nowMs = options.nowMs ?? Date.now()\n const outcome = await firestore.runTransaction(async (transaction: any) => {\n const snapshot = await transaction.get(orderRef)\n if (!snapshot.exists) {\n return { ok: false as const, status: 404, error: 'Unknown sale' }\n }\n const order = liftOrder(orderRef.id, snapshot.data())\n if (order.channel !== 'pos' || !Array.isArray(order.payments)) {\n return { ok: false as const, status: 409, error: 'This order is not an open register sale' }\n }\n const context = (options.prepare\n ? await options.prepare(transaction)\n : undefined) as C\n const payments = CommerceModel.orderPayments(order)\n const existing = payments.find((payment) => payment.id === options.paymentId)\n const step = options.decide({ order, payments, existing, context })\n if (step.kind === 'refuse') {\n return { ok: false as const, status: step.status, error: step.error }\n }\n if (step.kind === 'keep') {\n return {\n ok: true as const,\n order,\n payment: existing ?? null,\n completed: false,\n changed: false,\n }\n }\n const nextPayments = existing\n ? payments.map((payment) => (payment.id === step.payment.id ? step.payment : payment))\n : [...payments, step.payment]\n let next: PosLiftedOrder = { ...order, payments: nextPayments }\n if (step.event) {\n next = {\n ...next,\n timeline: CommerceModel.appendOrderEvent(\n order,\n step.event.event,\n step.event.detail,\n nowMs,\n ),\n }\n }\n const completion = posCompletionPatch(next, nextPayments, nowMs)\n const write: Record<string, unknown> = {\n payments: nextPayments,\n ...(next.timeline !== order.timeline ? { timeline: next.timeline } : {}),\n }\n if (completion) {\n Object.assign(write, completion.patch)\n next = { ...next, ...(completion.patch as Partial<PosLiftedOrder>) }\n Object.assign(write, CommerceModel.orderListFields(next, orderRef.id))\n // ACCRUED IN THE SAME COMMIT AS THE FLIP (the AGL-2111 rule): the part\n // of the take no card payout carried goes on the org's invoice, and an\n // order and the fee it owes cannot diverge.\n const feeOrgId = String(order.posFeeOrgId ?? '')\n if (completion.invoiceTakeCents > 0 && feeOrgId) {\n const month = offlineFeeMonthKey(new Date(nowMs))\n transaction.set(\n firestore.collection('orgs').doc(feeOrgId).collection('offlineFees').doc(month),\n {\n month,\n feeCents: firebaseAdmin.firestore.FieldValue.increment(completion.invoiceTakeCents),\n orders: firebaseAdmin.firestore.FieldValue.increment(1),\n },\n { merge: true },\n )\n }\n } else if (\n order.status === 'paid' &&\n step.payment.status === 'succeeded' &&\n existing?.status !== 'succeeded'\n ) {\n // MONEY THAT ARRIVED AFTER THE SALE WAS ALREADY PAID: a QR page paid\n // after the cashier took another tender. It is recorded, never\n // dropped, and said on the order so the merchant can refund it.\n write['timeline'] = CommerceModel.appendOrderEvent(\n next,\n 'pos-overpaid',\n `${CommerceModel.describeOrderPayment(step.payment)} arrived after the ` +\n 'sale was already paid. Refund it from Stripe.',\n nowMs,\n )\n }\n transaction.set(orderRef, write, { merge: true })\n options.write?.(transaction, context, step.payment, existing)\n return {\n ok: true as const,\n order: next,\n payment: step.payment,\n completed: Boolean(completion),\n changed: true,\n }\n })\n if (outcome.ok && outcome.completed) {\n await completePosSale(options.hostId, outcome.order)\n }\n return outcome\n}\n\n/*==========================================\n * \"A REGISTER SALE COMPLETED\" — the one point every POS sale passes through\n * (AGL-3607), whichever way it was paid: the ledger's last payment\n * ({@link completePosSale}), a single-tender cash or room sale\n * (`pos-order.ts`), or a legacy QR sale paid through the `commerce-draft`\n * webhook branch. Peripherals (a cloud receipt printer, a cash drawer kick)\n * and anything else that must follow a sale subscribe here rather than\n * patching each path.\n *=========================================*/\n\nexport interface PosSaleCompletedEvent {\n hostId: string\n orderId: string\n order: CommerceModel.HostOrder\n /**\n * Rung while the register was offline and synced later (AGL-3625): the\n * customer has already left, so nothing at the counter should react now.\n */\n offline?: boolean\n}\n\nexport type PosSaleCompletedListener = (event: PosSaleCompletedEvent) => void | Promise<void>\n\nconst saleCompletedListeners = new Set<PosSaleCompletedListener>()\n\n/** Subscribes to completed register sales; returns the unsubscribe. */\nexport function onPosSaleCompleted(listener: PosSaleCompletedListener): () => void {\n saleCompletedListeners.add(listener)\n return () => saleCompletedListeners.delete(listener)\n}\n\n/**\n * Tells every listener a register sale completed. Awaited, and never throws:\n * the money is already taken, so a listener's failure is logged, not\n * returned to a cashier who would ring the sale again.\n */\nexport async function notifyPosSaleCompleted(event: PosSaleCompletedEvent): Promise<void> {\n for (const listener of [...saleCompletedListeners]) {\n try {\n await listener(event)\n } catch (error) {\n console.error('[pos-sale] sale-completed listener failed', event.orderId, error)\n }\n }\n}\n\n/** Reads the sale as it stands, for the register's status polls. */\nexport async function readPosSale(\n hostId: string,\n orderId: string,\n): Promise<PosLiftedOrder | null> {\n const snapshot = await firebaseAdmin\n .app()\n .firestore()\n .collection('hosts')\n .doc(hostId)\n .collection('orders')\n .doc(orderId)\n .get()\n if (!snapshot.exists) return null\n return liftOrder(snapshot.id, snapshot.data())\n}\n\n/**\n * Everything that follows a sale being paid, run once by the call whose\n * commit completed it. Each step is guarded on its own and none can undo the\n * sale: the money is taken, so a failure here is logged and said on the order\n * rather than thrown back at a cashier who would ring it again.\n */\nexport async function completePosSale(\n hostId: string,\n order: PosLiftedOrder,\n): Promise<void> {\n const firestore = firebaseAdmin.app().firestore()\n const hostRef = firestore.collection('hosts').doc(hostId)\n const orderRef = hostRef.collection('orders').doc(order.$id)\n const notes: Array<{ event: string; detail: string }> = []\n\n // The promotion's slot becomes a redemption only now: a sale that was\n // voided half-paid never counted against the merchant's cap (AGL-305).\n if (order.discountId && order.discountHoldKey) {\n const settled = await settlePromotionSlot({\n firestore,\n ref: hostRef.collection('discounts').doc(order.discountId),\n holdKey: order.discountHoldKey,\n label: `pos discount ${order.discountId}`,\n })\n if (settled === 'missing' || settled === 'error') {\n notes.push({\n event: 'redemption-orphaned',\n detail:\n `Discount ${order.discountId} was applied to this sale but its ` +\n 'redemption could not be counted against its limit.',\n })\n }\n }\n\n // Stock comes off exactly once, here, compounding across lines of one\n // product (AGL-1828) and atomically against other channels (AGL-2320).\n //\n // Except for a sale rung OFFLINE (AGL-3625): the customer left with the\n // goods, so the offline sync took the stock when it recorded the sale,\n // paid or not. One whose card failed and is collected later at the\n // register (AGL-4039) completes here, and must not take it a second time.\n const products = new Map<string, CommerceModel.HostProduct>()\n for (const line of order.offline ? [] : order.lineItems ?? []) {\n try {\n if (!products.has(line.productId)) {\n const snapshot = await hostRef.collection('products').doc(line.productId).get()\n if (!snapshot.exists) continue\n products.set(line.productId, CommerceModel.liftLegacyProduct(snapshot.data() as any))\n }\n const product = products.get(line.productId) as CommerceModel.HostProduct\n const variantId = line.variantId ?? product.variants[0]?.id\n const tracked = product.variants.some(\n (variant) => variant.id === variantId && variant.inventory != null,\n )\n if (!variantId || !tracked) continue\n const moved = await decrementVariantStock({\n firestore,\n hostRef,\n hostId,\n productId: line.productId,\n variantId,\n quantity: line.quantity,\n locationId: order.locationId || undefined,\n ledger: { reason: 'sale', orderId: order.$id },\n })\n if (!moved.before || !moved.after) continue\n products.set(line.productId, moved.after)\n alertLowStockCrossing(hostId, moved.before, moved.after)\n } catch (error) {\n console.error('[pos-sale] stock decrement failed', order.$id, line.productId, error)\n }\n }\n\n const receipt = order.receiptRequest\n const receiptEmail = receipt?.channel === 'email' ? String(receipt.to ?? '') : ''\n const contactEmail = receiptEmail || String(order.customerEmail ?? '')\n const marketingOptIn = Boolean((receipt as { marketingOptIn?: boolean } | undefined)?.marketingOptIn)\n const totalCents = Number(order.totals?.totalCents ?? 0)\n if (contactEmail) {\n await recordCapturedContact({\n orgId: '',\n hostId,\n identity: { email: contactEmail },\n surface: 'relationship',\n lifecycleFloor: 'customer',\n // The customer's own tick on the display, the same opt-in the online\n // checkout records (AGL-3608); an unticked box records nothing.\n ...(marketingOptIn ? { marketingConsent: true } : {}),\n purchaseCents: totalCents,\n interaction: {\n source: 'order',\n refId: order.$id,\n summary: `In-store purchase ($${(totalCents / 100).toFixed(2)})`,\n },\n }).catch((error: unknown) => {\n console.error('[pos-sale] contact capture failed', error)\n })\n }\n\n // The receipt and the paid event, through the same doors every sale uses\n // (AGL-3610, AGL-3611): the buyer-notification door claims each message\n // per channel, so a second completion path can never mail twice, and it\n // texts the receipt when the customer chose a text and a provider is on.\n if ((receipt?.channel === 'email' || receipt?.channel === 'sms') && receipt.to) {\n // The customer named where it goes: it goes there, whatever else the\n // order holds (AGL-3608).\n const sent = await deliverChosenPosReceipt(\n { hostId, orderId: order.$id },\n { channel: receipt.channel, to: receipt.to, orderEmail: String(order.customerEmail ?? '') },\n )\n if (sent !== 'sent') {\n notes.push({\n event: 'receipt-unsent',\n detail: `The ${receipt.channel === 'sms' ? 'text' : 'email'} receipt could not be sent.`,\n })\n }\n } else if (contactEmail) {\n await notifyOrderBuyer({ hostId, orderId: order.$id }, 'receipt', { email: contactEmail })\n }\n await raiseOrderEvent(ORDER_PAID_EVENT, { hostId, orderId: order.$id, key: 'paid' }).catch(\n (error: unknown) => console.error('[pos-sale] order.paid event failed', error),\n )\n\n if (notes.length) {\n await firestore\n .runTransaction(async (transaction: any) => {\n const fresh = liftOrder(orderRef.id, (await transaction.get(orderRef)).data())\n let timeline = fresh.timeline ?? []\n for (const note of notes) {\n timeline = CommerceModel.appendOrderEvent({ timeline }, note.event, note.detail)\n }\n transaction.set(orderRef, { timeline }, { merge: true })\n })\n .catch((error: unknown) => console.error('[pos-sale] note failed', error))\n }\n\n await notifyPosSaleCompleted({ hostId, orderId: order.$id, order })\n\n // The customer screen says thank you and forgets the customer: the state\n // is rewritten whole, so no address or phone outlives the sale (AGL-3608).\n if (order.registerId) {\n await resetPosDisplay(hostId, order.registerId).catch((error: unknown) =>\n console.error('[pos-sale] display reset failed', error),\n )\n }\n}\n\n/**\n * Sends a receipt the customer (or the cashier for them) explicitly asked\n * for, to the address or number they gave (AGL-3607, AGL-3608).\n *\n * It goes through the buyer-notification door first, so the order's\n * once-per-channel marker is claimed and a completion that races this call\n * cannot send a second copy. The door can skip it, though, for reasons that\n * do not apply to a request made at the counter: the store switched\n * automatic receipts or texts off, a receipt already went out on that\n * channel to an earlier address, or the door would use the email the order\n * was opened with rather than the one just typed. In each of those cases the\n * receipt is sent explicitly, as the order dialog's \"Resend receipt\" does.\n */\nexport async function deliverChosenPosReceipt(\n ref: { hostId: string; orderId: string },\n input: { channel: 'email' | 'sms'; to: string; orderEmail?: string },\n): Promise<'sent' | 'failed' | 'not_configured'> {\n const orderEmail = String(input.orderEmail ?? '').trim().toLowerCase()\n const to = input.to.trim()\n const doorAddressesIt = input.channel === 'sms' || !orderEmail || orderEmail === to.toLowerCase()\n if (doorAddressesIt) {\n const door = await notifyOrderBuyer(ref, 'receipt', input.channel === 'email' ? { email: to } : {})\n const entry =\n door.outcome === 'handled'\n ? door.channels.find((channel) => channel.channel === input.channel)\n : undefined\n if (entry?.outcome === 'sent') return 'sent'\n if (entry?.outcome === 'failed') return 'failed'\n // Already sent to this very address: nothing more to do.\n if (entry?.outcome === 'already' && input.channel === 'email') return 'sent'\n }\n const explicit = await sendOrderReceipt(ref, { channel: input.channel, to })\n if (explicit.outcome === 'sent') return 'sent'\n return explicit.outcome === 'not_configured' ? 'not_configured' : 'failed'\n}\n\n/**\n * Hands back a promotion slot an open sale was holding, when the sale is\n * voided rather than paid.\n */\nexport async function releasePosSaleDiscount(\n hostId: string,\n order: PosLiftedOrder,\n): Promise<void> {\n if (!order.discountId || !order.discountHoldKey) return\n await releasePromotionHold(\n firebaseAdmin\n .app()\n .firestore()\n .collection('hosts')\n .doc(hostId)\n .collection('discounts')\n .doc(order.discountId),\n order.discountHoldKey,\n )\n}\n"],"names":["createHash","firebaseAdmin","recordCapturedContact","CommerceModel","alertLowStockCrossing","decrementVariantStock","releasePromotionHold","settlePromotionSlot","offlineFeeMonthKey","resetPosDisplay","notifyOrderBuyer","sendOrderReceipt","raiseOrderEvent","ORDER_PAID_EVENT","posPaymentId","orderId","attemptKey","update","digest","slice","posSaleSummary","order","payments","orderPayments","totalCents","Number","totals","$id","status","paidCents","posSettledCents","dueCents","posBalanceDueCents","tenderableCents","posTenderableCents","tipCents","posTipCents","map","payment","id","method","amountCents","cardBrand","last4","changeCents","checkoutUrl","readerId","creditLabel","failureMessage","livemode","posCompletionPatch","nowMs","takeFeeCents","Math","max","round","posTakeFeeCents","invoiceTakeCents","posInvoiceTakeCents","settled","filter","cardFeeCents","isCardPaymentMethod","reduce","sum","feeCents","intents","paymentIntentId","Boolean","tenders","describeOrderPayment","overpaid","patch","paidAtMs","feeCollection","posFeeCollection","length","paymentIntentIds","some","timeline","appendOrderEvent","join","toFixed","liftOrder","data","liftLegacyOrder","applyPosPayment","options","firestore","app","orderRef","collection","doc","hostId","Date","now","outcome","runTransaction","transaction","snapshot","get","exists","ok","error","channel","Array","isArray","context","prepare","undefined","existing","find","paymentId","step","decide","kind","completed","changed","nextPayments","next","event","detail","completion","write","Object","assign","orderListFields","feeOrgId","String","posFeeOrgId","month","set","FieldValue","increment","orders","merge","completePosSale","saleCompletedListeners","Set","onPosSaleCompleted","listener","add","delete","notifyPosSaleCompleted","console","readPosSale","receipt","hostRef","notes","discountId","discountHoldKey","ref","holdKey","label","push","products","Map","line","offline","lineItems","product","has","productId","liftLegacyProduct","variantId","variants","tracked","variant","inventory","moved","quantity","locationId","ledger","reason","before","after","receiptRequest","receiptEmail","to","contactEmail","customerEmail","marketingOptIn","orgId","identity","email","surface","lifecycleFloor","marketingConsent","purchaseCents","interaction","source","refId","summary","catch","sent","deliverChosenPosReceipt","orderEmail","key","fresh","note","registerId","input","trim","toLowerCase","doorAddressesIt","door","entry","channels","explicit","releasePosSaleDiscount"],"mappings":"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"}
@@ -17,6 +17,7 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
17
17
  */ import { createResourceUid } from "@aglyn/aglyn/app-utils/create-resource-uid";
18
18
  import { computePosShiftReport, posShiftPrintReport, posCashVarianceCents } from "../model/commerce-pos-ops.js";
19
19
  import { authorizePosOps, defaultPosOpsDeps, posOpsBody, posOpsCleanId, readPosRegister, resolvePosCashier } from "./pos-ops-gate.js";
20
+ import { holdsPosPermission, posPermissionRefusal } from "../model/plugin-permissions.js";
20
21
  /*==========================================
21
22
  * SHIFTS AND THE CASH DRAWER (AGL-3609): `POST /api/commerce/pos-shift`.
22
23
  *
@@ -119,6 +120,16 @@ export async function handlePosShift(deps, req) {
119
120
  const registerId = register.ref.id;
120
121
  const { cashierId } = await resolvePosCashier(deps, staff, registerId, body['cashierAssertion']);
121
122
  const action = String((_body_action = body['action']) != null ? _body_action : '');
123
+ // Opening and closing a shift, cash in and out and the shift's reports are
124
+ // the cash drawer's (AGL-4047); which shift is open is the register's.
125
+ if (action !== 'current' && !holdsPosPermission(staff.membership.permissions, 'posCashDrawer')) {
126
+ return {
127
+ status: 403,
128
+ body: {
129
+ error: posPermissionRefusal('posCashDrawer')
130
+ }
131
+ };
132
+ }
122
133
  const firestore = deps.firestore();
123
134
  const shifts = register.ref.collection('shifts');
124
135
  switch(action){