@aglyn/plugins-commerce 1.0.0-beta.143

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 (417) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +10 -0
  3. package/package.json +57 -0
  4. package/src/index.d.ts +38 -0
  5. package/src/index.js +38 -0
  6. package/src/index.js.map +1 -0
  7. package/src/lib/components/account.d.ts +31 -0
  8. package/src/lib/components/account.js +645 -0
  9. package/src/lib/components/account.js.map +1 -0
  10. package/src/lib/components/cart.d.ts +38 -0
  11. package/src/lib/components/cart.js +851 -0
  12. package/src/lib/components/cart.js.map +1 -0
  13. package/src/lib/components/commerce-console-page.d.ts +32 -0
  14. package/src/lib/components/commerce-console-page.js +296 -0
  15. package/src/lib/components/commerce-console-page.js.map +1 -0
  16. package/src/lib/components/commerce-console-sections.d.ts +34 -0
  17. package/src/lib/components/commerce-console-sections.js +62 -0
  18. package/src/lib/components/commerce-console-sections.js.map +1 -0
  19. package/src/lib/components/console/catalog-organization-card.component.d.ts +14 -0
  20. package/src/lib/components/console/catalog-organization-card.component.js +1087 -0
  21. package/src/lib/components/console/catalog-organization-card.component.js.map +1 -0
  22. package/src/lib/components/console/commerce-analytics-card.component.d.ts +27 -0
  23. package/src/lib/components/console/commerce-analytics-card.component.js +310 -0
  24. package/src/lib/components/console/commerce-analytics-card.component.js.map +1 -0
  25. package/src/lib/components/console/commerce-glance-card.component.d.ts +20 -0
  26. package/src/lib/components/console/commerce-glance-card.component.js +340 -0
  27. package/src/lib/components/console/commerce-glance-card.component.js.map +1 -0
  28. package/src/lib/components/console/commerce-stat-tile.component.d.ts +37 -0
  29. package/src/lib/components/console/commerce-stat-tile.component.js +72 -0
  30. package/src/lib/components/console/commerce-stat-tile.component.js.map +1 -0
  31. package/src/lib/components/console/discounts-card.component.d.ts +14 -0
  32. package/src/lib/components/console/discounts-card.component.js +443 -0
  33. package/src/lib/components/console/discounts-card.component.js.map +1 -0
  34. package/src/lib/components/console/entitlement-gate.component.d.ts +76 -0
  35. package/src/lib/components/console/entitlement-gate.component.js +115 -0
  36. package/src/lib/components/console/entitlement-gate.component.js.map +1 -0
  37. package/src/lib/components/console/gift-cards-card.component.d.ts +29 -0
  38. package/src/lib/components/console/gift-cards-card.component.js +379 -0
  39. package/src/lib/components/console/gift-cards-card.component.js.map +1 -0
  40. package/src/lib/components/console/host-coupons-card.component.d.ts +14 -0
  41. package/src/lib/components/console/host-coupons-card.component.js +252 -0
  42. package/src/lib/components/console/host-coupons-card.component.js.map +1 -0
  43. package/src/lib/components/console/host-orders-card.component.d.ts +13 -0
  44. package/src/lib/components/console/host-orders-card.component.js +861 -0
  45. package/src/lib/components/console/host-orders-card.component.js.map +1 -0
  46. package/src/lib/components/console/locations-card.component.d.ts +14 -0
  47. package/src/lib/components/console/locations-card.component.js +256 -0
  48. package/src/lib/components/console/locations-card.component.js.map +1 -0
  49. package/src/lib/components/console/member-posts-card.component.d.ts +8 -0
  50. package/src/lib/components/console/member-posts-card.component.js +283 -0
  51. package/src/lib/components/console/member-posts-card.component.js.map +1 -0
  52. package/src/lib/components/console/newest-site-users-card.component.d.ts +36 -0
  53. package/src/lib/components/console/newest-site-users-card.component.js +126 -0
  54. package/src/lib/components/console/newest-site-users-card.component.js.map +1 -0
  55. package/src/lib/components/console/order-detail-dialog.component.d.ts +28 -0
  56. package/src/lib/components/console/order-detail-dialog.component.js +976 -0
  57. package/src/lib/components/console/order-detail-dialog.component.js.map +1 -0
  58. package/src/lib/components/console/paid-media.d.ts +127 -0
  59. package/src/lib/components/console/paid-media.js +397 -0
  60. package/src/lib/components/console/paid-media.js.map +1 -0
  61. package/src/lib/components/console/payments-settings-card.component.d.ts +13 -0
  62. package/src/lib/components/console/payments-settings-card.component.js +295 -0
  63. package/src/lib/components/console/payments-settings-card.component.js.map +1 -0
  64. package/src/lib/components/console/pos-page.component.d.ts +13 -0
  65. package/src/lib/components/console/pos-page.component.js +916 -0
  66. package/src/lib/components/console/pos-page.component.js.map +1 -0
  67. package/src/lib/components/console/product-editor-dialog.component.d.ts +32 -0
  68. package/src/lib/components/console/product-editor-dialog.component.js +1374 -0
  69. package/src/lib/components/console/product-editor-dialog.component.js.map +1 -0
  70. package/src/lib/components/console/products-hub-card.component.d.ts +16 -0
  71. package/src/lib/components/console/products-hub-card.component.js +1280 -0
  72. package/src/lib/components/console/products-hub-card.component.js.map +1 -0
  73. package/src/lib/components/console/products-hub-zone.component.d.ts +50 -0
  74. package/src/lib/components/console/products-hub-zone.component.js +200 -0
  75. package/src/lib/components/console/products-hub-zone.component.js.map +1 -0
  76. package/src/lib/components/console/recovery-queue-card.component.d.ts +39 -0
  77. package/src/lib/components/console/recovery-queue-card.component.js +262 -0
  78. package/src/lib/components/console/recovery-queue-card.component.js.map +1 -0
  79. package/src/lib/components/console/registers-card.component.d.ts +21 -0
  80. package/src/lib/components/console/registers-card.component.js +296 -0
  81. package/src/lib/components/console/registers-card.component.js.map +1 -0
  82. package/src/lib/components/console/reservations-card.component.d.ts +14 -0
  83. package/src/lib/components/console/reservations-card.component.js +650 -0
  84. package/src/lib/components/console/reservations-card.component.js.map +1 -0
  85. package/src/lib/components/console/reviews-moderation-card.component.d.ts +8 -0
  86. package/src/lib/components/console/reviews-moderation-card.component.js +235 -0
  87. package/src/lib/components/console/reviews-moderation-card.component.js.map +1 -0
  88. package/src/lib/components/console/shipping-settings-card.component.d.ts +38 -0
  89. package/src/lib/components/console/shipping-settings-card.component.js +560 -0
  90. package/src/lib/components/console/shipping-settings-card.component.js.map +1 -0
  91. package/src/lib/components/console/stock-movements-card.component.d.ts +31 -0
  92. package/src/lib/components/console/stock-movements-card.component.js +333 -0
  93. package/src/lib/components/console/stock-movements-card.component.js.map +1 -0
  94. package/src/lib/components/console/store-settings-card.component.d.ts +14 -0
  95. package/src/lib/components/console/store-settings-card.component.js +300 -0
  96. package/src/lib/components/console/store-settings-card.component.js.map +1 -0
  97. package/src/lib/components/console/storefront-tax-summary-card.component.d.ts +73 -0
  98. package/src/lib/components/console/storefront-tax-summary-card.component.js +408 -0
  99. package/src/lib/components/console/storefront-tax-summary-card.component.js.map +1 -0
  100. package/src/lib/components/console/suppliers-card.component.d.ts +8 -0
  101. package/src/lib/components/console/suppliers-card.component.js +328 -0
  102. package/src/lib/components/console/suppliers-card.component.js.map +1 -0
  103. package/src/lib/components/console/tax-settings-card.component.d.ts +14 -0
  104. package/src/lib/components/console/tax-settings-card.component.js +473 -0
  105. package/src/lib/components/console/tax-settings-card.component.js.map +1 -0
  106. package/src/lib/components/gate.d.ts +39 -0
  107. package/src/lib/components/gate.js +202 -0
  108. package/src/lib/components/gate.js.map +1 -0
  109. package/src/lib/components/gated-video.d.ts +40 -0
  110. package/src/lib/components/gated-video.js +366 -0
  111. package/src/lib/components/gated-video.js.map +1 -0
  112. package/src/lib/components/member-feed.d.ts +32 -0
  113. package/src/lib/components/member-feed.js +198 -0
  114. package/src/lib/components/member-feed.js.map +1 -0
  115. package/src/lib/components/member-recovery.d.ts +35 -0
  116. package/src/lib/components/member-recovery.js +313 -0
  117. package/src/lib/components/member-recovery.js.map +1 -0
  118. package/src/lib/components/member-signin.d.ts +35 -0
  119. package/src/lib/components/member-signin.js +257 -0
  120. package/src/lib/components/member-signin.js.map +1 -0
  121. package/src/lib/components/member-signup.d.ts +34 -0
  122. package/src/lib/components/member-signup.js +287 -0
  123. package/src/lib/components/member-signup.js.map +1 -0
  124. package/src/lib/components/newsletter-signup.d.ts +39 -0
  125. package/src/lib/components/newsletter-signup.js +229 -0
  126. package/src/lib/components/newsletter-signup.js.map +1 -0
  127. package/src/lib/components/product-detail.d.ts +38 -0
  128. package/src/lib/components/product-detail.js +1022 -0
  129. package/src/lib/components/product-detail.js.map +1 -0
  130. package/src/lib/components/product-grid.d.ts +67 -0
  131. package/src/lib/components/product-grid.js +909 -0
  132. package/src/lib/components/product-grid.js.map +1 -0
  133. package/src/lib/components/product-reviews.d.ts +32 -0
  134. package/src/lib/components/product-reviews.js +349 -0
  135. package/src/lib/components/product-reviews.js.map +1 -0
  136. package/src/lib/components/related-products.d.ts +33 -0
  137. package/src/lib/components/related-products.js +232 -0
  138. package/src/lib/components/related-products.js.map +1 -0
  139. package/src/lib/components/reservation-widget.d.ts +33 -0
  140. package/src/lib/components/reservation-widget.js +418 -0
  141. package/src/lib/components/reservation-widget.js.map +1 -0
  142. package/src/lib/components/storefront-payment-element-fallback.d.ts +18 -0
  143. package/src/lib/components/storefront-payment-element-fallback.js +51 -0
  144. package/src/lib/components/storefront-payment-element-fallback.js.map +1 -0
  145. package/src/lib/components/storefront-payment-element.d.ts +78 -0
  146. package/src/lib/components/storefront-payment-element.js +156 -0
  147. package/src/lib/components/storefront-payment-element.js.map +1 -0
  148. package/src/lib/components/wishlist.d.ts +46 -0
  149. package/src/lib/components/wishlist.js +304 -0
  150. package/src/lib/components/wishlist.js.map +1 -0
  151. package/src/lib/constants/bundle-common.d.ts +18 -0
  152. package/src/lib/constants/bundle-common.js +18 -0
  153. package/src/lib/constants/bundle-common.js.map +1 -0
  154. package/src/lib/constants/product-filters.d.ts +35 -0
  155. package/src/lib/constants/product-filters.js +109 -0
  156. package/src/lib/constants/product-filters.js.map +1 -0
  157. package/src/lib/model/commerce-cart.d.ts +52 -0
  158. package/src/lib/model/commerce-cart.js +102 -0
  159. package/src/lib/model/commerce-cart.js.map +1 -0
  160. package/src/lib/model/commerce-connect-transfer.d.ts +243 -0
  161. package/src/lib/model/commerce-connect-transfer.js +231 -0
  162. package/src/lib/model/commerce-connect-transfer.js.map +1 -0
  163. package/src/lib/model/commerce-discounts.d.ts +164 -0
  164. package/src/lib/model/commerce-discounts.js +231 -0
  165. package/src/lib/model/commerce-discounts.js.map +1 -0
  166. package/src/lib/model/commerce-dispute.d.ts +124 -0
  167. package/src/lib/model/commerce-dispute.js +225 -0
  168. package/src/lib/model/commerce-dispute.js.map +1 -0
  169. package/src/lib/model/commerce-gift-cards.d.ts +107 -0
  170. package/src/lib/model/commerce-gift-cards.js +121 -0
  171. package/src/lib/model/commerce-gift-cards.js.map +1 -0
  172. package/src/lib/model/commerce-io.d.ts +36 -0
  173. package/src/lib/model/commerce-io.js +245 -0
  174. package/src/lib/model/commerce-io.js.map +1 -0
  175. package/src/lib/model/commerce-orders.d.ts +1040 -0
  176. package/src/lib/model/commerce-orders.js +1022 -0
  177. package/src/lib/model/commerce-orders.js.map +1 -0
  178. package/src/lib/model/commerce-promotions.d.ts +188 -0
  179. package/src/lib/model/commerce-promotions.js +199 -0
  180. package/src/lib/model/commerce-promotions.js.map +1 -0
  181. package/src/lib/model/commerce-reservations.d.ts +175 -0
  182. package/src/lib/model/commerce-reservations.js +157 -0
  183. package/src/lib/model/commerce-reservations.js.map +1 -0
  184. package/src/lib/model/commerce-shipping.d.ts +316 -0
  185. package/src/lib/model/commerce-shipping.js +484 -0
  186. package/src/lib/model/commerce-shipping.js.map +1 -0
  187. package/src/lib/model/commerce-stock-holds.d.ts +199 -0
  188. package/src/lib/model/commerce-stock-holds.js +190 -0
  189. package/src/lib/model/commerce-stock-holds.js.map +1 -0
  190. package/src/lib/model/commerce-subscription-status.d.ts +67 -0
  191. package/src/lib/model/commerce-subscription-status.js +76 -0
  192. package/src/lib/model/commerce-subscription-status.js.map +1 -0
  193. package/src/lib/model/commerce-tax-decision.d.ts +222 -0
  194. package/src/lib/model/commerce-tax-decision.js +165 -0
  195. package/src/lib/model/commerce-tax-decision.js.map +1 -0
  196. package/src/lib/model/commerce-tax.d.ts +176 -0
  197. package/src/lib/model/commerce-tax.js +92 -0
  198. package/src/lib/model/commerce-tax.js.map +1 -0
  199. package/src/lib/model/commerce.d.ts +551 -0
  200. package/src/lib/model/commerce.js +739 -0
  201. package/src/lib/model/commerce.js.map +1 -0
  202. package/src/lib/model/index.d.ts +40 -0
  203. package/src/lib/model/index.js +40 -0
  204. package/src/lib/model/index.js.map +1 -0
  205. package/src/lib/model/order-figures.d.ts +48 -0
  206. package/src/lib/model/order-figures.js +74 -0
  207. package/src/lib/model/order-figures.js.map +1 -0
  208. package/src/lib/model/plugin-permissions.d.ts +23 -0
  209. package/src/lib/model/plugin-permissions.js +34 -0
  210. package/src/lib/model/plugin-permissions.js.map +1 -0
  211. package/src/lib/model/purchase-analytics.d.ts +186 -0
  212. package/src/lib/model/purchase-analytics.js +216 -0
  213. package/src/lib/model/purchase-analytics.js.map +1 -0
  214. package/src/lib/plugin-config.d.ts +62 -0
  215. package/src/lib/plugin-config.js +78 -0
  216. package/src/lib/plugin-config.js.map +1 -0
  217. package/src/lib/plugin.d.ts +28 -0
  218. package/src/lib/plugin.js +147 -0
  219. package/src/lib/plugin.js.map +1 -0
  220. package/src/lib/server/billing-webhook.d.ts +26 -0
  221. package/src/lib/server/billing-webhook.js +4011 -0
  222. package/src/lib/server/billing-webhook.js.map +1 -0
  223. package/src/lib/server/cancel-order.d.ts +87 -0
  224. package/src/lib/server/cancel-order.js +368 -0
  225. package/src/lib/server/cancel-order.js.map +1 -0
  226. package/src/lib/server/cart-checkout.d.ts +25 -0
  227. package/src/lib/server/cart-checkout.js +976 -0
  228. package/src/lib/server/cart-checkout.js.map +1 -0
  229. package/src/lib/server/cart-cookie.d.ts +32 -0
  230. package/src/lib/server/cart-cookie.js +77 -0
  231. package/src/lib/server/cart-cookie.js.map +1 -0
  232. package/src/lib/server/cart.d.ts +34 -0
  233. package/src/lib/server/cart.js +181 -0
  234. package/src/lib/server/cart.js.map +1 -0
  235. package/src/lib/server/catalog.d.ts +127 -0
  236. package/src/lib/server/catalog.js +277 -0
  237. package/src/lib/server/catalog.js.map +1 -0
  238. package/src/lib/server/checkout.d.ts +36 -0
  239. package/src/lib/server/checkout.js +915 -0
  240. package/src/lib/server/checkout.js.map +1 -0
  241. package/src/lib/server/connect.d.ts +26 -0
  242. package/src/lib/server/connect.js +238 -0
  243. package/src/lib/server/connect.js.map +1 -0
  244. package/src/lib/server/contact-refund.d.ts +117 -0
  245. package/src/lib/server/contact-refund.js +196 -0
  246. package/src/lib/server/contact-refund.js.map +1 -0
  247. package/src/lib/server/download.d.ts +39 -0
  248. package/src/lib/server/download.js +206 -0
  249. package/src/lib/server/download.js.map +1 -0
  250. package/src/lib/server/draft-order.d.ts +26 -0
  251. package/src/lib/server/draft-order.js +706 -0
  252. package/src/lib/server/draft-order.js.map +1 -0
  253. package/src/lib/server/feed.d.ts +24 -0
  254. package/src/lib/server/feed.js +59 -0
  255. package/src/lib/server/feed.js.map +1 -0
  256. package/src/lib/server/fulfill-order.d.ts +97 -0
  257. package/src/lib/server/fulfill-order.js +235 -0
  258. package/src/lib/server/fulfill-order.js.map +1 -0
  259. package/src/lib/server/gate.d.ts +36 -0
  260. package/src/lib/server/gate.js +112 -0
  261. package/src/lib/server/gate.js.map +1 -0
  262. package/src/lib/server/gift-cards.d.ts +42 -0
  263. package/src/lib/server/gift-cards.js +219 -0
  264. package/src/lib/server/gift-cards.js.map +1 -0
  265. package/src/lib/server/low-stock.d.ts +49 -0
  266. package/src/lib/server/low-stock.js +60 -0
  267. package/src/lib/server/low-stock.js.map +1 -0
  268. package/src/lib/server/manual-tax-rate.d.ts +82 -0
  269. package/src/lib/server/manual-tax-rate.js +113 -0
  270. package/src/lib/server/manual-tax-rate.js.map +1 -0
  271. package/src/lib/server/member-feed.d.ts +24 -0
  272. package/src/lib/server/member-feed.js +72 -0
  273. package/src/lib/server/member-feed.js.map +1 -0
  274. package/src/lib/server/member-name-search.d.ts +37 -0
  275. package/src/lib/server/member-name-search.js +42 -0
  276. package/src/lib/server/member-name-search.js.map +1 -0
  277. package/src/lib/server/member-post.d.ts +23 -0
  278. package/src/lib/server/member-post.js +166 -0
  279. package/src/lib/server/member-post.js.map +1 -0
  280. package/src/lib/server/membership-account.d.ts +37 -0
  281. package/src/lib/server/membership-account.js +148 -0
  282. package/src/lib/server/membership-account.js.map +1 -0
  283. package/src/lib/server/membership-admin-password.d.ts +33 -0
  284. package/src/lib/server/membership-admin-password.js +202 -0
  285. package/src/lib/server/membership-admin-password.js.map +1 -0
  286. package/src/lib/server/membership-content.d.ts +23 -0
  287. package/src/lib/server/membership-content.js +105 -0
  288. package/src/lib/server/membership-content.js.map +1 -0
  289. package/src/lib/server/membership-login.d.ts +19 -0
  290. package/src/lib/server/membership-login.js +137 -0
  291. package/src/lib/server/membership-login.js.map +1 -0
  292. package/src/lib/server/membership-logout.d.ts +19 -0
  293. package/src/lib/server/membership-logout.js +35 -0
  294. package/src/lib/server/membership-logout.js.map +1 -0
  295. package/src/lib/server/membership-recover.d.ts +60 -0
  296. package/src/lib/server/membership-recover.js +244 -0
  297. package/src/lib/server/membership-recover.js.map +1 -0
  298. package/src/lib/server/membership-register.d.ts +22 -0
  299. package/src/lib/server/membership-register.js +241 -0
  300. package/src/lib/server/membership-register.js.map +1 -0
  301. package/src/lib/server/membership-reset.d.ts +26 -0
  302. package/src/lib/server/membership-reset.js +88 -0
  303. package/src/lib/server/membership-reset.js.map +1 -0
  304. package/src/lib/server/membership-wishlist.d.ts +23 -0
  305. package/src/lib/server/membership-wishlist.js +89 -0
  306. package/src/lib/server/membership-wishlist.js.map +1 -0
  307. package/src/lib/server/membership.d.ts +96 -0
  308. package/src/lib/server/membership.js +222 -0
  309. package/src/lib/server/membership.js.map +1 -0
  310. package/src/lib/server/native-checkout.d.ts +170 -0
  311. package/src/lib/server/native-checkout.js +193 -0
  312. package/src/lib/server/native-checkout.js.map +1 -0
  313. package/src/lib/server/newsletter.d.ts +23 -0
  314. package/src/lib/server/newsletter.js +323 -0
  315. package/src/lib/server/newsletter.js.map +1 -0
  316. package/src/lib/server/notify-restock.d.ts +22 -0
  317. package/src/lib/server/notify-restock.js +84 -0
  318. package/src/lib/server/notify-restock.js.map +1 -0
  319. package/src/lib/server/order-analytics.d.ts +134 -0
  320. package/src/lib/server/order-analytics.js +263 -0
  321. package/src/lib/server/order-analytics.js.map +1 -0
  322. package/src/lib/server/order-figures.d.ts +33 -0
  323. package/src/lib/server/order-figures.js +220 -0
  324. package/src/lib/server/order-figures.js.map +1 -0
  325. package/src/lib/server/paid-media-delivery.d.ts +173 -0
  326. package/src/lib/server/paid-media-delivery.js +212 -0
  327. package/src/lib/server/paid-media-delivery.js.map +1 -0
  328. package/src/lib/server/pos-order.d.ts +54 -0
  329. package/src/lib/server/pos-order.js +1137 -0
  330. package/src/lib/server/pos-order.js.map +1 -0
  331. package/src/lib/server/process-abandoned.d.ts +54 -0
  332. package/src/lib/server/process-abandoned.js +222 -0
  333. package/src/lib/server/process-abandoned.js.map +1 -0
  334. package/src/lib/server/process-restock.d.ts +42 -0
  335. package/src/lib/server/process-restock.js +219 -0
  336. package/src/lib/server/process-restock.js.map +1 -0
  337. package/src/lib/server/product-card.d.ts +29 -0
  338. package/src/lib/server/product-card.js +54 -0
  339. package/src/lib/server/product-card.js.map +1 -0
  340. package/src/lib/server/product.d.ts +70 -0
  341. package/src/lib/server/product.js +105 -0
  342. package/src/lib/server/product.js.map +1 -0
  343. package/src/lib/server/promotion-hold.d.ts +144 -0
  344. package/src/lib/server/promotion-hold.js +174 -0
  345. package/src/lib/server/promotion-hold.js.map +1 -0
  346. package/src/lib/server/reconcile-stock.d.ts +106 -0
  347. package/src/lib/server/reconcile-stock.js +349 -0
  348. package/src/lib/server/reconcile-stock.js.map +1 -0
  349. package/src/lib/server/refund.d.ts +45 -0
  350. package/src/lib/server/refund.js +607 -0
  351. package/src/lib/server/refund.js.map +1 -0
  352. package/src/lib/server/related.d.ts +24 -0
  353. package/src/lib/server/related.js +104 -0
  354. package/src/lib/server/related.js.map +1 -0
  355. package/src/lib/server/reservation-availability.d.ts +23 -0
  356. package/src/lib/server/reservation-availability.js +111 -0
  357. package/src/lib/server/reservation-availability.js.map +1 -0
  358. package/src/lib/server/reserve-stock.d.ts +156 -0
  359. package/src/lib/server/reserve-stock.js +146 -0
  360. package/src/lib/server/reserve-stock.js.map +1 -0
  361. package/src/lib/server/reserve.d.ts +25 -0
  362. package/src/lib/server/reserve.js +426 -0
  363. package/src/lib/server/reserve.js.map +1 -0
  364. package/src/lib/server/restock-flag.d.ts +202 -0
  365. package/src/lib/server/restock-flag.js +449 -0
  366. package/src/lib/server/restock-flag.js.map +1 -0
  367. package/src/lib/server/reviews.d.ts +51 -0
  368. package/src/lib/server/reviews.js +132 -0
  369. package/src/lib/server/reviews.js.map +1 -0
  370. package/src/lib/server/site-page-enricher.d.ts +42 -0
  371. package/src/lib/server/site-page-enricher.js +149 -0
  372. package/src/lib/server/site-page-enricher.js.map +1 -0
  373. package/src/lib/server/site-page-resolver.d.ts +26 -0
  374. package/src/lib/server/site-page-resolver.js +223 -0
  375. package/src/lib/server/site-page-resolver.js.map +1 -0
  376. package/src/lib/server/stock-hold.d.ts +127 -0
  377. package/src/lib/server/stock-hold.js +258 -0
  378. package/src/lib/server/stock-hold.js.map +1 -0
  379. package/src/lib/server/storefront-tax-record.d.ts +22 -0
  380. package/src/lib/server/storefront-tax-record.js +218 -0
  381. package/src/lib/server/storefront-tax-record.js.map +1 -0
  382. package/src/lib/server/storefront-tax.d.ts +197 -0
  383. package/src/lib/server/storefront-tax.js +245 -0
  384. package/src/lib/server/storefront-tax.js.map +1 -0
  385. package/src/lib/server/stream.d.ts +25 -0
  386. package/src/lib/server/stream.js +191 -0
  387. package/src/lib/server/stream.js.map +1 -0
  388. package/src/lib/server/subscription-portal.d.ts +24 -0
  389. package/src/lib/server/subscription-portal.js +91 -0
  390. package/src/lib/server/subscription-portal.js.map +1 -0
  391. package/src/lib/server/supplier-outbox.d.ts +190 -0
  392. package/src/lib/server/supplier-outbox.js +342 -0
  393. package/src/lib/server/supplier-outbox.js.map +1 -0
  394. package/src/lib/server/supplier-update.d.ts +23 -0
  395. package/src/lib/server/supplier-update.js +289 -0
  396. package/src/lib/server/supplier-update.js.map +1 -0
  397. package/src/lib/server/tax-profile.d.ts +29 -0
  398. package/src/lib/server/tax-profile.js +40 -0
  399. package/src/lib/server/tax-profile.js.map +1 -0
  400. package/src/lib/server.d.ts +32 -0
  401. package/src/lib/server.js +311 -0
  402. package/src/lib/server.js.map +1 -0
  403. package/src/lib/site.d.ts +27 -0
  404. package/src/lib/site.js +134 -0
  405. package/src/lib/site.js.map +1 -0
  406. package/src/lib/utils/escape-html.d.ts +41 -0
  407. package/src/lib/utils/escape-html.js +41 -0
  408. package/src/lib/utils/escape-html.js.map +1 -0
  409. package/src/lib/utils/generate-preset-id.d.ts +19 -0
  410. package/src/lib/utils/generate-preset-id.js +25 -0
  411. package/src/lib/utils/generate-preset-id.js.map +1 -0
  412. package/src/lib/utils/member-continue.d.ts +45 -0
  413. package/src/lib/utils/member-continue.js +49 -0
  414. package/src/lib/utils/member-continue.js.map +1 -0
  415. package/src/lib/utils/use-storefront-purchase-event.d.ts +60 -0
  416. package/src/lib/utils/use-storefront-purchase-event.js +142 -0
  417. package/src/lib/utils/use-storefront-purchase-event.js.map +1 -0
