@aglyn/plugins-commerce 1.0.0-beta.231 → 1.0.0-beta.233

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 (266) hide show
  1. package/package.json +13 -13
  2. package/src/lib/components/cart-extras.d.ts +6 -0
  3. package/src/lib/components/cart-extras.js +4 -1
  4. package/src/lib/components/cart-extras.js.map +1 -1
  5. package/src/lib/components/cart-fulfillment.d.ts +117 -0
  6. package/src/lib/components/cart-fulfillment.js +367 -0
  7. package/src/lib/components/cart-fulfillment.js.map +1 -0
  8. package/src/lib/components/cart.js +52 -10
  9. package/src/lib/components/cart.js.map +1 -1
  10. package/src/lib/components/commerce-console-page.js +42 -1
  11. package/src/lib/components/commerce-console-page.js.map +1 -1
  12. package/src/lib/components/console/catalog-organization-card.component.js +1 -0
  13. package/src/lib/components/console/catalog-organization-card.component.js.map +1 -1
  14. package/src/lib/components/console/host-orders-card.component.js +42 -11
  15. package/src/lib/components/console/host-orders-card.component.js.map +1 -1
  16. package/src/lib/components/console/local-delivery-settings-card.component.d.ts +37 -0
  17. package/src/lib/components/console/local-delivery-settings-card.component.js +542 -0
  18. package/src/lib/components/console/local-delivery-settings-card.component.js.map +1 -0
  19. package/src/lib/components/console/locations-card.component.js +177 -3
  20. package/src/lib/components/console/locations-card.component.js.map +1 -1
  21. package/src/lib/components/console/order-detail-dialog.component.js +10 -0
  22. package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
  23. package/src/lib/components/console/order-local-fulfillment-panel.component.d.ts +44 -0
  24. package/src/lib/components/console/order-local-fulfillment-panel.component.js +265 -0
  25. package/src/lib/components/console/order-local-fulfillment-panel.component.js.map +1 -0
  26. package/src/lib/components/console/order-offline-notice.component.d.ts +12 -0
  27. package/src/lib/components/console/order-offline-notice.component.js +53 -0
  28. package/src/lib/components/console/order-offline-notice.component.js.map +1 -0
  29. package/src/lib/components/console/pickup-delivery-queue-card.component.d.ts +35 -0
  30. package/src/lib/components/console/pickup-delivery-queue-card.component.js +222 -0
  31. package/src/lib/components/console/pickup-delivery-queue-card.component.js.map +1 -0
  32. package/src/lib/components/console/pos/pos-api.d.ts +24 -1
  33. package/src/lib/components/console/pos/pos-api.js +13 -0
  34. package/src/lib/components/console/pos/pos-api.js.map +1 -1
  35. package/src/lib/components/console/pos/pos-item-dialog.component.d.ts +12 -0
  36. package/src/lib/components/console/pos/pos-item-dialog.component.js +10 -8
  37. package/src/lib/components/console/pos/pos-item-dialog.component.js.map +1 -1
  38. package/src/lib/components/console/pos/pos-kiosk-queue.component.d.ts +22 -0
  39. package/src/lib/components/console/pos/pos-kiosk-queue.component.js +168 -0
  40. package/src/lib/components/console/pos/pos-kiosk-queue.component.js.map +1 -0
  41. package/src/lib/components/console/pos/pos-tender-dialogs.component.d.ts +18 -0
  42. package/src/lib/components/console/pos/pos-tender-dialogs.component.js +116 -1
  43. package/src/lib/components/console/pos/pos-tender-dialogs.component.js.map +1 -1
  44. package/src/lib/components/console/pos/pos-tender-panel.component.d.ts +8 -0
  45. package/src/lib/components/console/pos/pos-tender-panel.component.js +77 -18
  46. package/src/lib/components/console/pos/pos-tender-panel.component.js.map +1 -1
  47. package/src/lib/components/console/pos/use-pos-display.d.ts +5 -2
  48. package/src/lib/components/console/pos/use-pos-display.js +3 -2
  49. package/src/lib/components/console/pos/use-pos-display.js.map +1 -1
  50. package/src/lib/components/console/pos-devices-card.component.js +2 -2
  51. package/src/lib/components/console/pos-devices-card.component.js.map +1 -1
  52. package/src/lib/components/console/pos-display/pairing-screen.d.ts +5 -2
  53. package/src/lib/components/console/pos-display/pairing-screen.js +7 -5
  54. package/src/lib/components/console/pos-display/pairing-screen.js.map +1 -1
  55. package/src/lib/components/console/pos-display/pos-display-api.d.ts +7 -1
  56. package/src/lib/components/console/pos-display/pos-display-api.js +7 -2
  57. package/src/lib/components/console/pos-display/pos-display-api.js.map +1 -1
  58. package/src/lib/components/console/pos-kiosk/kiosk-checkout.d.ts +41 -0
  59. package/src/lib/components/console/pos-kiosk/kiosk-checkout.js +275 -0
  60. package/src/lib/components/console/pos-kiosk/kiosk-checkout.js.map +1 -0
  61. package/src/lib/components/console/pos-kiosk/kiosk-menu.d.ts +32 -0
  62. package/src/lib/components/console/pos-kiosk/kiosk-menu.js +344 -0
  63. package/src/lib/components/console/pos-kiosk/kiosk-menu.js.map +1 -0
  64. package/src/lib/components/console/pos-kiosk/kiosk-staff.d.ts +12 -0
  65. package/src/lib/components/console/pos-kiosk/kiosk-staff.js +257 -0
  66. package/src/lib/components/console/pos-kiosk/kiosk-staff.js.map +1 -0
  67. package/src/lib/components/console/pos-kiosk/pos-kiosk-api.d.ts +114 -0
  68. package/src/lib/components/console/pos-kiosk/pos-kiosk-api.js +189 -0
  69. package/src/lib/components/console/pos-kiosk/pos-kiosk-api.js.map +1 -0
  70. package/src/lib/components/console/pos-kiosk/use-kiosk-idle.d.ts +16 -0
  71. package/src/lib/components/console/pos-kiosk/use-kiosk-idle.js +80 -0
  72. package/src/lib/components/console/pos-kiosk/use-kiosk-idle.js.map +1 -0
  73. package/src/lib/components/console/pos-kiosk-page.component.d.ts +28 -0
  74. package/src/lib/components/console/pos-kiosk-page.component.js +791 -0
  75. package/src/lib/components/console/pos-kiosk-page.component.js.map +1 -0
  76. package/src/lib/components/console/pos-offline/pos-offline-api.d.ts +44 -0
  77. package/src/lib/components/console/pos-offline/pos-offline-api.js +69 -0
  78. package/src/lib/components/console/pos-offline/pos-offline-api.js.map +1 -0
  79. package/src/lib/components/console/pos-offline/pos-offline-banner.component.d.ts +7 -0
  80. package/src/lib/components/console/pos-offline/pos-offline-banner.component.js +135 -0
  81. package/src/lib/components/console/pos-offline/pos-offline-banner.component.js.map +1 -0
  82. package/src/lib/components/console/pos-offline/pos-offline-checkout.component.d.ts +32 -0
  83. package/src/lib/components/console/pos-offline/pos-offline-checkout.component.js +287 -0
  84. package/src/lib/components/console/pos-offline/pos-offline-checkout.component.js.map +1 -0
  85. package/src/lib/components/console/pos-offline/pos-offline-store.d.ts +63 -0
  86. package/src/lib/components/console/pos-offline/pos-offline-store.js +145 -0
  87. package/src/lib/components/console/pos-offline/pos-offline-store.js.map +1 -0
  88. package/src/lib/components/console/pos-offline/register-offline.d.ts +24 -0
  89. package/src/lib/components/console/pos-offline/register-offline.js +24 -0
  90. package/src/lib/components/console/pos-offline/register-offline.js.map +1 -0
  91. package/src/lib/components/console/pos-offline/use-pos-offline.d.ts +85 -0
  92. package/src/lib/components/console/pos-offline/use-pos-offline.js +542 -0
  93. package/src/lib/components/console/pos-offline/use-pos-offline.js.map +1 -0
  94. package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js +72 -17
  95. package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js.map +1 -1
  96. package/src/lib/components/console/pos-page.component.js +228 -51
  97. package/src/lib/components/console/pos-page.component.js.map +1 -1
  98. package/src/lib/components/console/pos-zones.d.ts +23 -0
  99. package/src/lib/components/console/pos-zones.js +31 -0
  100. package/src/lib/components/console/pos-zones.js.map +1 -0
  101. package/src/lib/components/console/product-editor-dialog.component.js +10 -64
  102. package/src/lib/components/console/product-editor-dialog.component.js.map +1 -1
  103. package/src/lib/components/console/products-hub-card.component.js +46 -30
  104. package/src/lib/components/console/products-hub-card.component.js.map +1 -1
  105. package/src/lib/components/console/shipping-settings-card.component.js +1 -1
  106. package/src/lib/components/console/shipping-settings-card.component.js.map +1 -1
  107. package/src/lib/components/console/stock-movements-card.component.js +48 -16
  108. package/src/lib/components/console/stock-movements-card.component.js.map +1 -1
  109. package/src/lib/components/console/store-zones.d.ts +8 -1
  110. package/src/lib/components/console/store-zones.js +11 -1
  111. package/src/lib/components/console/store-zones.js.map +1 -1
  112. package/src/lib/components/console/storefront-tax-summary-card.component.js +1 -0
  113. package/src/lib/components/console/storefront-tax-summary-card.component.js.map +1 -1
  114. package/src/lib/components/order-status.js +66 -0
  115. package/src/lib/components/order-status.js.map +1 -1
  116. package/src/lib/components/product-detail.js +42 -15
  117. package/src/lib/components/product-detail.js.map +1 -1
  118. package/src/lib/constants/local-fulfillment-list-query.d.ts +48 -0
  119. package/src/lib/constants/local-fulfillment-list-query.js +84 -0
  120. package/src/lib/constants/local-fulfillment-list-query.js.map +1 -0
  121. package/src/lib/constants/orders-list-query.d.ts +7 -2
  122. package/src/lib/constants/orders-list-query.js +89 -8
  123. package/src/lib/constants/orders-list-query.js.map +1 -1
  124. package/src/lib/constants/pos-shift-list-query.d.ts +22 -0
  125. package/src/lib/constants/pos-shift-list-query.js +115 -0
  126. package/src/lib/constants/pos-shift-list-query.js.map +1 -0
  127. package/src/lib/constants/product-list-query.d.ts +6 -1
  128. package/src/lib/constants/product-list-query.js +77 -8
  129. package/src/lib/constants/product-list-query.js.map +1 -1
  130. package/src/lib/constants/stock-movement-query.d.ts +3 -2
  131. package/src/lib/constants/stock-movement-query.js +52 -8
  132. package/src/lib/constants/stock-movement-query.js.map +1 -1
  133. package/src/lib/declarations.server.js +21 -0
  134. package/src/lib/declarations.server.js.map +1 -1
  135. package/src/lib/model/buyer-notifications.d.ts +5 -3
  136. package/src/lib/model/buyer-notifications.js +25 -4
  137. package/src/lib/model/buyer-notifications.js.map +1 -1
  138. package/src/lib/model/commerce-orders.d.ts +103 -1
  139. package/src/lib/model/commerce-orders.js +2 -1
  140. package/src/lib/model/commerce-orders.js.map +1 -1
  141. package/src/lib/model/commerce-pos-kiosk.d.ts +175 -0
  142. package/src/lib/model/commerce-pos-kiosk.js +147 -0
  143. package/src/lib/model/commerce-pos-kiosk.js.map +1 -0
  144. package/src/lib/model/commerce-pos-offline.d.ts +234 -0
  145. package/src/lib/model/commerce-pos-offline.js +301 -0
  146. package/src/lib/model/commerce-pos-offline.js.map +1 -0
  147. package/src/lib/model/commerce-pos-ops.d.ts +16 -6
  148. package/src/lib/model/commerce-pos-ops.js +12 -4
  149. package/src/lib/model/commerce-pos-ops.js.map +1 -1
  150. package/src/lib/model/commerce-pos.d.ts +13 -1
  151. package/src/lib/model/commerce-pos.js +5 -4
  152. package/src/lib/model/commerce-pos.js.map +1 -1
  153. package/src/lib/model/commerce-stock-holds.d.ts +24 -3
  154. package/src/lib/model/commerce-stock-holds.js +26 -8
  155. package/src/lib/model/commerce-stock-holds.js.map +1 -1
  156. package/src/lib/model/commerce.d.ts +7 -1
  157. package/src/lib/model/commerce.js.map +1 -1
  158. package/src/lib/model/index.d.ts +5 -0
  159. package/src/lib/model/index.js +5 -0
  160. package/src/lib/model/index.js.map +1 -1
  161. package/src/lib/model/local-fulfillment-settings.d.ts +178 -0
  162. package/src/lib/model/local-fulfillment-settings.js +361 -0
  163. package/src/lib/model/local-fulfillment-settings.js.map +1 -0
  164. package/src/lib/model/order-list-fields.d.ts +10 -1
  165. package/src/lib/model/order-list-fields.js +1 -0
  166. package/src/lib/model/order-list-fields.js.map +1 -1
  167. package/src/lib/model/order-local-fulfillment.d.ts +131 -0
  168. package/src/lib/model/order-local-fulfillment.js +125 -0
  169. package/src/lib/model/order-local-fulfillment.js.map +1 -0
  170. package/src/lib/model/order-shipping-export.js +4 -0
  171. package/src/lib/model/order-shipping-export.js.map +1 -1
  172. package/src/lib/model/order-status-view.d.ts +20 -1
  173. package/src/lib/model/order-status-view.js +60 -6
  174. package/src/lib/model/order-status-view.js.map +1 -1
  175. package/src/lib/model/product-write.d.ts +186 -0
  176. package/src/lib/model/product-write.js +116 -0
  177. package/src/lib/model/product-write.js.map +1 -0
  178. package/src/lib/plugin-config.js +6 -2
  179. package/src/lib/plugin-config.js.map +1 -1
  180. package/src/lib/plugin.js +11 -0
  181. package/src/lib/plugin.js.map +1 -1
  182. package/src/lib/pos-kiosk-config.d.ts +26 -0
  183. package/src/lib/pos-kiosk-config.js +59 -0
  184. package/src/lib/pos-kiosk-config.js.map +1 -0
  185. package/src/lib/server/api-v1/openapi.js +8 -0
  186. package/src/lib/server/api-v1/openapi.js.map +1 -1
  187. package/src/lib/server/api-v1/order-view.d.ts +19 -0
  188. package/src/lib/server/api-v1/order-view.js +35 -0
  189. package/src/lib/server/api-v1/order-view.js.map +1 -1
  190. package/src/lib/server/billing-webhook.js +238 -87
  191. package/src/lib/server/billing-webhook.js.map +1 -1
  192. package/src/lib/server/cart-checkout.d.ts +2 -0
  193. package/src/lib/server/cart-checkout.js +173 -13
  194. package/src/lib/server/cart-checkout.js.map +1 -1
  195. package/src/lib/server/channel-order-updates.d.ts +50 -0
  196. package/src/lib/server/channel-order-updates.js +290 -0
  197. package/src/lib/server/channel-order-updates.js.map +1 -0
  198. package/src/lib/server/channel-orders.d.ts +85 -0
  199. package/src/lib/server/channel-orders.js +543 -0
  200. package/src/lib/server/channel-orders.js.map +1 -0
  201. package/src/lib/server/checkout-extras.js +18 -4
  202. package/src/lib/server/checkout-extras.js.map +1 -1
  203. package/src/lib/server/checkout.js +71 -14
  204. package/src/lib/server/checkout.js.map +1 -1
  205. package/src/lib/server/local-fulfillment-status.d.ts +86 -0
  206. package/src/lib/server/local-fulfillment-status.js +379 -0
  207. package/src/lib/server/local-fulfillment-status.js.map +1 -0
  208. package/src/lib/server/local-fulfillment.d.ts +190 -0
  209. package/src/lib/server/local-fulfillment.js +580 -0
  210. package/src/lib/server/local-fulfillment.js.map +1 -0
  211. package/src/lib/server/membership-register.js +3 -1
  212. package/src/lib/server/membership-register.js.map +1 -1
  213. package/src/lib/server/order-notifications.js +61 -0
  214. package/src/lib/server/order-notifications.js.map +1 -1
  215. package/src/lib/server/pos-display.d.ts +27 -1
  216. package/src/lib/server/pos-display.js +50 -9
  217. package/src/lib/server/pos-display.js.map +1 -1
  218. package/src/lib/server/pos-kiosk-principal.d.ts +29 -0
  219. package/src/lib/server/pos-kiosk-principal.js +42 -0
  220. package/src/lib/server/pos-kiosk-principal.js.map +1 -0
  221. package/src/lib/server/pos-kiosk.d.ts +54 -0
  222. package/src/lib/server/pos-kiosk.js +972 -0
  223. package/src/lib/server/pos-kiosk.js.map +1 -0
  224. package/src/lib/server/pos-offline-sync.d.ts +85 -0
  225. package/src/lib/server/pos-offline-sync.js +765 -0
  226. package/src/lib/server/pos-offline-sync.js.map +1 -0
  227. package/src/lib/server/pos-order.js +22 -4
  228. package/src/lib/server/pos-order.js.map +1 -1
  229. package/src/lib/server/pos-payment.d.ts +6 -0
  230. package/src/lib/server/pos-payment.js +225 -6
  231. package/src/lib/server/pos-payment.js.map +1 -1
  232. package/src/lib/server/pos-print.js +5 -0
  233. package/src/lib/server/pos-print.js.map +1 -1
  234. package/src/lib/server/pos-return.js +27 -0
  235. package/src/lib/server/pos-return.js.map +1 -1
  236. package/src/lib/server/pos-sale.d.ts +6 -0
  237. package/src/lib/server/pos-sale.js +2 -0
  238. package/src/lib/server/pos-sale.js.map +1 -1
  239. package/src/lib/server/pos-shift.js +8 -1
  240. package/src/lib/server/pos-shift.js.map +1 -1
  241. package/src/lib/server/product-catalog.js +5 -1
  242. package/src/lib/server/product-catalog.js.map +1 -1
  243. package/src/lib/server/product-drafts.d.ts +5 -1
  244. package/src/lib/server/product-drafts.js +3 -3
  245. package/src/lib/server/product-drafts.js.map +1 -1
  246. package/src/lib/server/product-writer.d.ts +19 -0
  247. package/src/lib/server/product-writer.js +261 -0
  248. package/src/lib/server/product-writer.js.map +1 -0
  249. package/src/lib/server/products-write.d.ts +61 -0
  250. package/src/lib/server/products-write.js +375 -0
  251. package/src/lib/server/products-write.js.map +1 -0
  252. package/src/lib/server/refund.js +3 -0
  253. package/src/lib/server/refund.js.map +1 -1
  254. package/src/lib/server/stock-hold.d.ts +9 -1
  255. package/src/lib/server/stock-hold.js +15 -7
  256. package/src/lib/server/stock-hold.js.map +1 -1
  257. package/src/lib/server.js +21 -0
  258. package/src/lib/server.js.map +1 -1
  259. package/src/lib/tenant-emails.js +161 -0
  260. package/src/lib/tenant-emails.js.map +1 -1
  261. package/src/lib/testing/memory-firestore.d.ts +16 -3
  262. package/src/lib/testing/memory-firestore.js +11 -3
  263. package/src/lib/testing/memory-firestore.js.map +1 -1
  264. package/src/lib/transfer/products.server.d.ts +5 -0
  265. package/src/lib/transfer/products.server.js +2 -2
  266. package/src/lib/transfer/products.server.js.map +1 -1
@@ -0,0 +1,543 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
3
+ /**
4
+ * @license
5
+ * Copyright 2026 Aglyn LLC
6
+ *
7
+ * Licensed under the Apache License, Version 2.0 (the "License");
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ */ import { createResourceUid } from "@aglyn/aglyn/app-utils/create-resource-uid";
19
+ import { notifyHostManagers } from "@aglyn/tenant-data-admin";
20
+ import { firebaseAdmin } from "@aglyn/tenant-data-admin/server/firebase-admin";
21
+ import { createHash } from "node:crypto";
22
+ import * as CommerceModel from "../model/index.js";
23
+ import { ORDER_CANCELLED_EVENT, ORDER_PAID_EVENT } from "../model/order-events.js";
24
+ import { alertLowStockCrossing } from "./low-stock.js";
25
+ import { stageOrderEvent } from "./order-events.js";
26
+ import { capRestockLines, resolveTrackedRestockLines, saleReleaseCaps } from "./restock-flag.js";
27
+ import { completeChannelOrder, recordChannelOrderRefund } from "./channel-order-updates.js";
28
+ const DOC_ID = /^[A-Za-z0-9_-]{1,200}$/;
29
+ const CHANNEL_ID = /^[a-z0-9][a-z0-9-]{0,39}$/;
30
+ const MAX_LINES = 250;
31
+ const MAX_UNITS = 10000;
32
+ const MAX_CENTS = 10000000000;
33
+ /**
34
+ * The order document's id for one outside order: the channel, then a hash of
35
+ * the channel's own id. Deterministic, so a second import of the same order
36
+ * finds the first; hashed, because a channel's id may hold characters a
37
+ * document id may not.
38
+ */ export function channelOrderDocId(channelId, externalOrderId) {
39
+ const digest = createHash('sha256').update(`${channelId}\u0000${externalOrderId}`).digest('hex').slice(0, 24);
40
+ return `${channelId}-${digest}`;
41
+ }
42
+ const whole = (value, max)=>{
43
+ const number = Number(value);
44
+ return Number.isInteger(number) && number >= 0 && number <= max ? number : null;
45
+ };
46
+ const clip = (value, max)=>String(value != null ? value : '').trim().slice(0, max);
47
+ /** What a seller refuses before reading anything, in the merchant's words; `null` when the order is well formed. */ export function channelOrderProblem(order) {
48
+ var _ref, _ref1, _order_currency;
49
+ var _order_channel;
50
+ if (!DOC_ID.test(String((_ref = order == null ? void 0 : order.hostId) != null ? _ref : '')) || /^__.*__$/.test(order.hostId)) return 'The order names no site.';
51
+ if (!CHANNEL_ID.test(String((_ref1 = (_order_channel = order.channel) == null ? void 0 : _order_channel.id) != null ? _ref1 : ''))) return 'The order names no channel.';
52
+ if (!clip(order.externalOrderId, 200)) return 'The order has no id on its channel.';
53
+ if (!/^[A-Za-z]{3}$/.test(String((_order_currency = order.currency) != null ? _order_currency : ''))) return 'The order names no currency.';
54
+ const lines = Array.isArray(order.lines) ? order.lines : [];
55
+ if (!lines.length) return 'The order has no items.';
56
+ if (lines.length > MAX_LINES) return `The order has more than ${MAX_LINES} items.`;
57
+ for (const line of lines){
58
+ if (whole(line == null ? void 0 : line.quantity, MAX_UNITS) === null || Number(line.quantity) < 1) return 'An item of the order has no quantity.';
59
+ if (whole(line == null ? void 0 : line.unitPriceCents, MAX_CENTS) === null) return 'An item of the order has no price.';
60
+ if (!clip(line == null ? void 0 : line.externalLineId, 200)) return 'An item of the order has no id on its channel.';
61
+ }
62
+ for (const amount of [
63
+ order.shippingCents,
64
+ order.taxCents,
65
+ order.discountCents,
66
+ order.totalCents
67
+ ]){
68
+ if (whole(amount, MAX_CENTS) === null) return 'The order’s totals are not whole amounts.';
69
+ }
70
+ return null;
71
+ }
72
+ const cleanFees = (fees)=>{
73
+ if (!Array.isArray(fees)) return {
74
+ fees: null,
75
+ totalCents: null
76
+ };
77
+ const kept = fees.map((fee)=>({
78
+ label: clip(fee == null ? void 0 : fee.label, 80) || 'Fee',
79
+ amountCents: whole(fee == null ? void 0 : fee.amountCents, MAX_CENTS)
80
+ })).filter((fee)=>fee.amountCents !== null).slice(0, 20);
81
+ return {
82
+ fees: kept,
83
+ totalCents: kept.reduce((sum, fee)=>sum + fee.amountCents, 0)
84
+ };
85
+ };
86
+ const address = (value)=>{
87
+ if (!value) return null;
88
+ const out = {};
89
+ for (const key of [
90
+ 'name',
91
+ 'line1',
92
+ 'line2',
93
+ 'city',
94
+ 'state',
95
+ 'postalCode',
96
+ 'country',
97
+ 'phone'
98
+ ]){
99
+ const text = clip(value[key], 200);
100
+ if (text) out[key] = key === 'country' ? text.toUpperCase() : text;
101
+ }
102
+ return Object.keys(out).length ? out : null;
103
+ };
104
+ /** The live variant whose SKU is `sku`, matched without regard to case; `null` when none or several products claim it. */ async function locateSku(firestore, hostId, sku) {
105
+ const wanted = sku.trim().toLowerCase();
106
+ if (!wanted) return null;
107
+ const snapshot = await firestore.collection('hosts').doc(hostId).collection('products').where('skus', 'array-contains', wanted).limit(5).get();
108
+ const found = [];
109
+ for (const doc of snapshot.docs){
110
+ if (doc.get('deletedAt')) continue;
111
+ const variants = Array.isArray(doc.get('variants')) ? doc.get('variants') : [];
112
+ const variant = variants.find((entry)=>{
113
+ var _ref;
114
+ return String((_ref = entry == null ? void 0 : entry['sku']) != null ? _ref : '').trim().toLowerCase() === wanted && (entry == null ? void 0 : entry['id']);
115
+ });
116
+ if (variant) found.push({
117
+ productId: doc.id,
118
+ variantId: String(variant['id'])
119
+ });
120
+ }
121
+ // Two products sharing a SKU is ambiguous; taking either's stock would be a guess.
122
+ return found.length === 1 ? found[0] : null;
123
+ }
124
+ const defaultDeps = ()=>({
125
+ firestore: ()=>firebaseAdmin.app().firestore(),
126
+ now: Date.now
127
+ });
128
+ /** Records one outside order; see the module header. */ export async function importChannelOrder(order, deps = defaultDeps()) {
129
+ var _existing_data;
130
+ const problem = channelOrderProblem(order);
131
+ if (problem) return {
132
+ outcome: 'refused',
133
+ reason: problem
134
+ };
135
+ const firestore = deps.firestore();
136
+ const hostRef = firestore.collection('hosts').doc(order.hostId);
137
+ const orderId = channelOrderDocId(order.channel.id, clip(order.externalOrderId, 200));
138
+ const orderRef = hostRef.collection('orders').doc(orderId);
139
+ const channelLabel = clip(order.channel.label, 60) || order.channel.id;
140
+ // Already recorded: answered before any product is looked up.
141
+ const existing = await orderRef.get();
142
+ if (existing.exists) return alreadyOutcome(orderId, (_existing_data = existing.data()) != null ? _existing_data : {});
143
+ const store = await hostRef.collection('settings').doc('store').get();
144
+ const storeCurrency = clip(store.get('currency'), 3).toUpperCase() || 'USD';
145
+ const currency = order.currency.toUpperCase();
146
+ if (currency !== storeCurrency) {
147
+ return {
148
+ outcome: 'refused',
149
+ reason: `This order is in ${currency}, and the store sells in ${storeCurrency}. Ship it from ${channelLabel}.`
150
+ };
151
+ }
152
+ // Each line's product, found before the transaction (a query cannot run
153
+ // inside one) and checked again inside it, where the stock is decided.
154
+ const located = [];
155
+ for (const line of order.lines){
156
+ const productId = clip(line.productId, 200);
157
+ const variantId = clip(line.variantId, 200);
158
+ if (productId && variantId && DOC_ID.test(productId) && !/^__.*__$/.test(productId)) {
159
+ located.push({
160
+ productId,
161
+ variantId
162
+ });
163
+ } else {
164
+ located.push(line.sku ? await locateSku(firestore, order.hostId, line.sku) : null);
165
+ }
166
+ }
167
+ const nowMs = deps.now();
168
+ const placedAtMs = Number.isFinite(order.placedAtMs) && order.placedAtMs > 0 ? Math.min(order.placedAtMs, nowMs) : nowMs;
169
+ const productIds = [
170
+ ...new Set(located.filter((entry)=>entry !== null).map((entry)=>entry.productId))
171
+ ];
172
+ const crossings = [];
173
+ const result = await firestore.runTransaction(async (transaction)=>{
174
+ var _again_data, _counter_get;
175
+ const counterRef = hostRef.collection('counters').doc('orders');
176
+ const [again, counter, ...productSnaps] = await Promise.all([
177
+ transaction.get(orderRef),
178
+ transaction.get(counterRef),
179
+ ...productIds.map((productId)=>transaction.get(hostRef.collection('products').doc(productId)))
180
+ ]);
181
+ if (again.exists) return {
182
+ kind: 'already',
183
+ data: (_again_data = again.data()) != null ? _again_data : {}
184
+ };
185
+ const products = new Map();
186
+ productSnaps.forEach((snapshot, index)=>{
187
+ if (!snapshot.exists || snapshot.get('deletedAt')) return;
188
+ const lifted = CommerceModel.liftLegacyProduct(snapshot.data());
189
+ products.set(productIds[index], {
190
+ before: lifted,
191
+ current: lifted
192
+ });
193
+ });
194
+ const lineItems = [];
195
+ const shortfalls = [];
196
+ const unmatched = [];
197
+ const ledger = [];
198
+ order.lines.forEach((line, lineIndex)=>{
199
+ var _variant_options, _product_type;
200
+ const quantity = Number(line.quantity);
201
+ const place = located[lineIndex];
202
+ const held = place ? products.get(place.productId) : undefined;
203
+ const variant = held == null ? void 0 : held.current.variants.find((entry)=>entry.id === (place == null ? void 0 : place.variantId));
204
+ if (!place || !held || !variant) {
205
+ unmatched.push(lineIndex);
206
+ lineItems.push(_extends({
207
+ productId: '',
208
+ name: clip(line.name, 200) || clip(line.sku, 120) || 'Item'
209
+ }, line.sku ? {
210
+ sku: clip(line.sku, 120)
211
+ } : {}, {
212
+ productType: 'physical',
213
+ quantity,
214
+ unitAmountCents: Number(line.unitPriceCents)
215
+ }));
216
+ return;
217
+ }
218
+ const product = held.current;
219
+ const label = Object.values((_variant_options = variant.options) != null ? _variant_options : {}).filter(Boolean).join(' / ');
220
+ lineItems.push(_extends({
221
+ productId: place.productId,
222
+ variantId: variant.id,
223
+ name: product.name
224
+ }, label ? {
225
+ variantLabel: label
226
+ } : {}, variant.sku ? {
227
+ sku: variant.sku
228
+ } : line.sku ? {
229
+ sku: clip(line.sku, 120)
230
+ } : {}, {
231
+ productType: (_product_type = product.type) != null ? _product_type : 'physical',
232
+ quantity,
233
+ unitAmountCents: Number(line.unitPriceCents)
234
+ }));
235
+ if (variant.inventory == null) return;
236
+ const requested = -quantity;
237
+ const applied = CommerceModel.appliedVariantInventoryDelta(product, variant.id, requested);
238
+ const variants = CommerceModel.adjustVariantInventory(product, variant.id, requested);
239
+ held.current = _extends({}, product, {
240
+ variants
241
+ });
242
+ ledger.push(_extends({
243
+ productId: place.productId,
244
+ variantId: variant.id,
245
+ delta: requested
246
+ }, applied !== requested ? {
247
+ appliedDelta: applied
248
+ } : {}, {
249
+ reason: 'sale',
250
+ orderId,
251
+ source: channelLabel,
252
+ atMs: nowMs
253
+ }));
254
+ const short = applied - requested;
255
+ if (short > 0 && product.oversellPolicy !== 'backorder') {
256
+ var _ref, _variant_sku;
257
+ shortfalls.push({
258
+ lineIndex,
259
+ sku: (_ref = (_variant_sku = variant.sku) != null ? _variant_sku : line.sku) != null ? _ref : null,
260
+ short
261
+ });
262
+ }
263
+ });
264
+ const number = Number((_counter_get = counter.get('next')) != null ? _counter_get : 1);
265
+ transaction.set(counterRef, {
266
+ next: number + 1
267
+ }, {
268
+ merge: true
269
+ });
270
+ for (const [productId, held] of products){
271
+ if (held.current === held.before) continue;
272
+ transaction.set(hostRef.collection('products').doc(productId), _extends({
273
+ variants: held.current.variants
274
+ }, CommerceModel.productStockFields(held.current), {
275
+ updatedAtMs: nowMs
276
+ }), {
277
+ merge: true
278
+ });
279
+ crossings.push({
280
+ before: held.before,
281
+ after: held.current
282
+ });
283
+ }
284
+ for (const row of ledger)transaction.set(hostRef.collection('inventoryAdjustments').doc(createResourceUid()), row);
285
+ const itemsCents = lineItems.reduce((sum, line)=>sum + line.unitAmountCents * line.quantity, 0);
286
+ const fees = cleanFees(order.fees);
287
+ const lines = order.lines.map((line, lineIndex)=>({
288
+ lineIndex,
289
+ externalLineId: clip(line.externalLineId, 200)
290
+ }));
291
+ const externalRef = clip(order.externalRef, 120) || clip(order.externalOrderId, 120);
292
+ const shipTo = address(order.shippingAddress);
293
+ const timeline = [
294
+ {
295
+ atMs: nowMs,
296
+ event: 'paid',
297
+ detail: `Sold on ${channelLabel}, order ${externalRef}`
298
+ },
299
+ ...unmatched.length ? [
300
+ {
301
+ atMs: nowMs,
302
+ event: 'line-unmatched',
303
+ detail: `${unmatched.length} ${unmatched.length === 1 ? 'item matches' : 'items match'} no product's SKU, ` + 'so no stock was taken for ' + `${unmatched.length === 1 ? 'it' : 'them'}.`
304
+ }
305
+ ] : [],
306
+ ...shortfalls.length ? [
307
+ {
308
+ atMs: nowMs,
309
+ event: 'oversold',
310
+ detail: `${shortfalls.reduce((sum, entry)=>sum + entry.short, 0)} sold beyond what was in stock.`
311
+ }
312
+ ] : []
313
+ ];
314
+ const data = CommerceModel.withOrderListFields(orderId, _extends({
315
+ number,
316
+ status: 'paid',
317
+ channel: 'marketplace',
318
+ channelSource: _extends({
319
+ channelId: order.channel.id,
320
+ channelLabel,
321
+ externalOrderId: clip(order.externalOrderId, 200),
322
+ externalRef,
323
+ lines,
324
+ currency,
325
+ taxRemittedByChannel: true,
326
+ fees: fees.fees,
327
+ feesTotalCents: fees.totalCents
328
+ }, order.handoff === 'courier' ? {
329
+ handoff: 'courier'
330
+ } : {}),
331
+ lineItems,
332
+ totals: {
333
+ itemsCents,
334
+ shippingCents: Number(order.shippingCents),
335
+ taxCents: Number(order.taxCents),
336
+ discountCents: Number(order.discountCents),
337
+ totalCents: Number(order.totalCents),
338
+ // Aglyn takes nothing from a sale another channel was paid for.
339
+ feeCents: 0
340
+ },
341
+ timeline,
342
+ livemode: order.testMode !== true,
343
+ customerName: clip(order.customerName, 200) || (shipTo == null ? void 0 : shipTo.name) || null,
344
+ customerEmail: null
345
+ }, shipTo ? {
346
+ shippingAddress: shipTo
347
+ } : {}, {
348
+ amountCents: Number(order.totalCents),
349
+ feeCents: 0,
350
+ createdAtMs: placedAtMs,
351
+ importedAtMs: nowMs,
352
+ createdAt: firebaseAdmin.firestore.FieldValue.serverTimestamp()
353
+ }));
354
+ transaction.set(orderRef, data);
355
+ // The event carries the order as stored, less the sentinel only Firestore can read.
356
+ const { createdAt: _sentinel } = data, eventOrder = _object_without_properties_loose(data, [
357
+ "createdAt"
358
+ ]);
359
+ stageOrderEvent(transaction, ORDER_PAID_EVENT, {
360
+ hostId: order.hostId,
361
+ orderId,
362
+ key: 'paid',
363
+ order: eventOrder
364
+ });
365
+ return {
366
+ kind: 'created',
367
+ number,
368
+ lines,
369
+ shortfalls,
370
+ unmatched
371
+ };
372
+ });
373
+ if (result.kind === 'already') return alreadyOutcome(orderId, result.data);
374
+ const displayRef = CommerceModel.formatOrderNumber({
375
+ number: result.number
376
+ }, orderId);
377
+ for (const crossing of crossings)alertLowStockCrossing(order.hostId, crossing.before, crossing.after);
378
+ const totalLabel = `${(Number(order.totalCents) / 100).toFixed(2)} ${currency}`;
379
+ const units = order.lines.reduce((sum, line)=>sum + Number(line.quantity), 0);
380
+ void notifyHostManagers(order.hostId, {
381
+ type: 'content.order',
382
+ title: `New ${channelLabel} order on {site} — ${totalLabel}`,
383
+ body: `Order ${displayRef} came in from ${channelLabel} (their order ${clip(order.externalRef, 120) || order.externalOrderId}): ` + `${units} item${units === 1 ? '' : 's'}, ${totalLabel}. ` + (order.handoff === 'courier' ? `Have it ready for the ${channelLabel} courier.` : `Ship it from the order here and the tracking goes back to ${channelLabel}.`),
384
+ link: `/${order.hostId}/products`
385
+ });
386
+ if (result.shortfalls.length) {
387
+ const short = result.shortfalls.reduce((sum, entry)=>sum + entry.short, 0);
388
+ void notifyHostManagers(order.hostId, {
389
+ type: 'content.lowStock',
390
+ title: `Oversold on ${channelLabel} — order ${displayRef}`,
391
+ body: `${channelLabel} sold ${short} unit${short === 1 ? '' : 's'} more than {site} had in stock ` + `(order ${displayRef}). Restock ${short === 1 ? 'it' : 'them'}, or cancel the items on ${channelLabel}.`,
392
+ link: `/${order.hostId}/products`
393
+ });
394
+ }
395
+ return {
396
+ outcome: 'created',
397
+ recordId: orderId,
398
+ displayRef,
399
+ lines: result.lines,
400
+ shortfalls: result.shortfalls,
401
+ unmatched: result.unmatched
402
+ };
403
+ }
404
+ function alreadyOutcome(recordId, data) {
405
+ const source = data['channelSource'];
406
+ return {
407
+ outcome: 'already',
408
+ recordId,
409
+ displayRef: CommerceModel.formatOrderNumber({
410
+ number: Number(data['number']) || undefined
411
+ }, recordId),
412
+ lines: Array.isArray(source == null ? void 0 : source.lines) ? source.lines : []
413
+ };
414
+ }
415
+ /**
416
+ * The channel canceled an order it sent: the order is cancelled here, and
417
+ * the units its sale took go back on the shelf — bounded by its own ledger,
418
+ * exactly as the console's cancel bounds them. Refuses once anything shipped.
419
+ */ export async function cancelChannelOrder(request, deps = defaultDeps()) {
420
+ var _ref, _ref1;
421
+ if (!DOC_ID.test(String((_ref = request == null ? void 0 : request.hostId) != null ? _ref : '')) || !DOC_ID.test(String((_ref1 = request == null ? void 0 : request.recordId) != null ? _ref1 : ''))) {
422
+ return {
423
+ outcome: 'no_such_record'
424
+ };
425
+ }
426
+ if (/^__.*__$/.test(request.hostId) || /^__.*__$/.test(request.recordId)) return {
427
+ outcome: 'no_such_record'
428
+ };
429
+ const firestore = deps.firestore();
430
+ const hostRef = firestore.collection('hosts').doc(request.hostId);
431
+ const orderRef = hostRef.collection('orders').doc(request.recordId);
432
+ const nowMs = deps.now();
433
+ const outcome = await firestore.runTransaction(async (transaction)=>{
434
+ var _snapshot_data, _order_fulfillments, _snapshot_data1;
435
+ const snapshot = await transaction.get(orderRef);
436
+ if (!snapshot.exists) return {
437
+ outcome: 'no_such_record'
438
+ };
439
+ const order = CommerceModel.liftLegacyOrder((_snapshot_data = snapshot.data()) != null ? _snapshot_data : {});
440
+ if (order.channel !== 'marketplace') return {
441
+ outcome: 'not_cancellable',
442
+ status: order.status
443
+ };
444
+ if (order.status === 'cancelled') return {
445
+ outcome: 'already'
446
+ };
447
+ if (order.status !== 'paid' || ((_order_fulfillments = order.fulfillments) != null ? _order_fulfillments : []).length) {
448
+ return {
449
+ outcome: 'not_cancellable',
450
+ status: order.status
451
+ };
452
+ }
453
+ const rows = await transaction.get(hostRef.collection('inventoryAdjustments').where('orderId', '==', request.recordId));
454
+ const caps = saleReleaseCaps(rows.docs.filter((row)=>row.get('reason') === 'sale'));
455
+ const { lines, products } = await resolveTrackedRestockLines(hostRef, order, (ref)=>transaction.get(ref));
456
+ const byProduct = new Map();
457
+ for (const line of capRestockLines(lines, caps)){
458
+ var _byProduct_get;
459
+ byProduct.set(line.productId, [
460
+ ...(_byProduct_get = byProduct.get(line.productId)) != null ? _byProduct_get : [],
461
+ line
462
+ ]);
463
+ }
464
+ let units = 0;
465
+ for (const [productId, productLines] of byProduct){
466
+ const product = products.get(productId);
467
+ if (!product) continue;
468
+ let variants = product.variants;
469
+ for (const line of productLines){
470
+ variants = CommerceModel.adjustVariantInventory({
471
+ variants
472
+ }, line.variantId, line.quantity);
473
+ units += line.quantity;
474
+ }
475
+ transaction.update(hostRef.collection('products').doc(productId), _extends({
476
+ variants
477
+ }, CommerceModel.productStockFields(_extends({}, product, {
478
+ variants
479
+ })), {
480
+ updatedAtMs: nowMs
481
+ }));
482
+ for (const line of productLines){
483
+ transaction.set(hostRef.collection('inventoryAdjustments').doc(createResourceUid()), {
484
+ productId,
485
+ variantId: line.variantId,
486
+ delta: line.quantity,
487
+ reason: 'cancellation',
488
+ orderId: request.recordId,
489
+ atMs: nowMs
490
+ });
491
+ }
492
+ }
493
+ const reason = clip(request.reason, 200) || 'Canceled on its channel';
494
+ const patch = {
495
+ status: 'cancelled',
496
+ updatedAtMs: nowMs,
497
+ timeline: CommerceModel.appendOrderEvent(order, 'cancelled', units > 0 ? `${reason}. ${units} ${units === 1 ? 'unit' : 'units'} returned to stock.` : reason, nowMs)
498
+ };
499
+ transaction.update(orderRef, patch);
500
+ stageOrderEvent(transaction, ORDER_CANCELLED_EVENT, {
501
+ hostId: request.hostId,
502
+ orderId: request.recordId,
503
+ key: 'cancelled',
504
+ order: _extends({}, (_snapshot_data1 = snapshot.data()) != null ? _snapshot_data1 : {}, patch)
505
+ });
506
+ return {
507
+ outcome: 'cancelled',
508
+ restockedUnits: units
509
+ };
510
+ });
511
+ return outcome;
512
+ }
513
+ /** The channel's charges on a sale, recorded once it says; a later answer replaces an earlier one. */ export async function recordChannelOrderFees(request, deps = defaultDeps()) {
514
+ var _ref, _ref1;
515
+ if (!DOC_ID.test(String((_ref = request == null ? void 0 : request.hostId) != null ? _ref : '')) || !DOC_ID.test(String((_ref1 = request == null ? void 0 : request.recordId) != null ? _ref1 : ''))) return 'no_such_record';
516
+ if (/^__.*__$/.test(request.hostId) || /^__.*__$/.test(request.recordId)) return 'no_such_record';
517
+ const firestore = deps.firestore();
518
+ const orderRef = firestore.collection('hosts').doc(request.hostId).collection('orders').doc(request.recordId);
519
+ const fees = cleanFees(request.fees);
520
+ return firestore.runTransaction(async (transaction)=>{
521
+ const snapshot = await transaction.get(orderRef);
522
+ const source = snapshot.get('channelSource');
523
+ if (!snapshot.exists || snapshot.get('channel') !== 'marketplace' || !source) return 'no_such_record';
524
+ transaction.update(orderRef, {
525
+ channelSource: _extends({}, source, {
526
+ fees: fees.fees,
527
+ feesTotalCents: fees.totalCents
528
+ }),
529
+ updatedAtMs: deps.now()
530
+ });
531
+ return 'recorded';
532
+ });
533
+ }
534
+ export const commerceChannelOrders = {
535
+ importOrder: (order)=>importChannelOrder(order),
536
+ cancelOrder: (request)=>cancelChannelOrder(request),
537
+ recordFees: (request)=>recordChannelOrderFees(request),
538
+ // A courier's pickup and a channel's refund or adjustment (AGL-3644).
539
+ completeOrder: (request)=>completeChannelOrder(request),
540
+ recordRefund: (request)=>recordChannelOrderRefund(request)
541
+ };
542
+
543
+ //# sourceMappingURL=channel-orders.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/channel-orders.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 { createResourceUid } from '@aglyn/aglyn/app-utils/create-resource-uid'\nimport type {\n PluginChannelOrder,\n PluginChannelOrderCancelOutcome,\n PluginChannelOrderFee,\n PluginChannelOrderOutcome,\n PluginChannelOrders,\n PluginChannelOrderShortfall,\n} from '@aglyn/aglyn/plugin-manager/plugin-channel-orders'\nimport { notifyHostManagers } from '@aglyn/tenant-data-admin'\nimport { firebaseAdmin } from '@aglyn/tenant-data-admin/server/firebase-admin'\nimport { createHash } from 'node:crypto'\nimport * as CommerceModel from '../model'\nimport { ORDER_CANCELLED_EVENT, ORDER_PAID_EVENT } from '../model/order-events'\nimport { alertLowStockCrossing } from './low-stock'\nimport { stageOrderEvent } from './order-events'\nimport { capRestockLines, resolveTrackedRestockLines, saleReleaseCaps } from './restock-flag'\nimport { completeChannelOrder, recordChannelOrderRefund } from './channel-order-updates'\n\n/**\n * ORDERS SOLD ON ANOTHER CHANNEL (AGL-3638): commerce's implementation of\n * core's `core.channel-orders`, which a marketplace plugin records each\n * order it brings in through.\n *\n * ## One transaction, so two channels cannot sell the last unit twice\n *\n * The order, its number, every product's count, every count's ledger row and\n * the `order.paid` event are ONE Firestore transaction. Each product is read\n * with `transaction.get`, which serializes this write with every other sale\n * of that product (the AGL-2320 reasoning): a storefront checkout landing at\n * the same moment decrements from the count this write left, never from the\n * one it read. The marketplace plugin then pushes the new count to every\n * other channel.\n *\n * A marketplace order is already sold and paid when it arrives, so a shelf\n * that cannot cover it does not refuse it: the units the shelf held are\n * taken, the order is recorded whole, and the merchant is told which units\n * are short — the same loud oversell `reserve-stock.ts` raises.\n *\n * ## Once per outside order\n *\n * The order's id is derived from the channel and its order id\n * ({@link channelOrderDocId}), and the transaction refuses to write over an\n * order that exists, so a retried import answers `already` and moves nothing.\n *\n * ## No money moves here\n *\n * The buyer paid the channel. `totals.feeCents` — Aglyn's own take — is 0,\n * the channel's charges are recorded on `channelSource.fees` for the\n * merchant's books, the tax is the channel's to remit, and refunds happen on\n * the channel. No buyer email is sent: a marketplace forbids contacting its\n * buyers outside it, and none of them hands over a real address.\n */\n\ntype Firestore = FirebaseFirestore.Firestore\n\nconst DOC_ID = /^[A-Za-z0-9_-]{1,200}$/\nconst CHANNEL_ID = /^[a-z0-9][a-z0-9-]{0,39}$/\nconst MAX_LINES = 250\nconst MAX_UNITS = 10_000\nconst MAX_CENTS = 100_000_000_00\n\n/**\n * The order document's id for one outside order: the channel, then a hash of\n * the channel's own id. Deterministic, so a second import of the same order\n * finds the first; hashed, because a channel's id may hold characters a\n * document id may not.\n */\nexport function channelOrderDocId(channelId: string, externalOrderId: string): string {\n const digest = createHash('sha256').update(`${channelId}\\u0000${externalOrderId}`).digest('hex').slice(0, 24)\n return `${channelId}-${digest}`\n}\n\nconst whole = (value: unknown, max: number): number | null => {\n const number = Number(value)\n return Number.isInteger(number) && number >= 0 && number <= max ? number : null\n}\n\nconst clip = (value: unknown, max: number): string => String(value ?? '').trim().slice(0, max)\n\n/** What a seller refuses before reading anything, in the merchant's words; `null` when the order is well formed. */\nexport function channelOrderProblem(order: PluginChannelOrder): string | null {\n if (!DOC_ID.test(String(order?.hostId ?? '')) || /^__.*__$/.test(order.hostId)) return 'The order names no site.'\n if (!CHANNEL_ID.test(String(order.channel?.id ?? ''))) return 'The order names no channel.'\n if (!clip(order.externalOrderId, 200)) return 'The order has no id on its channel.'\n if (!/^[A-Za-z]{3}$/.test(String(order.currency ?? ''))) return 'The order names no currency.'\n const lines = Array.isArray(order.lines) ? order.lines : []\n if (!lines.length) return 'The order has no items.'\n if (lines.length > MAX_LINES) return `The order has more than ${MAX_LINES} items.`\n for (const line of lines) {\n if (whole(line?.quantity, MAX_UNITS) === null || Number(line.quantity) < 1) return 'An item of the order has no quantity.'\n if (whole(line?.unitPriceCents, MAX_CENTS) === null) return 'An item of the order has no price.'\n if (!clip(line?.externalLineId, 200)) return 'An item of the order has no id on its channel.'\n }\n for (const amount of [order.shippingCents, order.taxCents, order.discountCents, order.totalCents]) {\n if (whole(amount, MAX_CENTS) === null) return 'The order’s totals are not whole amounts.'\n }\n return null\n}\n\nconst cleanFees = (fees: readonly PluginChannelOrderFee[] | null | undefined) => {\n if (!Array.isArray(fees)) return { fees: null, totalCents: null }\n const kept = fees\n .map((fee) => ({ label: clip(fee?.label, 80) || 'Fee', amountCents: whole(fee?.amountCents, MAX_CENTS) }))\n .filter((fee): fee is { label: string; amountCents: number } => fee.amountCents !== null)\n .slice(0, 20)\n return { fees: kept, totalCents: kept.reduce((sum, fee) => sum + fee.amountCents, 0) }\n}\n\nconst address = (value: PluginChannelOrder['shippingAddress']): CommerceModel.OrderAddress | null => {\n if (!value) return null\n const out: CommerceModel.OrderAddress = {}\n for (const key of ['name', 'line1', 'line2', 'city', 'state', 'postalCode', 'country', 'phone'] as const) {\n const text = clip(value[key], 200)\n if (text) out[key] = key === 'country' ? text.toUpperCase() : text\n }\n return Object.keys(out).length ? out : null\n}\n\ninterface Located {\n productId: string\n variantId: string\n}\n\n/** The live variant whose SKU is `sku`, matched without regard to case; `null` when none or several products claim it. */\nasync function locateSku(firestore: Firestore, hostId: string, sku: string): Promise<Located | null> {\n const wanted = sku.trim().toLowerCase()\n if (!wanted) return null\n const snapshot = await firestore\n .collection('hosts')\n .doc(hostId)\n .collection('products')\n .where('skus', 'array-contains', wanted)\n .limit(5)\n .get()\n const found: Located[] = []\n for (const doc of snapshot.docs) {\n if (doc.get('deletedAt')) continue\n const variants = Array.isArray(doc.get('variants')) ? (doc.get('variants') as Array<Record<string, unknown>>) : []\n const variant = variants.find((entry) => String(entry?.['sku'] ?? '').trim().toLowerCase() === wanted && entry?.['id'])\n if (variant) found.push({ productId: doc.id, variantId: String(variant['id']) })\n }\n // Two products sharing a SKU is ambiguous; taking either's stock would be a guess.\n return found.length === 1 ? found[0] : null\n}\n\nexport interface ChannelOrderDeps {\n firestore: () => Firestore\n now: () => number\n}\n\nconst defaultDeps = (): ChannelOrderDeps => ({ firestore: () => firebaseAdmin.app().firestore(), now: Date.now })\n\n/** Records one outside order; see the module header. */\nexport async function importChannelOrder(\n order: PluginChannelOrder,\n deps: ChannelOrderDeps = defaultDeps(),\n): Promise<PluginChannelOrderOutcome> {\n const problem = channelOrderProblem(order)\n if (problem) return { outcome: 'refused', reason: problem }\n const firestore = deps.firestore()\n const hostRef = firestore.collection('hosts').doc(order.hostId)\n const orderId = channelOrderDocId(order.channel.id, clip(order.externalOrderId, 200))\n const orderRef = hostRef.collection('orders').doc(orderId)\n const channelLabel = clip(order.channel.label, 60) || order.channel.id\n\n // Already recorded: answered before any product is looked up.\n const existing = await orderRef.get()\n if (existing.exists) return alreadyOutcome(orderId, existing.data() ?? {})\n\n const store = await hostRef.collection('settings').doc('store').get()\n const storeCurrency = clip(store.get('currency'), 3).toUpperCase() || 'USD'\n const currency = order.currency.toUpperCase()\n if (currency !== storeCurrency) {\n return {\n outcome: 'refused',\n reason: `This order is in ${currency}, and the store sells in ${storeCurrency}. Ship it from ${channelLabel}.`,\n }\n }\n\n // Each line's product, found before the transaction (a query cannot run\n // inside one) and checked again inside it, where the stock is decided.\n const located: Array<Located | null> = []\n for (const line of order.lines) {\n const productId = clip(line.productId, 200)\n const variantId = clip(line.variantId, 200)\n if (productId && variantId && DOC_ID.test(productId) && !/^__.*__$/.test(productId)) {\n located.push({ productId, variantId })\n } else {\n located.push(line.sku ? await locateSku(firestore, order.hostId, line.sku) : null)\n }\n }\n\n const nowMs = deps.now()\n const placedAtMs = Number.isFinite(order.placedAtMs) && order.placedAtMs > 0 ? Math.min(order.placedAtMs, nowMs) : nowMs\n const productIds = [...new Set(located.filter((entry): entry is Located => entry !== null).map((entry) => entry.productId))]\n const crossings: Array<{ before: CommerceModel.HostProduct; after: CommerceModel.HostProduct }> = []\n\n const result = await firestore.runTransaction(async (transaction) => {\n const counterRef = hostRef.collection('counters').doc('orders')\n const [again, counter, ...productSnaps] = await Promise.all([\n transaction.get(orderRef),\n transaction.get(counterRef),\n ...productIds.map((productId) => transaction.get(hostRef.collection('products').doc(productId))),\n ])\n if (again.exists) return { kind: 'already' as const, data: again.data() ?? {} }\n const products = new Map<string, { before: CommerceModel.HostProduct; current: CommerceModel.HostProduct }>()\n productSnaps.forEach((snapshot, index) => {\n if (!snapshot.exists || snapshot.get('deletedAt')) return\n const lifted = CommerceModel.liftLegacyProduct(snapshot.data() as never)\n products.set(productIds[index], { before: lifted, current: lifted })\n })\n\n const lineItems: CommerceModel.OrderLineItem[] = []\n const shortfalls: PluginChannelOrderShortfall[] = []\n const unmatched: number[] = []\n const ledger: CommerceModel.InventoryAdjustment[] = []\n order.lines.forEach((line, lineIndex) => {\n const quantity = Number(line.quantity)\n const place = located[lineIndex]\n const held = place ? products.get(place.productId) : undefined\n const variant = held?.current.variants.find((entry) => entry.id === place?.variantId)\n if (!place || !held || !variant) {\n unmatched.push(lineIndex)\n lineItems.push({\n productId: '',\n name: clip(line.name, 200) || clip(line.sku, 120) || 'Item',\n ...(line.sku ? { sku: clip(line.sku, 120) } : {}),\n productType: 'physical',\n quantity,\n unitAmountCents: Number(line.unitPriceCents),\n })\n return\n }\n const product = held.current\n const label = Object.values(variant.options ?? {}).filter(Boolean).join(' / ')\n lineItems.push({\n productId: place.productId,\n variantId: variant.id,\n name: product.name,\n ...(label ? { variantLabel: label } : {}),\n ...(variant.sku ? { sku: variant.sku } : line.sku ? { sku: clip(line.sku, 120) } : {}),\n productType: product.type ?? 'physical',\n quantity,\n unitAmountCents: Number(line.unitPriceCents),\n })\n if (variant.inventory == null) return\n const requested = -quantity\n const applied = CommerceModel.appliedVariantInventoryDelta(product, variant.id, requested)\n const variants = CommerceModel.adjustVariantInventory(product, variant.id, requested)\n held.current = { ...product, variants }\n ledger.push({\n productId: place.productId,\n variantId: variant.id,\n delta: requested,\n ...(applied !== requested ? { appliedDelta: applied } : {}),\n reason: 'sale',\n orderId,\n source: channelLabel,\n atMs: nowMs,\n })\n const short = applied - requested\n if (short > 0 && product.oversellPolicy !== 'backorder') {\n shortfalls.push({ lineIndex, sku: variant.sku ?? line.sku ?? null, short })\n }\n })\n\n const number = Number(counter.get('next') ?? 1)\n transaction.set(counterRef, { next: number + 1 }, { merge: true })\n for (const [productId, held] of products) {\n if (held.current === held.before) continue\n transaction.set(\n hostRef.collection('products').doc(productId),\n { variants: held.current.variants, ...CommerceModel.productStockFields(held.current), updatedAtMs: nowMs },\n { merge: true },\n )\n crossings.push({ before: held.before, after: held.current })\n }\n for (const row of ledger) transaction.set(hostRef.collection('inventoryAdjustments').doc(createResourceUid()), row)\n\n const itemsCents = lineItems.reduce((sum, line) => sum + line.unitAmountCents * line.quantity, 0)\n const fees = cleanFees(order.fees)\n const lines = order.lines.map((line, lineIndex) => ({ lineIndex, externalLineId: clip(line.externalLineId, 200) }))\n const externalRef = clip(order.externalRef, 120) || clip(order.externalOrderId, 120)\n const shipTo = address(order.shippingAddress)\n const timeline: CommerceModel.OrderTimelineEvent[] = [\n { atMs: nowMs, event: 'paid', detail: `Sold on ${channelLabel}, order ${externalRef}` },\n ...(unmatched.length\n ? [\n {\n atMs: nowMs,\n event: 'line-unmatched',\n detail:\n `${unmatched.length} ${unmatched.length === 1 ? 'item matches' : 'items match'} no product's SKU, ` +\n 'so no stock was taken for ' +\n `${unmatched.length === 1 ? 'it' : 'them'}.`,\n },\n ]\n : []),\n ...(shortfalls.length\n ? [\n {\n atMs: nowMs,\n event: 'oversold',\n detail: `${shortfalls.reduce((sum, entry) => sum + entry.short, 0)} sold beyond what was in stock.`,\n },\n ]\n : []),\n ]\n const data = CommerceModel.withOrderListFields(orderId, {\n number,\n status: 'paid' as const,\n channel: 'marketplace' as const,\n channelSource: {\n channelId: order.channel.id,\n channelLabel,\n externalOrderId: clip(order.externalOrderId, 200),\n externalRef,\n lines,\n currency,\n taxRemittedByChannel: true as const,\n fees: fees.fees,\n feesTotalCents: fees.totalCents,\n ...(order.handoff === 'courier' ? { handoff: 'courier' as const } : {}),\n },\n lineItems,\n totals: {\n itemsCents,\n shippingCents: Number(order.shippingCents),\n taxCents: Number(order.taxCents),\n discountCents: Number(order.discountCents),\n totalCents: Number(order.totalCents),\n // Aglyn takes nothing from a sale another channel was paid for.\n feeCents: 0,\n },\n timeline,\n livemode: order.testMode !== true,\n customerName: clip(order.customerName, 200) || shipTo?.name || null,\n customerEmail: null,\n ...(shipTo ? { shippingAddress: shipTo } : {}),\n amountCents: Number(order.totalCents),\n feeCents: 0,\n createdAtMs: placedAtMs,\n importedAtMs: nowMs,\n createdAt: firebaseAdmin.firestore.FieldValue.serverTimestamp(),\n })\n transaction.set(orderRef, data)\n // The event carries the order as stored, less the sentinel only Firestore can read.\n const { createdAt: _sentinel, ...eventOrder } = data\n stageOrderEvent(transaction, ORDER_PAID_EVENT, { hostId: order.hostId, orderId, key: 'paid', order: eventOrder })\n return { kind: 'created' as const, number, lines, shortfalls, unmatched }\n })\n\n if (result.kind === 'already') return alreadyOutcome(orderId, result.data)\n const displayRef = CommerceModel.formatOrderNumber({ number: result.number }, orderId)\n for (const crossing of crossings) alertLowStockCrossing(order.hostId, crossing.before, crossing.after)\n const totalLabel = `${(Number(order.totalCents) / 100).toFixed(2)} ${currency}`\n const units = order.lines.reduce((sum, line) => sum + Number(line.quantity), 0)\n void notifyHostManagers(order.hostId, {\n type: 'content.order',\n title: `New ${channelLabel} order on {site} — ${totalLabel}`,\n body:\n `Order ${displayRef} came in from ${channelLabel} (their order ${clip(order.externalRef, 120) || order.externalOrderId}): ` +\n `${units} item${units === 1 ? '' : 's'}, ${totalLabel}. ` +\n (order.handoff === 'courier'\n ? `Have it ready for the ${channelLabel} courier.`\n : `Ship it from the order here and the tracking goes back to ${channelLabel}.`),\n link: `/${order.hostId}/products`,\n })\n if (result.shortfalls.length) {\n const short = result.shortfalls.reduce((sum, entry) => sum + entry.short, 0)\n void notifyHostManagers(order.hostId, {\n type: 'content.lowStock',\n title: `Oversold on ${channelLabel} — order ${displayRef}`,\n body:\n `${channelLabel} sold ${short} unit${short === 1 ? '' : 's'} more than {site} had in stock ` +\n `(order ${displayRef}). Restock ${short === 1 ? 'it' : 'them'}, or cancel the items on ${channelLabel}.`,\n link: `/${order.hostId}/products`,\n })\n }\n return {\n outcome: 'created',\n recordId: orderId,\n displayRef,\n lines: result.lines,\n shortfalls: result.shortfalls,\n unmatched: result.unmatched,\n }\n}\n\nfunction alreadyOutcome(recordId: string, data: Record<string, unknown>): PluginChannelOrderOutcome {\n const source = data['channelSource'] as CommerceModel.OrderChannelSource | undefined\n return {\n outcome: 'already',\n recordId,\n displayRef: CommerceModel.formatOrderNumber({ number: Number(data['number']) || undefined }, recordId),\n lines: Array.isArray(source?.lines) ? source.lines : [],\n }\n}\n\n/**\n * The channel canceled an order it sent: the order is cancelled here, and\n * the units its sale took go back on the shelf — bounded by its own ledger,\n * exactly as the console's cancel bounds them. Refuses once anything shipped.\n */\nexport async function cancelChannelOrder(\n request: { hostId: string; recordId: string; reason: string },\n deps: ChannelOrderDeps = defaultDeps(),\n): Promise<PluginChannelOrderCancelOutcome> {\n if (!DOC_ID.test(String(request?.hostId ?? '')) || !DOC_ID.test(String(request?.recordId ?? ''))) {\n return { outcome: 'no_such_record' }\n }\n if (/^__.*__$/.test(request.hostId) || /^__.*__$/.test(request.recordId)) return { outcome: 'no_such_record' }\n const firestore = deps.firestore()\n const hostRef = firestore.collection('hosts').doc(request.hostId)\n const orderRef = hostRef.collection('orders').doc(request.recordId)\n const nowMs = deps.now()\n const outcome = await firestore.runTransaction(async (transaction): Promise<PluginChannelOrderCancelOutcome> => {\n const snapshot = await transaction.get(orderRef)\n if (!snapshot.exists) return { outcome: 'no_such_record' }\n const order = CommerceModel.liftLegacyOrder((snapshot.data() ?? {}) as never)\n if (order.channel !== 'marketplace') return { outcome: 'not_cancellable', status: order.status }\n if (order.status === 'cancelled') return { outcome: 'already' }\n if (order.status !== 'paid' || (order.fulfillments ?? []).length) {\n return { outcome: 'not_cancellable', status: order.status }\n }\n const rows = await transaction.get(hostRef.collection('inventoryAdjustments').where('orderId', '==', request.recordId))\n const caps = saleReleaseCaps(rows.docs.filter((row) => row.get('reason') === 'sale'))\n const { lines, products } = await resolveTrackedRestockLines(hostRef as never, order, (ref) => transaction.get(ref))\n const byProduct = new Map<string, CommerceModel.OrderRestockLine[]>()\n for (const line of capRestockLines(lines, caps)) {\n byProduct.set(line.productId, [...(byProduct.get(line.productId) ?? []), line])\n }\n let units = 0\n for (const [productId, productLines] of byProduct) {\n const product = products.get(productId)\n if (!product) continue\n let variants = product.variants\n for (const line of productLines) {\n variants = CommerceModel.adjustVariantInventory({ variants }, line.variantId, line.quantity)\n units += line.quantity\n }\n transaction.update(hostRef.collection('products').doc(productId), {\n variants,\n ...CommerceModel.productStockFields({ ...product, variants }),\n updatedAtMs: nowMs,\n })\n for (const line of productLines) {\n transaction.set(hostRef.collection('inventoryAdjustments').doc(createResourceUid()), {\n productId,\n variantId: line.variantId,\n delta: line.quantity,\n reason: 'cancellation',\n orderId: request.recordId,\n atMs: nowMs,\n } satisfies CommerceModel.InventoryAdjustment)\n }\n }\n const reason = clip(request.reason, 200) || 'Canceled on its channel'\n const patch = {\n status: 'cancelled' as const,\n updatedAtMs: nowMs,\n timeline: CommerceModel.appendOrderEvent(\n order,\n 'cancelled',\n units > 0 ? `${reason}. ${units} ${units === 1 ? 'unit' : 'units'} returned to stock.` : reason,\n nowMs,\n ),\n }\n transaction.update(orderRef, patch)\n stageOrderEvent(transaction, ORDER_CANCELLED_EVENT, {\n hostId: request.hostId,\n orderId: request.recordId,\n key: 'cancelled',\n order: { ...(snapshot.data() ?? {}), ...patch },\n })\n return { outcome: 'cancelled', restockedUnits: units }\n })\n return outcome\n}\n\n/** The channel's charges on a sale, recorded once it says; a later answer replaces an earlier one. */\nexport async function recordChannelOrderFees(\n request: { hostId: string; recordId: string; fees: PluginChannelOrderFee[] },\n deps: ChannelOrderDeps = defaultDeps(),\n): Promise<'recorded' | 'no_such_record'> {\n if (!DOC_ID.test(String(request?.hostId ?? '')) || !DOC_ID.test(String(request?.recordId ?? ''))) return 'no_such_record'\n if (/^__.*__$/.test(request.hostId) || /^__.*__$/.test(request.recordId)) return 'no_such_record'\n const firestore = deps.firestore()\n const orderRef = firestore.collection('hosts').doc(request.hostId).collection('orders').doc(request.recordId)\n const fees = cleanFees(request.fees)\n return firestore.runTransaction(async (transaction) => {\n const snapshot = await transaction.get(orderRef)\n const source = snapshot.get('channelSource') as CommerceModel.OrderChannelSource | undefined\n if (!snapshot.exists || snapshot.get('channel') !== 'marketplace' || !source) return 'no_such_record' as const\n transaction.update(orderRef, {\n channelSource: { ...source, fees: fees.fees, feesTotalCents: fees.totalCents },\n updatedAtMs: deps.now(),\n })\n return 'recorded' as const\n })\n}\n\nexport const commerceChannelOrders: PluginChannelOrders = {\n importOrder: (order) => importChannelOrder(order),\n cancelOrder: (request) => cancelChannelOrder(request),\n recordFees: (request) => recordChannelOrderFees(request),\n // A courier's pickup and a channel's refund or adjustment (AGL-3644).\n completeOrder: (request) => completeChannelOrder(request),\n recordRefund: (request) => recordChannelOrderRefund(request),\n}\n"],"names":["createResourceUid","notifyHostManagers","firebaseAdmin","createHash","CommerceModel","ORDER_CANCELLED_EVENT","ORDER_PAID_EVENT","alertLowStockCrossing","stageOrderEvent","capRestockLines","resolveTrackedRestockLines","saleReleaseCaps","completeChannelOrder","recordChannelOrderRefund","DOC_ID","CHANNEL_ID","MAX_LINES","MAX_UNITS","MAX_CENTS","channelOrderDocId","channelId","externalOrderId","digest","update","slice","whole","value","max","number","Number","isInteger","clip","String","trim","channelOrderProblem","order","test","hostId","channel","id","currency","lines","Array","isArray","length","line","quantity","unitPriceCents","externalLineId","amount","shippingCents","taxCents","discountCents","totalCents","cleanFees","fees","kept","map","fee","label","amountCents","filter","reduce","sum","address","out","key","text","toUpperCase","Object","keys","locateSku","firestore","sku","wanted","toLowerCase","snapshot","collection","doc","where","limit","get","found","docs","variants","variant","find","entry","push","productId","variantId","defaultDeps","app","now","Date","importChannelOrder","deps","existing","problem","outcome","reason","hostRef","orderId","orderRef","channelLabel","exists","alreadyOutcome","data","store","storeCurrency","located","nowMs","placedAtMs","isFinite","Math","min","productIds","Set","crossings","result","runTransaction","transaction","again","counter","counterRef","productSnaps","Promise","all","kind","products","Map","forEach","index","lifted","liftLegacyProduct","set","before","current","lineItems","shortfalls","unmatched","ledger","lineIndex","product","place","held","undefined","name","productType","unitAmountCents","values","options","Boolean","join","variantLabel","type","inventory","requested","applied","appliedVariantInventoryDelta","adjustVariantInventory","delta","appliedDelta","source","atMs","short","oversellPolicy","next","merge","productStockFields","updatedAtMs","after","row","itemsCents","externalRef","shipTo","shippingAddress","timeline","event","detail","withOrderListFields","status","channelSource","taxRemittedByChannel","feesTotalCents","handoff","totals","feeCents","livemode","testMode","customerName","customerEmail","createdAtMs","importedAtMs","createdAt","FieldValue","serverTimestamp","_sentinel","eventOrder","displayRef","formatOrderNumber","crossing","totalLabel","toFixed","units","title","body","link","recordId","cancelChannelOrder","request","liftLegacyOrder","fulfillments","rows","caps","ref","byProduct","productLines","patch","appendOrderEvent","restockedUnits","recordChannelOrderFees","commerceChannelOrders","importOrder","cancelOrder","recordFees","completeOrder","recordRefund"],"mappings":"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"}