@@ -0,0 +1,1022 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ /**
3
+ * @license
4
+ * Copyright 2026 Aglyn LLC
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */ /**
18
+ * Orders model v1 (AGL-283): line items snapshot the product/variant at
19
+ * purchase time (renames and price changes never rewrite history), a
20
+ * small status machine gates transitions, and totals are integer cents.
21
+ * Docs live at `hosts/{hostId}/orders/{id}`; the Stripe webhook creates
22
+ * them and the orders console (AGL-287) drives transitions. Pure — no
23
+ * I/O here.
24
+ */ import { stripeIdIsTestMode } from "@aglyn/aglyn/app-utils/stripe-deployment-mode";
25
+ /**
26
+ * Legal status transitions. Refund/cancel policies: anything paid can
27
+ * refund; only unfulfilled orders cancel (refund instead once shipped).
28
+ *
29
+ * `cancelled` IS NOT TERMINAL, and treating it as one trapped money (AGL-2149).
30
+ * `cancel-order.ts` accepts a **paid** order — `paid: [… 'cancelled' …]` above
31
+ * — and moves no money when it does: it flips the status and returns the stock.
32
+ * `refund.ts` gates on `canTransitionOrder(order.status, 'refunded')`, so with
33
+ * `cancelled: []` the refund door closed behind the cancel and answered "orders
34
+ * in cancelled cannot refund" forever. An admin who cancelled a paid order
35
+ * instead of refunding it — the two buttons sit next to each other in the order
36
+ * dialog — had permanently locked the shopper's money out of every refund route
37
+ * this product has. The shopper's only remaining recourse was a chargeback,
38
+ * which costs the merchant the goods, the money AND the dispute fee.
39
+ *
40
+ * Whether cancelling a PAID order should refuse, or refund on the merchant's
41
+ * behalf, is a real product question and is deliberately NOT answered here:
42
+ * either would change what an existing console button does to money. Making the
43
+ * money reachable is the part that must not wait for that answer.
44
+ *
45
+ * A cancelled order that never took money simply has nothing to refund —
46
+ * `refund.ts` resolves no payment intent and answers "No payment to refund" —
47
+ * so the widened edge costs a lapsed `pending` order nothing.
48
+ */ const ORDER_TRANSITIONS = {
49
+ pending: [
50
+ 'paid',
51
+ 'cancelled'
52
+ ],
53
+ paid: [
54
+ 'partially_fulfilled',
55
+ 'fulfilled',
56
+ 'cancelled',
57
+ 'refunded'
58
+ ],
59
+ partially_fulfilled: [
60
+ 'fulfilled',
61
+ 'refunded'
62
+ ],
63
+ fulfilled: [
64
+ 'delivered',
65
+ 'refunded'
66
+ ],
67
+ delivered: [
68
+ 'refunded'
69
+ ],
70
+ cancelled: [
71
+ 'refunded'
72
+ ],
73
+ refunded: []
74
+ };
75
+ export function canTransitionOrder(from, to) {
76
+ var _ORDER_TRANSITIONS_from;
77
+ return ((_ORDER_TRANSITIONS_from = ORDER_TRANSITIONS[from]) != null ? _ORDER_TRANSITIONS_from : []).includes(to);
78
+ }
79
+ /**
80
+ * One money part, coerced to a whole non-negative number of cents (AGL-2224).
81
+ *
82
+ * `Math.max(0, Math.round(x))` is NOT this guard, and the difference is the
83
+ * whole defect: `Math.max` and `Math.min` PROPAGATE `NaN` rather than
84
+ * discarding it, so a single non-finite input made every field below `NaN` and
85
+ * `totalCents` with them. That is not a cosmetic wrong number — it is a number
86
+ * that defeats comparison. `cashReceivedCents < NaN` is `false`, so the POS
87
+ * "cash received is short" guard passed a sale that had taken no money; and a
88
+ * `NaN` written to Firestore (a legal double there) poisons every downstream
89
+ * sum, so ONE bad order renders a merchant's whole revenue figure `NaN`
90
+ * forever after.
91
+ *
92
+ * The inputs that can be non-finite are real, not theoretical: a POS
93
+ * `discountPct` that is not a number, a product whose `priceUsd` is a string
94
+ * or absent (`Number(undefined) * 100`), a `taxCents` derived from either. So
95
+ * this coerces at the boundary every order in the product passes through,
96
+ * rather than at each of the five callers, and answers 0 — the only value that
97
+ * cannot silently overstate what the shopper owes.
98
+ */ const wholeCents = (value)=>{
99
+ const cents = Math.round(Number(value != null ? value : 0));
100
+ return Number.isFinite(cents) && cents > 0 ? cents : 0;
101
+ };
102
+ /**
103
+ * Split `totalCents` across `weights` so the parts sum to it EXACTLY.
104
+ *
105
+ * Largest-remainder (Hamilton) apportionment. Each weight takes its exact
106
+ * share, the shares are floored, and the cents left over by flooring are handed
107
+ * one each to the largest fractional parts, ties going to the lower index so
108
+ * the answer is deterministic for a given input.
109
+ *
110
+ * The exactness is the whole point and it is a money property, not a
111
+ * neatness one: `Math.round` per line loses or invents cents against the total
112
+ * — three lines splitting a 10¢ discount round to 3+3+3=9 and the missing cent
113
+ * has to come from somewhere. A refund built on a split that does not close is
114
+ * a reconciliation defect that surfaces months later against Stripe's numbers.
115
+ *
116
+ * Pure and total. A non-positive total, an empty weight list, or weights that
117
+ * sum to nothing all answer zeros — never a division by zero, never a NaN
118
+ * propagated into an amount someone is charged.
119
+ */ export function apportionCents(weights, totalCents) {
120
+ const safe = (weights != null ? weights : []).map((weight)=>Math.max(0, Math.round(Number(weight != null ? weight : 0))));
121
+ const basis = safe.reduce((sum, weight)=>sum + weight, 0);
122
+ const total = Math.max(0, Math.round(Number(totalCents != null ? totalCents : 0)));
123
+ if (safe.length === 0 || basis <= 0 || total <= 0) return safe.map(()=>0);
124
+ // Never hand back more than there is to split. A discount larger than the
125
+ // items it came off is a data fault, and apportioning it in full would
126
+ // credit lines with money the order never carried.
127
+ const pot = Math.min(total, basis);
128
+ const exact = safe.map((weight)=>weight * pot / basis);
129
+ const shares = exact.map((value)=>Math.floor(value));
130
+ let remainder = pot - shares.reduce((sum, share)=>sum + share, 0);
131
+ const order = exact.map((value, index)=>({
132
+ index,
133
+ fraction: value - Math.floor(value)
134
+ })).sort((a, b)=>b.fraction - a.fraction || a.index - b.index);
135
+ for (const entry of order){
136
+ if (remainder <= 0) break;
137
+ shares[entry.index] += 1;
138
+ remainder -= 1;
139
+ }
140
+ return shares;
141
+ }
142
+ /**
143
+ * What refunding the named lines is actually worth.
144
+ *
145
+ * A line's LIST value is `unitAmountCents x quantity`, and that is what the
146
+ * refund route used to hand back. It is the wrong number on any order that
147
+ * carried an order-level discount, because the buyer never paid it: a $10
148
+ * coupon on two $50 lines means each line cost $45, and refunding one at $50
149
+ * pays back $5 the buyer never spent. The order then has less left than its
150
+ * remaining line is worth, so the SECOND line refund is refused outright and
151
+ * the merchant cannot finish the job they started.
152
+ *
153
+ * So each line carries its share of the discount, apportioned by list value
154
+ * through {@link apportionCents} — which guarantees the shares sum to the whole
155
+ * discount, so refunding every line returns exactly `itemsCents - discountCents`
156
+ * and no cent is stranded or invented.
157
+ *
158
+ * SHIPPING AND TAX ARE DELIBERATELY NOT IN THIS FIGURE. Refunding a line
159
+ * returns what the goods cost. Shipping is charged for the consignment rather
160
+ * than the line, so no split of it is defensible without knowing whether the
161
+ * parcel still ships; tax follows the goods but is Stripe's to recompute, and
162
+ * an order whose tax was collected under Aglyn's own registration
163
+ * (`taxMode: 'stripe-automatic'`) is not one this function may quietly decide
164
+ * to hand back. Both remain whole-order concerns, refundable by amount.
165
+ *
166
+ * Pure: unknown indexes contribute nothing rather than throwing.
167
+ */ export function orderLineRefundCents(order, lineIndexes) {
168
+ var _ref, _ref1;
169
+ var _order_totals;
170
+ const lines = (_ref = order == null ? void 0 : order.lineItems) != null ? _ref : [];
171
+ const gross = lines.map((line)=>{
172
+ var _ref, _ref1;
173
+ return Math.max(0, Math.round(Number((_ref = line == null ? void 0 : line.unitAmountCents) != null ? _ref : 0)) * Math.max(1, Math.round(Number((_ref1 = line == null ? void 0 : line.quantity) != null ? _ref1 : 1))));
174
+ });
175
+ const shares = apportionCents(gross, Math.max(0, Math.round(Number((_ref1 = order == null ? void 0 : (_order_totals = order.totals) == null ? void 0 : _order_totals.discountCents) != null ? _ref1 : 0))));
176
+ const wanted = new Set((lineIndexes != null ? lineIndexes : []).filter((index)=>Number.isInteger(index) && index >= 0 && index < lines.length));
177
+ let cents = 0;
178
+ for (const index of wanted)cents += gross[index] - shares[index];
179
+ return Math.max(0, cents);
180
+ }
181
+ /**
182
+ * A REHEARSAL IS NOT REVENUE.
183
+ *
184
+ * A smoke-test checkout writes a real order document. Stripe never moved money
185
+ * for it — the session id is `cs_test_…` — but every surface that sums paid
186
+ * orders counted it, so a storefront with one test order and no sales reported
187
+ * revenue it had never earned. Found in production: a single $18.00 order from
188
+ * an end-to-end run, standing as the whole platform's storefront revenue.
189
+ *
190
+ * ## Two signals, in order of trust
191
+ *
192
+ * `livemode` is a RECORDED FACT and wins whenever it is present: the webhook
193
+ * knows which Stripe environment an event came from and now writes it onto the
194
+ * order. Only a literal boolean counts, the same three-valued reading every
195
+ * other money gate in this codebase uses.
196
+ *
197
+ * The session id prefix is the FALLBACK, for the orders written before
198
+ * anything recorded the fact. It is Stripe's convention rather than our data,
199
+ * so it lives behind `stripeIdIsTestMode` and is not spelled out here.
200
+ *
201
+ * ## An unknowable order is LIVE
202
+ *
203
+ * An order with no `livemode` and no Stripe session id — a POS cash sale, a
204
+ * folio charge, a draft order paid offline — is real money and is counted.
205
+ * Answering "test" for anything we cannot identify would zero genuine sales,
206
+ * which is the one direction this must never fail in: a merchant under-reporting
207
+ * their own revenue has no way to tell it is happening.
208
+ */ export function orderIsTestMode(order) {
209
+ if (typeof (order == null ? void 0 : order.livemode) === 'boolean') return !order.livemode;
210
+ // `$id` as well as the field: every storefront order is keyed BY its session
211
+ // id, so the doc id carries the same signal and is present on rows read
212
+ // straight out of Firestore even where the field was never written. A POS or
213
+ // draft order has an auto-generated id, which matches no Stripe prefix and
214
+ // correctly reads as live.
215
+ return stripeIdIsTestMode(order == null ? void 0 : order.checkoutSessionId) || stripeIdIsTestMode(order == null ? void 0 : order.$id);
216
+ }
217
+ /** Sums line items and folds in shipping/tax/discount/fee, all cents. */ export function computeOrderTotals(lineItems, parts) {
218
+ const itemsCents = (lineItems != null ? lineItems : []).reduce((sum, line)=>sum + wholeCents((line == null ? void 0 : line.unitAmountCents) * (line == null ? void 0 : line.quantity)), 0);
219
+ const shippingCents = wholeCents(parts == null ? void 0 : parts.shippingCents);
220
+ const taxCents = wholeCents(parts == null ? void 0 : parts.taxCents);
221
+ const discountCents = Math.min(wholeCents(parts == null ? void 0 : parts.discountCents), itemsCents + shippingCents);
222
+ return {
223
+ itemsCents,
224
+ shippingCents,
225
+ taxCents,
226
+ discountCents,
227
+ feeCents: wholeCents(parts == null ? void 0 : parts.feeCents),
228
+ totalCents: itemsCents + shippingCents + taxCents - discountCents
229
+ };
230
+ }
231
+ export function computeCheckoutSessionTotals(lineItems, session, parts) {
232
+ var _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7;
233
+ const details = (_ref = session == null ? void 0 : session.total_details) != null ? _ref : {};
234
+ const totals = computeOrderTotals(lineItems, {
235
+ feeCents: Number((_ref1 = parts == null ? void 0 : parts.feeCents) != null ? _ref1 : 0),
236
+ taxCents: Number((_ref2 = details == null ? void 0 : details.amount_tax) != null ? _ref2 : 0) + Number((_ref3 = parts == null ? void 0 : parts.lineItemTaxCents) != null ? _ref3 : 0),
237
+ shippingCents: Number((_ref4 = details == null ? void 0 : details.amount_shipping) != null ? _ref4 : 0),
238
+ discountCents: Number((_ref5 = details == null ? void 0 : details.amount_discount) != null ? _ref5 : 0) + Number((_ref6 = parts == null ? void 0 : parts.pricedInDiscountCents) != null ? _ref6 : 0)
239
+ });
240
+ const amountTotal = Number((_ref7 = session == null ? void 0 : session.amount_total) != null ? _ref7 : NaN);
241
+ return _extends({}, totals, {
242
+ totalCents: Number.isFinite(amountTotal) ? amountTotal : totals.totalCents
243
+ });
244
+ }
245
+ /** Non-negative integer cents from an untyped metadata value; 0 otherwise. */ function metadataCents(value) {
246
+ const cents = Math.round(Number(value != null ? value : 0));
247
+ return Number.isFinite(cents) && cents > 0 ? cents : 0;
248
+ }
249
+ /**
250
+ * The stored line items and totals for a `commerce-order` (buy-now) session
251
+ * (AGL-1711).
252
+ *
253
+ * ## What was wrong
254
+ *
255
+ * The webhook built the whole order from one number — it read
256
+ * `object.amount_total` into `amountCents`, wrote a single line item with
257
+ * `quantity` literal 1 and `unitAmountCents` set to that `amountCents`, and
258
+ * passed `computeOrderTotals` nothing but `feeCents`.
259
+ *
260
+ * `amount_total` is the ENTIRE charge, so the merchant's record said the
261
+ * product's unit price was the whole session total, that one unit was sold, and
262
+ * that tax and discount were zero. A 3 × $100 purchase recorded as 1 × $300.
263
+ *
264
+ * The dangerous property, and why this outlived AGL-1698: it is not internally
265
+ * inconsistent. `itemsCents` equalled `totalCents`, so the parts summed and any
266
+ * arithmetic check passed while every individual component was wrong. The
267
+ * useful test is not "do the parts sum" but "does each part match what Stripe
268
+ * actually charged", which is what the fixtures assert component by component.
269
+ *
270
+ * ## Why metadata, when AGL-1698's lesson was to read Stripe's own fields
271
+ *
272
+ * Two of the four parts are genuinely absent from Stripe's decomposition, and
273
+ * `checkout.ts` is what hid them:
274
+ *
275
+ * - **Tax.** In `manual` mode the tax is appended as `line_items[1]`, a normal
276
+ * product line labelled e.g. "Tax (8.25%)". Stripe does not know it is tax,
277
+ * so `total_details.amount_tax` is 0 while the money sits in `amount_total`.
278
+ * (In `stripe` mode `automatic_tax` makes `amount_tax` real — and it was not
279
+ * read either, so that tax was lost as well.)
280
+ * - **Discount.** A host coupon is applied by lowering the unit price we send,
281
+ * not as a Stripe discount, so `total_details.amount_discount` is 0.
282
+ *
283
+ * So `checkout.ts` now records both figures, plus the list unit price, in the
284
+ * session metadata as it computes them. This is NOT the reconstruction AGL-1698
285
+ * warned against: the guard there is against pricing from the host's product
286
+ * docs at webhook time, where an edit between session creation and delivery
287
+ * makes our sum disagree with the actual charge. Metadata is a snapshot of the
288
+ * numbers we handed Stripe, frozen at session creation, so it cannot drift.
289
+ * Everything Stripe does know — `amount_total`, `amount_tax`, `amount_shipping`,
290
+ * `amount_discount` — still comes from Stripe, via the shared
291
+ * `computeCheckoutSessionTotals` rather than a parallel decomposition.
292
+ *
293
+ * Shipping is read even though `checkout.ts` declares no `shipping_options`
294
+ * today (AGL-1720): the read is not conditioned on that, so the figure lands on
295
+ * its own the moment buy-now starts charging shipping.
296
+ *
297
+ * ## Sessions created before this change
298
+ *
299
+ * They carry `quantity` (always sent) but none of the three new keys, so the
300
+ * unit price falls back to what Stripe charged per unit, derived from
301
+ * `amount_total` with tax, shipping and discount taken back out. Those orders
302
+ * still reconcile against `amount_total` and their quantity is now right; what
303
+ * cannot be recovered is a priced-in coupon, which stays folded into the unit
304
+ * price exactly as it is today. Deriving from the product doc instead would
305
+ * make `itemsCents` gross with no matching `discountCents`, breaking the sum.
306
+ *
307
+ * ## Worked example — the spec fixture
308
+ *
309
+ * Three $100 units, a 10% host coupon, manual destination tax at 8.25%:
310
+ *
311
+ * listUnit 10000 metadata `unitAmountCents`
312
+ * × quantity 3 metadata `quantity`
313
+ * = itemsCents 30000
314
+ * - discountCents 3000 metadata `discountCents` (priced into the
315
+ * 9000 unit price sent to Stripe)
316
+ * + taxCents 2228 metadata `taxCents` (Stripe `line_items[1]`;
317
+ * `total_details.amount_tax` is 0)
318
+ * + shippingCents 0 Stripe `total_details.amount_shipping`
319
+ * = totalCents 29228 Stripe `amount_total`, verbatim
320
+ *
321
+ * The pre-fix record for the same purchase: `1 × 29228`, tax 0, discount 0 —
322
+ * which also sums to 29228.
323
+ *
324
+ * ## Also the subscription sale record (AGL-1732)
325
+ *
326
+ * `checkout.ts` builds a subscription session with the same function and the
327
+ * same metadata snapshot — only `mode` differs — so the initial charge of a
328
+ * storefront subscription decomposes identically. The webhook's
329
+ * `commerce-subscription` branch stores the result on the subscription
330
+ * document rather than as an order; the arithmetic is the same either way,
331
+ * which is why it lives here and is not duplicated there.
332
+ */ export function computeBuyNowOrder(session, snapshot) {
333
+ var _ref, _ref1, _metadata_quantity, _ref2, _ref3, _ref4, _ref5, _metadata_variantId, _metadata_productId;
334
+ const metadata = (_ref = session == null ? void 0 : session.metadata) != null ? _ref : {};
335
+ const details = (_ref1 = session == null ? void 0 : session.total_details) != null ? _ref1 : {};
336
+ const rawQuantity = Math.round(Number((_metadata_quantity = metadata.quantity) != null ? _metadata_quantity : 1));
337
+ const quantity = Number.isFinite(rawQuantity) && rawQuantity > 0 ? rawQuantity : 1;
338
+ const lineItemTaxCents = metadataCents(metadata.taxCents);
339
+ const pricedInDiscountCents = metadataCents(metadata.discountCents);
340
+ // What Stripe charged for the goods themselves, used only when the session
341
+ // predates the `unitAmountCents` metadata: strip every non-goods component
342
+ // back out of the total and add the discount back in.
343
+ const goodsCents = Number((_ref2 = session == null ? void 0 : session.amount_total) != null ? _ref2 : 0) - Number((_ref3 = details == null ? void 0 : details.amount_tax) != null ? _ref3 : 0) - Number((_ref4 = details == null ? void 0 : details.amount_shipping) != null ? _ref4 : 0) - lineItemTaxCents + Number((_ref5 = details == null ? void 0 : details.amount_discount) != null ? _ref5 : 0) + pricedInDiscountCents;
344
+ const unitAmountCents = metadataCents(metadata.unitAmountCents) || Math.max(0, Math.round(goodsCents / quantity));
345
+ const variantId = String((_metadata_variantId = metadata.variantId) != null ? _metadata_variantId : '');
346
+ const lineItems = [
347
+ _extends({
348
+ productId: String((_metadata_productId = metadata.productId) != null ? _metadata_productId : '')
349
+ }, variantId ? {
350
+ variantId
351
+ } : {}, {
352
+ name: snapshot.name
353
+ }, snapshot.variantLabel ? {
354
+ variantLabel: snapshot.variantLabel
355
+ } : {}, snapshot.sku ? {
356
+ sku: snapshot.sku
357
+ } : {}, snapshot.productType ? {
358
+ productType: snapshot.productType
359
+ } : {}, snapshot.supplierId ? {
360
+ supplierId: snapshot.supplierId
361
+ } : {}, {
362
+ quantity,
363
+ unitAmountCents
364
+ })
365
+ ];
366
+ return {
367
+ lineItems,
368
+ totals: computeCheckoutSessionTotals(lineItems, session, {
369
+ feeCents: metadataCents(metadata.feeCents),
370
+ lineItemTaxCents,
371
+ pricedInDiscountCents
372
+ })
373
+ };
374
+ }
375
+ /**
376
+ * The base a subscription invoice's platform fee SHOULD be taken on
377
+ * (AGL-2317): post-discount items, with tax and shipping removed.
378
+ *
379
+ * Every one-time door — `checkout.ts`, `cart-checkout.ts`, `draft-order.ts`,
380
+ * `pos-order.ts` and (since AGL-2315) bookings — sends a cents amount computed
381
+ * on items alone. The recurring door sent `application_fee_percent`, which
382
+ * Stripe applies to the WHOLE invoice, so Aglyn took a cut of sales tax — money
383
+ * that is the state's — and of shipping. On the issue's worked example ($30/mo
384
+ * digital, Business 2%, an 8.25% TX rate) the one-time base is $30.00 → 60¢ and
385
+ * the invoice total is $32.48 → 65¢.
386
+ *
387
+ * `total` and not a re-summed `lines.data[]`, deliberately. Stripe's own total
388
+ * is already net of every invoice-level discount and of any proration CREDIT,
389
+ * both of which `computeSubscriptionInvoiceOrder` drops (it floors a line at 0,
390
+ * which is right for a stored line item and wrong for a fee base — a mid-cycle
391
+ * downgrade credit reduces what the merchant is actually paid). Subtracting the
392
+ * two parts Stripe reports separately leaves exactly what was charged for goods.
393
+ *
394
+ * Tax is read on both spellings for the reason stated on `SubscriptionInvoiceSource`
395
+ * — the scalar was removed on newer API versions and the endpoint's version is
396
+ * dashboard configuration this repo cannot see. Reading only one of them would
397
+ * silently value tax at 0 and hand back the whole invoice total as the base,
398
+ * which is the very bug this closes.
399
+ */ export function subscriptionInvoiceFeeBasisCents(invoice) {
400
+ var _ref, _ref1;
401
+ var _invoice_shipping_cost;
402
+ const totalCents = metadataCents(invoice == null ? void 0 : invoice.total);
403
+ if (totalCents <= 0) return 0;
404
+ const scalarTax = Number((_ref = invoice == null ? void 0 : invoice.tax) != null ? _ref : NaN);
405
+ const taxCents = Number.isFinite(scalarTax) && scalarTax > 0 ? scalarTax : sumAmounts((_ref1 = invoice == null ? void 0 : invoice.total_taxes) != null ? _ref1 : invoice == null ? void 0 : invoice.total_tax_amounts);
406
+ const shippingCents = metadataCents(invoice == null ? void 0 : (_invoice_shipping_cost = invoice.shipping_cost) == null ? void 0 : _invoice_shipping_cost.amount_total);
407
+ return Math.max(0, totalCents - Math.max(0, taxCents) - shippingCents);
408
+ }
409
+ /**
410
+ * What the platform fee on a paid subscription invoice WOULD have been on the
411
+ * items-only base, at the rate Stripe actually applied (AGL-2317).
412
+ *
413
+ * ## The rate is never named here, on purpose
414
+ *
415
+ * Pricing is locked for Sept 1, so this is a BASE correction and must not be
416
+ * able to become a rate change. It therefore takes no plan, no entitlement and
417
+ * no `resolveTransactionFeePct` call: it scales the fee Stripe already charged
418
+ * by `base / total`. Whatever rate produced `application_fee_amount` — the
419
+ * sale-time one, a rate AGL-2289 has since re-priced, or a staff override —
420
+ * comes through untouched, and the only thing removed is the portion that was
421
+ * taken on tax and shipping. A test that changed a rate could not make this
422
+ * function agree with it.
423
+ *
424
+ * `Math.max(1, …)` matches `checkout.ts`: where a rate applies at all, the
425
+ * floor is a cent, never zero. An invoice with no fee, no total, or nothing but
426
+ * tax answers 0 and asks for no correction it cannot justify.
427
+ */ export function subscriptionInvoiceItemsOnlyFeeCents(invoice) {
428
+ const chargedCents = metadataCents(invoice == null ? void 0 : invoice.application_fee_amount);
429
+ if (chargedCents <= 0) return 0;
430
+ const totalCents = metadataCents(invoice == null ? void 0 : invoice.total);
431
+ // Nothing to scale against — leave what Stripe took rather than inventing a
432
+ // reduction from a total we cannot read.
433
+ if (totalCents <= 0) return chargedCents;
434
+ const basisCents = subscriptionInvoiceFeeBasisCents(invoice);
435
+ if (basisCents <= 0) return 0;
436
+ // Tax-free and shipping-free invoices — the majority — land here and are
437
+ // byte-identical to today, which is what makes this safe inside the freeze.
438
+ if (basisCents >= totalCents) return chargedCents;
439
+ return Math.max(1, Math.round(chargedCents * basisCents / totalCents));
440
+ }
441
+ /**
442
+ * The recurring goods a storefront subscription's `application_fee_percent`
443
+ * is sized against when a paid invoice re-prices it (AGL-2655).
444
+ *
445
+ * The percent carries Stripe's fixed 30¢ folded into a rate, so it depends
446
+ * on the amount it will be applied to — and the amount that matters is the
447
+ * NEXT cycle's, which nobody has yet. The best predictor is this cycle's
448
+ * items-only basis, for a cycle that bills the full recurring price:
449
+ * `subscription_cycle`, and `subscription_create` for the opening charge.
450
+ * Any other reason — a `subscription_update` proration, a threshold
451
+ * invoice — bills a fraction, and a percent sized on a fraction would be
452
+ * applied to the following full cycle and over-recover on it. Those, and a
453
+ * $0 opening invoice (a trial converts later), fall back to what the sale
454
+ * recorded: the sold lines' price × quantity, the stable figure the
455
+ * subscription bills every cycle it is not being adjusted.
456
+ *
457
+ * Zero when neither source knows — and the caller then leaves the rate as it
458
+ * stands rather than sizing a percent on nothing.
459
+ */ export function subscriptionRecurringBasisCents(invoice, soldLineItems) {
460
+ var _ref;
461
+ const reason = String((_ref = invoice == null ? void 0 : invoice.billing_reason) != null ? _ref : '');
462
+ const billsTheFullPrice = reason === 'subscription_cycle' || reason === 'subscription_create';
463
+ const cycleBasis = billsTheFullPrice ? subscriptionInvoiceFeeBasisCents(invoice) : 0;
464
+ if (cycleBasis > 0) return cycleBasis;
465
+ return (soldLineItems != null ? soldLineItems : []).reduce((sum, line)=>{
466
+ var _ref, _ref1;
467
+ const unit = Math.round(Number((_ref = line == null ? void 0 : line.unitAmountCents) != null ? _ref : 0));
468
+ const quantity = Math.round(Number((_ref1 = line == null ? void 0 : line.quantity) != null ? _ref1 : 0));
469
+ if (!Number.isFinite(unit) || !Number.isFinite(quantity)) return sum;
470
+ return sum + Math.max(0, unit) * Math.max(0, quantity);
471
+ }, 0);
472
+ }
473
+ /** Sum of an `[{ amount }]` list, ignoring anything unreadable. */ function sumAmounts(list) {
474
+ return (list != null ? list : []).reduce((sum, entry)=>{
475
+ var _ref;
476
+ const amount = Number((_ref = entry == null ? void 0 : entry.amount) != null ? _ref : 0);
477
+ return sum + (Number.isFinite(amount) ? amount : 0);
478
+ }, 0);
479
+ }
480
+ /** `price.recurring.interval` when it is one we sell, else undefined. */ function lineInterval(line) {
481
+ var _line_price_recurring, _line_price;
482
+ const interval = line == null ? void 0 : (_line_price = line.price) == null ? void 0 : (_line_price_recurring = _line_price.recurring) == null ? void 0 : _line_price_recurring.interval;
483
+ return interval === 'month' || interval === 'year' ? interval : undefined;
484
+ }
485
+ /**
486
+ * The line that describes the SUBSCRIPTION being billed.
487
+ *
488
+ * `lines.data[0]` is not it, for the AGL-1640 reason: a mid-cycle plan switch
489
+ * invoices the proration against the OLD price ahead of the new plan, and an
490
+ * invoice also carries one-off items and credits, any of which can sort first.
491
+ * Prefer a non-proration line stating a cadence; fall back to a proration one,
492
+ * since Stripe requires every recurring item on one subscription to share a
493
+ * cadence; fall back to the first line so a renewal still records a name.
494
+ */ export function selectSubscriptionInvoiceLine(invoice) {
495
+ var _ref, _ref1, _lines_find;
496
+ var _invoice_lines;
497
+ const lines = (_ref = invoice == null ? void 0 : (_invoice_lines = invoice.lines) == null ? void 0 : _invoice_lines.data) != null ? _ref : [];
498
+ return (_ref1 = (_lines_find = lines.find((line)=>!(line == null ? void 0 : line.proration) && lineInterval(line))) != null ? _lines_find : lines.find((line)=>lineInterval(line))) != null ? _ref1 : lines[0];
499
+ }
500
+ /**
501
+ * The cadence a paid invoice was billed on, or undefined when it does not say.
502
+ *
503
+ * Never guessed — the same three-state discipline as `billingIntervalFromInvoice`
504
+ * (AGL-1640). Storing `month` for an invoice that did not state one would make
505
+ * the merchant's own record of what a subscriber pays wrong in the one way that
506
+ * cannot be spotted by looking at it.
507
+ */ export function subscriptionInvoiceInterval(invoice) {
508
+ return lineInterval(selectSubscriptionInvoiceLine(invoice));
509
+ }
510
+ /**
511
+ * The stored line items and totals for one paid subscription invoice
512
+ * (AGL-1743) — a renewal, or the opening cycle.
513
+ *
514
+ * `snapshot` supplies the product identity, taken from what the sale already
515
+ * recorded rather than re-derived: an invoice line knows a description and a
516
+ * price, not a productId, a variant or a SKU. It is applied to the
517
+ * subscription's own line only; a proration or one-off line on the same invoice
518
+ * keeps Stripe's description and carries no product identity, because it is not
519
+ * a sale of that product.
520
+ *
521
+ * `totalCents` is Stripe's `amount_paid` verbatim, for the AGL-1698 reason —
522
+ * our sum is priced from lines we did not authorize and must never become the
523
+ * stored truth. Where a customer credit balance covers part of an invoice the
524
+ * parts will therefore exceed the collected total; the collected figure is the
525
+ * one that matters and the invoice's own `total` is stored beside it.
526
+ */ export function computeSubscriptionInvoiceOrder(invoice, snapshot) {
527
+ var _ref, _ref1, _ref2;
528
+ var _invoice_lines, _invoice_shipping_cost;
529
+ const subscriptionLine = selectSubscriptionInvoiceLine(invoice);
530
+ const lineItems = [];
531
+ for (const line of (_ref = invoice == null ? void 0 : (_invoice_lines = invoice.lines) == null ? void 0 : _invoice_lines.data) != null ? _ref : []){
532
+ var _ref3, _ref4, _ref5, _ref6;
533
+ var _line_price;
534
+ const amount = Math.round(Number((_ref3 = line == null ? void 0 : line.amount) != null ? _ref3 : 0));
535
+ // A credit line (negative proration) is not a sale of anything, and
536
+ // `computeOrderTotals` floors a line at 0 rather than subtracting it.
537
+ // Stripe's own collected total still carries its effect.
538
+ if (!Number.isFinite(amount) || amount <= 0) continue;
539
+ const rawQuantity = Math.round(Number((_ref4 = line == null ? void 0 : line.quantity) != null ? _ref4 : 1));
540
+ const quantity = Number.isFinite(rawQuantity) && rawQuantity > 0 ? rawQuantity : 1;
541
+ // The list unit price, except on a proration line, where `unit_amount` is
542
+ // the full price and `amount` is only the fraction being billed.
543
+ const listUnit = Math.round(Number((_ref5 = line == null ? void 0 : (_line_price = line.price) == null ? void 0 : _line_price.unit_amount) != null ? _ref5 : 0));
544
+ const unitAmountCents = !(line == null ? void 0 : line.proration) && Number.isFinite(listUnit) && listUnit > 0 ? listUnit : Math.max(0, Math.round(amount / quantity));
545
+ const isSubscriptionLine = line === subscriptionLine;
546
+ lineItems.push(_extends({
547
+ productId: isSubscriptionLine ? snapshot.productId : ''
548
+ }, isSubscriptionLine && snapshot.variantId ? {
549
+ variantId: snapshot.variantId
550
+ } : {}, {
551
+ name: isSubscriptionLine ? snapshot.name : String((_ref6 = line == null ? void 0 : line.description) != null ? _ref6 : 'Adjustment').slice(0, 200)
552
+ }, isSubscriptionLine && snapshot.variantLabel ? {
553
+ variantLabel: snapshot.variantLabel
554
+ } : {}, isSubscriptionLine && snapshot.sku ? {
555
+ sku: snapshot.sku
556
+ } : {}, isSubscriptionLine && snapshot.productType ? {
557
+ productType: snapshot.productType
558
+ } : {}, isSubscriptionLine && snapshot.supplierId ? {
559
+ supplierId: snapshot.supplierId
560
+ } : {}, {
561
+ quantity,
562
+ unitAmountCents
563
+ }));
564
+ }
565
+ const scalarTax = Number((_ref1 = invoice == null ? void 0 : invoice.tax) != null ? _ref1 : NaN);
566
+ const taxCents = Number.isFinite(scalarTax) && scalarTax > 0 ? scalarTax : // scalar; they do not coexist, so this cannot double-count.
567
+ sumAmounts((_ref2 = invoice == null ? void 0 : invoice.total_taxes) != null ? _ref2 : invoice == null ? void 0 : invoice.total_tax_amounts);
568
+ return {
569
+ lineItems,
570
+ totals: computeCheckoutSessionTotals(lineItems, {
571
+ amount_total: invoice == null ? void 0 : invoice.amount_paid,
572
+ total_details: {
573
+ amount_tax: taxCents,
574
+ amount_shipping: metadataCents(invoice == null ? void 0 : (_invoice_shipping_cost = invoice.shipping_cost) == null ? void 0 : _invoice_shipping_cost.amount_total),
575
+ amount_discount: sumAmounts(invoice == null ? void 0 : invoice.total_discount_amounts)
576
+ }
577
+ }, {
578
+ feeCents: metadataCents(invoice == null ? void 0 : invoice.application_fee_amount)
579
+ })
580
+ };
581
+ }
582
+ /** Display form: `#1042`; falls back to a doc-id stub for legacy rows. */ export function formatOrderNumber(order, docId) {
583
+ if (order.number != null) return `#${order.number}`;
584
+ return docId ? `#${docId.slice(-6).toUpperCase()}` : '#—';
585
+ }
586
+ /**
587
+ * Lifts a legacy Commerce Starter order row (flat productId/amountCents)
588
+ * into the v1 shape for display; already-shaped orders pass through.
589
+ */ export function liftLegacyOrder(raw) {
590
+ var _raw_amountCents, _raw_status, _raw_channel, _raw_totals, _raw_feeCents;
591
+ if (Array.isArray(raw.lineItems) && raw.lineItems.length > 0) {
592
+ return _extends({
593
+ status: 'paid'
594
+ }, raw);
595
+ }
596
+ const amountCents = Number((_raw_amountCents = raw.amountCents) != null ? _raw_amountCents : 0);
597
+ return _extends({}, raw, {
598
+ status: (_raw_status = raw.status) != null ? _raw_status : 'paid',
599
+ channel: (_raw_channel = raw.channel) != null ? _raw_channel : 'online',
600
+ lineItems: raw.productId ? [
601
+ {
602
+ productId: raw.productId,
603
+ name: 'Product',
604
+ quantity: 1,
605
+ unitAmountCents: amountCents
606
+ }
607
+ ] : [],
608
+ totals: (_raw_totals = raw.totals) != null ? _raw_totals : {
609
+ itemsCents: amountCents,
610
+ shippingCents: 0,
611
+ taxCents: 0,
612
+ discountCents: 0,
613
+ feeCents: Number((_raw_feeCents = raw.feeCents) != null ? _raw_feeCents : 0),
614
+ totalCents: amountCents
615
+ }
616
+ });
617
+ }
618
+ /**
619
+ * Does this order contain `productId`?
620
+ *
621
+ * Line items first, legacy flat `productId` as the fallback — the same test
622
+ * `gate.ts`, `download.ts` and `reviews.ts` already apply. Only the two
623
+ * buy-now-shaped Stripe paths ever write the flat field, so a legacy-only
624
+ * check silently excludes every cart, POS and draft order.
625
+ */ export function orderContainsProduct(order, productId) {
626
+ var _order_lineItems;
627
+ return ((_order_lineItems = order.lineItems) != null ? _order_lineItems : []).some((line)=>line.productId === productId) || order.productId === productId;
628
+ }
629
+ /**
630
+ * Line indexes already covered by a recorded fulfillment (AGL-2455).
631
+ *
632
+ * The set the supplier callback and the console's own fulfil both have to
633
+ * reason about, and the reason `status` alone could not: `supplier-update.ts`
634
+ * wrote `status: 'fulfilled'` as a LITERAL, so the first supplier to post
635
+ * tracking on a two-supplier order marked every line shipped — including lines
636
+ * they have never seen — and the second supplier's POST met a 409 because
637
+ * `fulfilled` cannot transition to `fulfilled`. The buyer was told their whole
638
+ * order shipped with one carrier and one tracking number.
639
+ */ export function coveredLineItemIds(order) {
640
+ var _order_fulfillments;
641
+ const covered = new Set();
642
+ for (const fulfillment of (_order_fulfillments = order.fulfillments) != null ? _order_fulfillments : []){
643
+ var _ref;
644
+ for (const index of (_ref = fulfillment == null ? void 0 : fulfillment.lineItemIds) != null ? _ref : []){
645
+ const line = Math.round(Number(index));
646
+ if (Number.isFinite(line) && line >= 0) covered.add(line);
647
+ }
648
+ }
649
+ return covered;
650
+ }
651
+ /** Distinct suppliers with at least one line on this order (AGL-2455). */ export function orderSupplierIds(order) {
652
+ var _order_lineItems;
653
+ return [
654
+ ...new Set(((_order_lineItems = order.lineItems) != null ? _order_lineItems : []).map((line)=>{
655
+ var _line_supplierId;
656
+ return String((_line_supplierId = line.supplierId) != null ? _line_supplierId : '');
657
+ }).filter(Boolean))
658
+ ];
659
+ }
660
+ /** Line indexes belonging to one supplier (AGL-2455). */ export function supplierLineItemIds(order, supplierId) {
661
+ var _order_lineItems;
662
+ return ((_order_lineItems = order.lineItems) != null ? _order_lineItems : []).map((line, index)=>({
663
+ line,
664
+ index
665
+ })).filter(({ line })=>{
666
+ var _line_supplierId;
667
+ return String((_line_supplierId = line.supplierId) != null ? _line_supplierId : '') === supplierId;
668
+ }).map(({ index })=>index);
669
+ }
670
+ /**
671
+ * The status an order reaches once `covered` lines are shipped (AGL-2455).
672
+ *
673
+ * COMPUTED from the fulfillment set rather than written as a literal, which is
674
+ * the whole of this issue's third requirement. `partially_fulfilled` has existed
675
+ * in `ORDER_TRANSITIONS` since orders shipped and nothing ever wrote it.
676
+ *
677
+ * An order with no lines at all reads as fulfilled — there is nothing left to
678
+ * ship, and answering `partially_fulfilled` would strand it forever.
679
+ */ export function statusAfterFulfilling(order, covered) {
680
+ var _order_lineItems;
681
+ const lines = (_order_lineItems = order.lineItems) != null ? _order_lineItems : [];
682
+ if (lines.length === 0) return 'fulfilled';
683
+ return lines.every((_line, index)=>covered.has(index)) ? 'fulfilled' : 'partially_fulfilled';
684
+ }
685
+ /**
686
+ * Statuses under which an order grants NO entitlement at all (AGL-2454).
687
+ *
688
+ * `pending` has not paid, `cancelled` was undone, `refunded` was given back.
689
+ * The literal list was copied into `download.ts`, `gate.ts`,
690
+ * `membership-account.ts` and `reviews.ts`; it lives here now so a change to
691
+ * what "withdrawn" means reaches all of them at once.
692
+ */ const WITHDRAWN_ORDER_STATUSES = [
693
+ 'pending',
694
+ 'cancelled',
695
+ 'refunded'
696
+ ];
697
+ /**
698
+ * How much of this order has been given back (AGL-2454).
699
+ *
700
+ * `full` follows `status` OR the money, because the two can legitimately
701
+ * disagree for a moment: `refund.ts` reserves `refundedCents` before it calls
702
+ * Stripe and flips `status` after, and a lost dispute reverses money on an
703
+ * order whose status is still `paid` until it closes. Reading only the status
704
+ * would treat that window as "nothing refunded".
705
+ */ export function orderRefundState(order) {
706
+ var _order_refundedCents, _ref, _order_amountCents;
707
+ var _order_totals;
708
+ const refundedCents = Math.max(0, Number((_order_refundedCents = order.refundedCents) != null ? _order_refundedCents : 0));
709
+ const totalCents = (_ref = (_order_totals = order.totals) == null ? void 0 : _order_totals.totalCents) != null ? _ref : Number((_order_amountCents = order.amountCents) != null ? _order_amountCents : 0);
710
+ if (order.status === 'refunded') return 'full';
711
+ if (!(refundedCents > 0)) return 'none';
712
+ return totalCents > 0 && refundedCents >= totalCents ? 'full' : 'partial';
713
+ }
714
+ /**
715
+ * Is this line's entitlement withdrawn?
716
+ *
717
+ * By INDEX, matching `refundedLineItemIds`. A cart can hold the same product on
718
+ * two lines and only one may be coming back, so a product-keyed test would
719
+ * revoke goods the buyer still owns.
720
+ */ export function orderLineRefunded(order, lineIndex) {
721
+ var _order_refundedLineItemIds;
722
+ return ((_order_refundedLineItemIds = order.refundedLineItemIds) != null ? _order_refundedLineItemIds : []).includes(lineIndex);
723
+ }
724
+ /**
725
+ * THE ONE ENTITLEMENT TEST (AGL-2454). Does this order still entitle the buyer
726
+ * to `productId`?
727
+ *
728
+ * Five gates asked this question and all five asked it as
729
+ * `!['pending','cancelled','refunded'].includes(status) && orderContainsProduct(…)`.
730
+ * That reading is why a partial refund revoked NOTHING: `refund.ts` writes
731
+ * `status: 'refunded'` only when the order is FULLY refunded, so a 99%-refunded
732
+ * order stayed `paid` and every gate said yes — downloads, licence keys, gated
733
+ * content and the right to post a verified review, all still live.
734
+ *
735
+ * Withdrawn now means either of two things, and both had to be expressible in
736
+ * one place or the five gates would drift again:
737
+ *
738
+ * - the whole order is withdrawn by `status`, as before; or
739
+ * - every line carrying this product was refunded BY NAME, which is the case a
740
+ * line-scoped refund creates and the only case where an amount can honestly
741
+ * be attributed to goods.
742
+ *
743
+ * `'any'` asks whether the order still entitles ANYTHING, which is what the
744
+ * membership paywall's subscription-shaped probe needs.
745
+ *
746
+ * The legacy flat `productId` order (one line, no `lineItems`) is lifted by
747
+ * `liftLegacyOrder` before it gets here, so index 0 is its only line and a
748
+ * line-scoped refund of it behaves like a full one.
749
+ */ export function orderEntitlesProduct(order, productId) {
750
+ var _order_lineItems;
751
+ if (WITHDRAWN_ORDER_STATUSES.includes(order.status)) {
752
+ return false;
753
+ }
754
+ const lines = (_order_lineItems = order.lineItems) != null ? _order_lineItems : [];
755
+ if (productId === 'any') {
756
+ if (lines.length === 0) return true;
757
+ return lines.some((_line, index)=>!orderLineRefunded(order, index));
758
+ }
759
+ const matching = lines.map((line, index)=>({
760
+ line,
761
+ index
762
+ })).filter(({ line })=>line.productId === productId);
763
+ if (matching.length === 0) {
764
+ // The legacy flat shape, which `liftLegacyOrder` normally converts. Kept so
765
+ // an unlifted row is not silently un-entitled — a false negative here locks
766
+ // a paying buyer out of goods they bought.
767
+ return order.productId === productId;
768
+ }
769
+ return matching.some(({ index })=>!orderLineRefunded(order, index));
770
+ }
771
+ /**
772
+ * Product ids whose entitlement this order has withdrawn line by line
773
+ * (AGL-2454) — every line for the product refunded, none left standing.
774
+ *
775
+ * What `refund.ts` uses to decide which licence keys to RETIRE. Not "any line
776
+ * refunded": a buyer who returned one of two copies still holds the product.
777
+ */ export function refundedProductIds(order) {
778
+ var _order_lineItems;
779
+ const lines = (_order_lineItems = order.lineItems) != null ? _order_lineItems : [];
780
+ const ids = new Set();
781
+ for (const line of lines){
782
+ if (!ids.has(line.productId) && !orderEntitlesProduct(order, line.productId)) {
783
+ ids.add(line.productId);
784
+ }
785
+ }
786
+ return [
787
+ ...ids
788
+ ];
789
+ }
790
+ /**
791
+ * The refund line the console and the merchant read (AGL-2454).
792
+ *
793
+ * Kept in the model because three surfaces show it and "partially refunded"
794
+ * must not mean different things on two of them. Empty for an order with
795
+ * nothing refunded — there is nothing to say.
796
+ */ export function orderRefundSummary(order) {
797
+ var _order_refundedCents, _ref, _order_amountCents, _order_refundedLineItemIds, _order_lineItems;
798
+ var _order_totals;
799
+ const state = orderRefundState(order);
800
+ if (state === 'none') return '';
801
+ const refundedCents = Math.max(0, Number((_order_refundedCents = order.refundedCents) != null ? _order_refundedCents : 0));
802
+ const totalCents = (_ref = (_order_totals = order.totals) == null ? void 0 : _order_totals.totalCents) != null ? _ref : Number((_order_amountCents = order.amountCents) != null ? _order_amountCents : 0);
803
+ if (state === 'full') return `Refunded in full ($${usd(refundedCents)})`;
804
+ const revoked = ((_order_refundedLineItemIds = order.refundedLineItemIds) != null ? _order_refundedLineItemIds : []).length;
805
+ const lines = ((_order_lineItems = order.lineItems) != null ? _order_lineItems : []).length;
806
+ const scope = revoked > 0 ? `${revoked} of ${lines} line${lines === 1 ? '' : 's'} withdrawn` : 'no lines withdrawn — refunded by amount';
807
+ return `Partially refunded ($${usd(refundedCents)} of $${usd(totalCents)}) — ${scope}`;
808
+ }
809
+ /** `12345` -> `123.45`, the CSV's money format. */ function usd(cents) {
810
+ return (cents / 100).toFixed(2);
811
+ }
812
+ /**
813
+ * Display labels for {@link OrderStatus}, and the MUI chip colour each one
814
+ * carries (AGL-2136). The orders screen advertised on `/product/commerce`
815
+ * shows the status as a COLOURED pill — `Paid`, `Fulfilled`, `Refunded` in
816
+ * three different colours — where the console rendered every status as the
817
+ * same default outlined chip, so the one column a merchant scans first
818
+ * carried no signal at all.
819
+ *
820
+ * Kept in the model rather than in the card because three surfaces render a
821
+ * status (the orders list, the detail dialog and the dashboard glance
822
+ * widget) and a colour that means "refunded" on one of them must not mean
823
+ * something else on the next.
824
+ */ export const ORDER_STATUS_LABELS = {
825
+ pending: 'Pending',
826
+ paid: 'Paid',
827
+ partially_fulfilled: 'Partly fulfilled',
828
+ fulfilled: 'Fulfilled',
829
+ delivered: 'Delivered',
830
+ cancelled: 'Canceled',
831
+ refunded: 'Refunded'
832
+ };
833
+ /**
834
+ * Chip colour per status. `pending` is deliberately `default` rather than
835
+ * `warning`: an unpaid order is not a problem, it is simply not money yet,
836
+ * and reserving the alarming colours for `cancelled`/`refunded` is what
837
+ * makes them readable at a glance.
838
+ */ export const ORDER_STATUS_COLOR = {
839
+ pending: 'default',
840
+ paid: 'success',
841
+ partially_fulfilled: 'warning',
842
+ fulfilled: 'info',
843
+ delivered: 'info',
844
+ cancelled: 'default',
845
+ refunded: 'error'
846
+ };
847
+ /** Display labels for {@link OrderChannel}. */ export const ORDER_CHANNEL_LABELS = {
848
+ online: 'Online',
849
+ pos: 'POS',
850
+ draft: 'Draft',
851
+ subscription: 'Subscription'
852
+ };
853
+ /** Human label for a channel, tolerating a legacy/unknown value. */ export function orderChannelLabel(channel) {
854
+ var _ref, _ORDER_CHANNEL_LABELS_;
855
+ return (_ref = (_ORDER_CHANNEL_LABELS_ = ORDER_CHANNEL_LABELS[channel != null ? channel : 'online']) != null ? _ORDER_CHANNEL_LABELS_ : channel) != null ? _ref : 'Online';
856
+ }
857
+ /**
858
+ * Net cents an order actually earned: the charged total less anything
859
+ * refunded. The three commerce surfaces each had their own inline copy of
860
+ * this expression; a refunded order counted as revenue on whichever one
861
+ * was written first.
862
+ */ export function orderNetCents(order) {
863
+ var _ref, _ref1, _order_refundedCents;
864
+ var _order_totals;
865
+ const gross = Number((_ref = (_ref1 = (_order_totals = order.totals) == null ? void 0 : _order_totals.totalCents) != null ? _ref1 : order.amountCents) != null ? _ref : 0);
866
+ return gross - Number((_order_refundedCents = order.refundedCents) != null ? _order_refundedCents : 0);
867
+ }
868
+ /** Milliseconds an order was created at, across every writer's field shape. */ export function orderCreatedAtMs(order) {
869
+ var _order_createdAt, _order_createdAt_toDate, _order_createdAt1;
870
+ if (typeof order.createdAtMs === 'number') return order.createdAtMs;
871
+ const seconds = (_order_createdAt = order.createdAt) == null ? void 0 : _order_createdAt.seconds;
872
+ if (typeof seconds === 'number') return seconds * 1000;
873
+ const date = (_order_createdAt1 = order.createdAt) == null ? void 0 : (_order_createdAt_toDate = _order_createdAt1.toDate) == null ? void 0 : _order_createdAt_toDate.call(_order_createdAt1);
874
+ return date ? date.getTime() : 0;
875
+ }
876
+ const ORDER_WINDOW_DAY_MS = 24 * 60 * 60 * 1000;
877
+ /**
878
+ * Percentage change from `previous` to `current`, or `null` when there is
879
+ * no baseline to divide by.
880
+ */ function deltaPct(current, previous) {
881
+ if (!previous) return null;
882
+ return Math.round((current - previous) / previous * 1000) / 10;
883
+ }
884
+ /**
885
+ * Summarises a window of orders and the window before it (AGL-2136).
886
+ *
887
+ * Every commerce mockup we advertise shows the money tiles carrying a
888
+ * period-over-period delta — `Revenue $26,540 +8.1%` — and the product had
889
+ * no prior-window computation anywhere in the repo, so no surface could
890
+ * have rendered one.
891
+ *
892
+ * `pending` and `cancelled` orders are excluded, matching the analytics
893
+ * card: neither is money. Refunds are subtracted rather than dropped, so a
894
+ * refund inside the window pushes the delta DOWN, which is the whole point
895
+ * of showing it.
896
+ */ export function summarizeOrderWindow(orders, options) {
897
+ var _options_days;
898
+ const days = (_options_days = options.days) != null ? _options_days : 30;
899
+ const spanMs = days * ORDER_WINDOW_DAY_MS;
900
+ const { nowMs } = options;
901
+ let revenueCents = 0;
902
+ let count = 0;
903
+ let priorRevenueCents = 0;
904
+ let priorCount = 0;
905
+ for (const order of orders){
906
+ const lifted = liftLegacyOrder(order);
907
+ if (lifted.status === 'pending' || lifted.status === 'cancelled') continue;
908
+ const age = nowMs - orderCreatedAtMs(order);
909
+ if (age < 0) continue;
910
+ if (age < spanMs) {
911
+ revenueCents += orderNetCents(order);
912
+ count += 1;
913
+ } else if (age < spanMs * 2) {
914
+ priorRevenueCents += orderNetCents(order);
915
+ priorCount += 1;
916
+ }
917
+ }
918
+ const aovCents = count ? Math.round(revenueCents / count) : 0;
919
+ const priorAovCents = priorCount ? Math.round(priorRevenueCents / priorCount) : 0;
920
+ return {
921
+ revenueCents,
922
+ orders: count,
923
+ aovCents,
924
+ revenueDeltaPct: deltaPct(revenueCents, priorRevenueCents),
925
+ ordersDeltaPct: deltaPct(count, priorCount),
926
+ aovDeltaPct: deltaPct(aovCents, priorAovCents)
927
+ };
928
+ }
929
+ /**
930
+ * Header for {@link buildOrdersCsv}. The original seven columns (AGL-96) keep
931
+ * their names AND their positions, so a saved import mapping — by name or by
932
+ * index — still resolves; the four reconciliation columns are appended.
933
+ */ export const ORDERS_CSV_HEADER = 'date,product,amountUsd,feeUsd,customerEmail,coupon,orderId,' + 'status,channel,refundedUsd,netUsd';
934
+ /**
935
+ * The orders console's `orders.csv` (AGL-1747).
936
+ *
937
+ * ## What was wrong
938
+ *
939
+ * The export read `amountCents`, `feeCents` and `productId` — the legacy
940
+ * Commerce Starter flat fields (AGL-90) — and nothing else. Checked writer by
941
+ * writer, only the two buy-now-shaped Stripe paths write them:
942
+ *
943
+ * | Order path | `amountCents` | `productId` |
944
+ * | -- | -- | -- |
945
+ * | buy-now (`commerce-order`, `billing-webhook.ts`) | yes | yes |
946
+ * | cart (`commerce-cart`, `billing-webhook.ts`) | yes | **no** |
947
+ * | POS cash and POS card (`pos-order.ts`) | **no** | **no** |
948
+ * | draft (`draft-order.ts`, paid by `commerce-draft`) | **no** | **no** |
949
+ *
950
+ * So every POS and draft order exported as `$0.00` and every cart order
951
+ * exported with a blank product, each beside a plausible date, email and order
952
+ * id — nothing in the file signals that the number is missing rather than
953
+ * genuinely zero. The console screen was right the whole time: the table row
954
+ * beside the export button, the detail dialog, the analytics card and lifetime
955
+ * purchases all read `totals` with the flat field only as a fallback. The
956
+ * export was the sole reader that had the precedence backwards, and a CSV is
957
+ * the artefact that reaches a bookkeeper.
958
+ *
959
+ * ## What "correct" means
960
+ *
961
+ * Per AGL-1711's lesson, the useful test is not "do the parts sum" but "does
962
+ * each column match what was actually charged" — a total-only assertion passes
963
+ * against a row whose every component is wrong. The spec therefore pins each
964
+ * cell of a worked example individually.
965
+ *
966
+ * ## Refunds
967
+ *
968
+ * `amountUsd` stays gross, which is what it has always meant, and the appended
969
+ * `refundedUsd`/`netUsd` carry the rest. A refunded order previously exported
970
+ * at its gross with nothing beside it to say so — the same class of error, in
971
+ * that the file understated nothing but overstated revenue.
972
+ */ export function buildOrdersCsv(orders, productNames = {}) {
973
+ const escape = (cell)=>/[",\n]/.test(cell) ? `"${cell.replace(/"/g, '""')}"` : cell;
974
+ return [
975
+ ORDERS_CSV_HEADER,
976
+ ...orders.map((order)=>{
977
+ var _order_lineItems, _ref, _ref1, _ref2, _ref3, _order_productId, _ref4, _ref5, _ref6, _ref7, _order_refundedCents, _order_customerEmail, _order_couponCode, _order_$id, _lifted_channel;
978
+ var _order_createdAt_toDate, _order_createdAt, _lineItems_, _lifted_totals, _lifted_totals1;
979
+ const lifted = liftLegacyOrder(order);
980
+ // The STORED line items, not the lifted ones: `liftLegacyOrder` gives a
981
+ // legacy flat row a synthetic line named "Product", which would shadow
982
+ // the real name the `productNames` lookup still recovers for those rows.
983
+ const lineItems = (_order_lineItems = order.lineItems) != null ? _order_lineItems : [];
984
+ // A cart order has several lines and no single product; name the first
985
+ // and count the rest, the way the table row renders it. `serverTimestamp`
986
+ // reads back null until the write lands, so `createdAtMs` — which every
987
+ // modern writer sets alongside it — covers the local snapshot.
988
+ const date = (_ref = (_order_createdAt = order.createdAt) == null ? void 0 : (_order_createdAt_toDate = _order_createdAt.toDate) == null ? void 0 : _order_createdAt_toDate.call(_order_createdAt)) != null ? _ref : order.createdAtMs ? new Date(order.createdAtMs) : null;
989
+ const product = (_ref1 = (_ref2 = (_ref3 = (_lineItems_ = lineItems[0]) == null ? void 0 : _lineItems_.name) != null ? _ref3 : productNames[(_order_productId = order.productId) != null ? _order_productId : '']) != null ? _ref2 : order.productId) != null ? _ref1 : '';
990
+ const totalCents = Number((_ref4 = (_ref5 = (_lifted_totals = lifted.totals) == null ? void 0 : _lifted_totals.totalCents) != null ? _ref5 : order.amountCents) != null ? _ref4 : 0);
991
+ const feeCents = Number((_ref6 = (_ref7 = (_lifted_totals1 = lifted.totals) == null ? void 0 : _lifted_totals1.feeCents) != null ? _ref7 : order.feeCents) != null ? _ref6 : 0);
992
+ const refundedCents = Number((_order_refundedCents = order.refundedCents) != null ? _order_refundedCents : 0);
993
+ return [
994
+ date ? date.toISOString() : '',
995
+ lineItems.length > 1 ? `${product} +${lineItems.length - 1} more` : product,
996
+ usd(totalCents),
997
+ usd(feeCents),
998
+ (_order_customerEmail = order.customerEmail) != null ? _order_customerEmail : '',
999
+ (_order_couponCode = order.couponCode) != null ? _order_couponCode : '',
1000
+ (_order_$id = order.$id) != null ? _order_$id : '',
1001
+ lifted.status,
1002
+ (_lifted_channel = lifted.channel) != null ? _lifted_channel : 'online',
1003
+ usd(refundedCents),
1004
+ usd(totalCents - refundedCents)
1005
+ ].map((cell)=>escape(String(cell))).join(',');
1006
+ })
1007
+ ].join('\n');
1008
+ }
1009
+ /** Appends a timeline event immutably (webhook + console share this). */ export function appendOrderEvent(order, event, detail, atMs = Date.now()) {
1010
+ var _order_timeline;
1011
+ return [
1012
+ ...(_order_timeline = order.timeline) != null ? _order_timeline : [],
1013
+ _extends({
1014
+ atMs,
1015
+ event
1016
+ }, detail ? {
1017
+ detail
1018
+ } : {})
1019
+ ];
1020
+ }
1021
+
1022
+ //# sourceMappingURL=commerce-orders.js.map