@openlup/platform 0.21.0 → 0.23.0

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 (349) hide show
  1. package/CHANGELOG.md +432 -146
  2. package/README.md +82 -589
  3. package/dist/composition/composeBundle.d.ts +7 -0
  4. package/dist/composition/composeBundle.js +2 -0
  5. package/dist/composition/fulfillmentContribution.d.ts +21 -0
  6. package/dist/composition/fulfillmentContribution.js +19 -0
  7. package/dist/composition/index.d.ts +1 -0
  8. package/dist/composition/index.js +1 -0
  9. package/dist/fulfillment/adapterConformance.d.ts +3 -0
  10. package/dist/fulfillment/adapterConformance.js +223 -0
  11. package/dist/fulfillment/bindings.d.ts +3 -0
  12. package/dist/fulfillment/bindings.js +29 -0
  13. package/dist/fulfillment/commerceFulfillmentHandlers.d.ts +29 -0
  14. package/dist/fulfillment/commerceFulfillmentHandlers.js +184 -0
  15. package/dist/fulfillment/commerceFulfillmentReadModel.d.ts +86 -0
  16. package/dist/fulfillment/commerceFulfillmentReadModel.js +131 -0
  17. package/dist/fulfillment/contracts/alignment.d.ts +25 -0
  18. package/dist/fulfillment/contracts/alignment.js +1 -0
  19. package/dist/fulfillment/contracts/bindings.d.ts +51 -0
  20. package/dist/fulfillment/contracts/bindings.js +1 -0
  21. package/dist/fulfillment/contracts/capabilities.d.ts +29 -0
  22. package/dist/fulfillment/contracts/capabilities.js +1 -0
  23. package/dist/fulfillment/contracts/conformance.d.ts +95 -0
  24. package/dist/fulfillment/contracts/conformance.js +1 -0
  25. package/dist/fulfillment/contracts/customerAlignment.d.ts +6 -0
  26. package/dist/fulfillment/contracts/customerAlignment.js +1 -0
  27. package/dist/fulfillment/contracts/dispatch.d.ts +143 -0
  28. package/dist/fulfillment/contracts/dispatch.js +1 -0
  29. package/dist/fulfillment/contracts/index.d.ts +18 -0
  30. package/dist/fulfillment/contracts/index.js +1 -0
  31. package/dist/fulfillment/contracts/label.d.ts +35 -0
  32. package/dist/fulfillment/contracts/label.js +1 -0
  33. package/dist/fulfillment/contracts/nativeUnsupported.d.ts +6 -0
  34. package/dist/fulfillment/contracts/nativeUnsupported.js +1 -0
  35. package/dist/fulfillment/contracts/observation.d.ts +72 -0
  36. package/dist/fulfillment/contracts/observation.js +1 -0
  37. package/dist/fulfillment/contracts/operator.d.ts +64 -0
  38. package/dist/fulfillment/contracts/operator.js +1 -0
  39. package/dist/fulfillment/contracts/read.d.ts +110 -0
  40. package/dist/fulfillment/contracts/read.js +1 -0
  41. package/dist/fulfillment/contracts/readback.d.ts +59 -0
  42. package/dist/fulfillment/contracts/readback.js +1 -0
  43. package/dist/fulfillment/contracts/replacement.d.ts +34 -0
  44. package/dist/fulfillment/contracts/replacement.js +1 -0
  45. package/dist/fulfillment/contracts/store.d.ts +89 -0
  46. package/dist/fulfillment/contracts/store.js +1 -0
  47. package/dist/fulfillment/contracts/sync.d.ts +226 -0
  48. package/dist/fulfillment/contracts/sync.js +1 -0
  49. package/dist/fulfillment/currentFulfillmentParcel.d.ts +2 -0
  50. package/dist/fulfillment/currentFulfillmentParcel.js +1 -0
  51. package/dist/fulfillment/delayReadModel.d.ts +11 -0
  52. package/dist/fulfillment/delayReadModel.js +45 -0
  53. package/dist/fulfillment/deliveryAlignmentReadModel.d.ts +4 -0
  54. package/dist/fulfillment/deliveryAlignmentReadModel.js +12 -0
  55. package/dist/fulfillment/dispatchProjection.d.ts +26 -0
  56. package/dist/fulfillment/dispatchProjection.js +107 -0
  57. package/dist/fulfillment/fulfillmentObservationEffects.d.ts +66 -0
  58. package/dist/fulfillment/fulfillmentObservationEffects.js +36 -0
  59. package/dist/fulfillment/handlerSchemas.d.ts +647 -0
  60. package/dist/fulfillment/handlerSchemas.js +213 -0
  61. package/dist/fulfillment/handlerSupport.d.ts +33 -0
  62. package/dist/fulfillment/handlerSupport.js +25 -0
  63. package/dist/fulfillment/index.d.ts +38 -0
  64. package/dist/fulfillment/index.js +37 -0
  65. package/dist/fulfillment/labelLifecycle.d.ts +24 -0
  66. package/dist/fulfillment/labelLifecycle.js +9 -0
  67. package/dist/fulfillment/lowStockEvidenceHandler.d.ts +36 -0
  68. package/dist/fulfillment/lowStockEvidenceHandler.js +46 -0
  69. package/dist/fulfillment/migrations.d.ts +32 -0
  70. package/dist/fulfillment/migrations.js +9 -0
  71. package/dist/fulfillment/nativeUnsupported.d.ts +10 -0
  72. package/dist/fulfillment/nativeUnsupported.js +18 -0
  73. package/dist/fulfillment/normalizedFulfillmentFacts.d.ts +2 -0
  74. package/dist/fulfillment/normalizedFulfillmentFacts.js +1 -0
  75. package/dist/fulfillment/observationProjection.d.ts +32 -0
  76. package/dist/fulfillment/observationProjection.js +90 -0
  77. package/dist/fulfillment/omnipack/capabilities.d.ts +3 -0
  78. package/dist/fulfillment/omnipack/capabilities.js +16 -0
  79. package/dist/fulfillment/omnipack/client.d.ts +39 -0
  80. package/dist/fulfillment/omnipack/client.js +172 -0
  81. package/dist/fulfillment/omnipack/index.d.ts +55 -0
  82. package/dist/fulfillment/omnipack/index.js +408 -0
  83. package/dist/fulfillment/omnipack/mappers.d.ts +79 -0
  84. package/dist/fulfillment/omnipack/mappers.js +199 -0
  85. package/dist/fulfillment/omnipack/observation.d.ts +28 -0
  86. package/dist/fulfillment/omnipack/observation.js +72 -0
  87. package/dist/fulfillment/omnipack/omnipackDispatchPayload.d.ts +36 -0
  88. package/dist/fulfillment/omnipack/omnipackDispatchPayload.js +63 -0
  89. package/dist/fulfillment/omnipack/omnipackOutboundOrderPayload.d.ts +83 -0
  90. package/dist/fulfillment/omnipack/omnipackOutboundOrderPayload.js +113 -0
  91. package/dist/fulfillment/omnipack/omnipackProductPackPayload.d.ts +11 -0
  92. package/dist/fulfillment/omnipack/omnipackProductPackPayload.js +38 -0
  93. package/dist/fulfillment/omnipack/omnipackProductPayload.d.ts +18 -0
  94. package/dist/fulfillment/omnipack/omnipackProductPayload.js +51 -0
  95. package/dist/fulfillment/omnipack/omnipackReconciliationPayload.d.ts +1 -0
  96. package/dist/fulfillment/omnipack/omnipackReconciliationPayload.js +3 -0
  97. package/dist/fulfillment/omnipack/omnipackStatusVocabulary.d.ts +4 -0
  98. package/dist/fulfillment/omnipack/omnipackStatusVocabulary.js +87 -0
  99. package/dist/fulfillment/omnipack/omnipackWebhookPayload.d.ts +9 -0
  100. package/dist/fulfillment/omnipack/omnipackWebhookPayload.js +76 -0
  101. package/dist/fulfillment/omnipack/productSyncMappers.d.ts +18 -0
  102. package/dist/fulfillment/omnipack/productSyncMappers.js +43 -0
  103. package/dist/fulfillment/omnipack/providerError.d.ts +25 -0
  104. package/dist/fulfillment/omnipack/providerError.js +47 -0
  105. package/dist/fulfillment/omnipack/reconciliation.d.ts +15 -0
  106. package/dist/fulfillment/omnipack/reconciliation.js +55 -0
  107. package/dist/fulfillment/omnipack/trackingReferences.d.ts +16 -0
  108. package/dist/fulfillment/omnipack/trackingReferences.js +52 -0
  109. package/dist/fulfillment/paidFulfillmentRecovery.d.ts +67 -0
  110. package/dist/fulfillment/paidFulfillmentRecovery.js +154 -0
  111. package/dist/fulfillment/paidHandoff.d.ts +27 -0
  112. package/dist/fulfillment/paidHandoff.js +86 -0
  113. package/dist/fulfillment/paidHandoffPorts.d.ts +24 -0
  114. package/dist/fulfillment/paidHandoffPorts.js +3 -0
  115. package/dist/fulfillment/postgresDeliveryAlignment.d.ts +4 -0
  116. package/dist/fulfillment/postgresDeliveryAlignment.js +12 -0
  117. package/dist/fulfillment/postgresDispatchStore.d.ts +16 -0
  118. package/dist/fulfillment/postgresDispatchStore.js +44 -0
  119. package/dist/fulfillment/postgresEvidenceReadPort.d.ts +25 -0
  120. package/dist/fulfillment/postgresEvidenceReadPort.js +45 -0
  121. package/dist/fulfillment/postgresPaidFulfillmentRecovery.d.ts +25 -0
  122. package/dist/fulfillment/postgresPaidFulfillmentRecovery.js +26 -0
  123. package/dist/fulfillment/postgresPaidHandoffStore.d.ts +4 -0
  124. package/dist/fulfillment/postgresPaidHandoffStore.js +10 -0
  125. package/dist/fulfillment/postgresShipmentSpine.d.ts +70 -0
  126. package/dist/fulfillment/postgresShipmentSpine.js +246 -0
  127. package/dist/fulfillment/postgresStockSyncPort.d.ts +8 -0
  128. package/dist/fulfillment/postgresStockSyncPort.js +66 -0
  129. package/dist/fulfillment/productReconciliationEvidenceHandler.d.ts +36 -0
  130. package/dist/fulfillment/productReconciliationEvidenceHandler.js +50 -0
  131. package/dist/fulfillment/providerCapabilities.d.ts +9 -0
  132. package/dist/fulfillment/providerCapabilities.js +17 -0
  133. package/dist/fulfillment/providerCommandLedger.d.ts +143 -0
  134. package/dist/fulfillment/providerCommandLedger.js +14 -0
  135. package/dist/fulfillment/providerDispatchAcceptance.d.ts +27 -0
  136. package/dist/fulfillment/providerDispatchAcceptance.js +29 -0
  137. package/dist/fulfillment/providerDispatchError.d.ts +6 -0
  138. package/dist/fulfillment/providerDispatchError.js +5 -0
  139. package/dist/fulfillment/providerDispatchWorker.d.ts +44 -0
  140. package/dist/fulfillment/providerDispatchWorker.js +199 -0
  141. package/dist/fulfillment/providerProductSyncWorker.d.ts +28 -0
  142. package/dist/fulfillment/providerProductSyncWorker.js +122 -0
  143. package/dist/fulfillment/providerReconciliationError.d.ts +9 -0
  144. package/dist/fulfillment/providerReconciliationError.js +17 -0
  145. package/dist/fulfillment/providerReconciliationTerminalSkip.d.ts +2 -0
  146. package/dist/fulfillment/providerReconciliationTerminalSkip.js +6 -0
  147. package/dist/fulfillment/providerReconciliationTimestamp.d.ts +1 -0
  148. package/dist/fulfillment/providerReconciliationTimestamp.js +27 -0
  149. package/dist/fulfillment/providerReconciliationWorker.d.ts +90 -0
  150. package/dist/fulfillment/providerReconciliationWorker.js +207 -0
  151. package/dist/fulfillment/providerStockAvailability.d.ts +13 -0
  152. package/dist/fulfillment/providerStockAvailability.js +51 -0
  153. package/dist/fulfillment/providerStockSyncWorker.d.ts +41 -0
  154. package/dist/fulfillment/providerStockSyncWorker.js +295 -0
  155. package/dist/fulfillment/providerTrackingReferences.d.ts +16 -0
  156. package/dist/fulfillment/providerTrackingReferences.js +23 -0
  157. package/dist/fulfillment/replacementRefusals.d.ts +5 -0
  158. package/dist/fulfillment/replacementRefusals.js +38 -0
  159. package/dist/fulfillment/replacementShipmentHandler.d.ts +5 -0
  160. package/dist/fulfillment/replacementShipmentHandler.js +46 -0
  161. package/dist/fulfillment/schemaCapabilities.d.ts +13 -0
  162. package/dist/fulfillment/schemaCapabilities.js +7 -0
  163. package/dist/fulfillment/shipmentsOverviewHandler.d.ts +16 -0
  164. package/dist/fulfillment/shipmentsOverviewHandler.js +54 -0
  165. package/dist/fulfillment/statusMap.d.ts +2 -0
  166. package/dist/fulfillment/statusMap.js +1 -0
  167. package/dist/fulfillment/trackingProgress.d.ts +1 -0
  168. package/dist/fulfillment/trackingProgress.js +1 -0
  169. package/dist/fulfillment/verifiedIngress.d.ts +79 -0
  170. package/dist/fulfillment/verifiedIngress.js +94 -0
  171. package/dist/invoicing/capabilities.d.ts +11 -0
  172. package/dist/invoicing/capabilities.js +10 -0
  173. package/dist/invoicing/contracts/capabilities.d.ts +40 -0
  174. package/dist/invoicing/contracts/capabilities.js +1 -0
  175. package/dist/invoicing/contracts/companyLookup.d.ts +49 -0
  176. package/dist/invoicing/contracts/companyLookup.js +1 -0
  177. package/dist/invoicing/contracts/delivery.d.ts +74 -0
  178. package/dist/invoicing/contracts/delivery.js +1 -0
  179. package/dist/invoicing/contracts/facts.d.ts +100 -0
  180. package/dist/invoicing/contracts/facts.js +1 -0
  181. package/dist/invoicing/contracts/host.d.ts +246 -0
  182. package/dist/invoicing/contracts/host.js +1 -0
  183. package/dist/invoicing/contracts/index.d.ts +16 -0
  184. package/dist/invoicing/contracts/index.js +1 -0
  185. package/dist/invoicing/contracts/provider.d.ts +126 -0
  186. package/dist/invoicing/contracts/provider.js +1 -0
  187. package/dist/invoicing/contracts/settlement.d.ts +66 -0
  188. package/dist/invoicing/contracts/settlement.js +1 -0
  189. package/dist/invoicing/contracts/store.d.ts +267 -0
  190. package/dist/invoicing/contracts/store.js +1 -0
  191. package/dist/invoicing/index.d.ts +1 -0
  192. package/dist/invoicing/index.js +1 -0
  193. package/dist/payments/stripe/index.d.ts +25 -0
  194. package/dist/payments/stripe/index.js +25 -0
  195. package/dist/payments/tpay/index.d.ts +30 -0
  196. package/dist/payments/tpay/index.js +30 -0
  197. package/dist/subscriptions/automaticRenewal.d.ts +44 -0
  198. package/dist/subscriptions/automaticRenewal.js +81 -0
  199. package/dist/subscriptions/automaticRenewalExecution.d.ts +21 -0
  200. package/dist/subscriptions/automaticRenewalExecution.js +44 -0
  201. package/dist/subscriptions/contracts/commands.d.ts +115 -0
  202. package/dist/subscriptions/contracts/commands.js +1 -0
  203. package/dist/subscriptions/contracts/dunning.d.ts +133 -0
  204. package/dist/subscriptions/contracts/dunning.js +1 -0
  205. package/dist/subscriptions/contracts/index.d.ts +6 -0
  206. package/dist/subscriptions/contracts/index.js +1 -0
  207. package/dist/subscriptions/contracts/messages.d.ts +43 -0
  208. package/dist/subscriptions/contracts/messages.js +1 -0
  209. package/dist/subscriptions/contracts/renewal.d.ts +533 -0
  210. package/dist/subscriptions/contracts/renewal.js +1 -0
  211. package/dist/subscriptions/contracts/stockWait.d.ts +73 -0
  212. package/dist/subscriptions/contracts/stockWait.js +1 -0
  213. package/dist/subscriptions/index.d.ts +39 -0
  214. package/dist/subscriptions/index.js +17 -0
  215. package/dist/subscriptions/paymentOutcomes.d.ts +8 -0
  216. package/dist/subscriptions/paymentOutcomes.js +27 -0
  217. package/dist/subscriptions/postgresRenewalStore.d.ts +20 -0
  218. package/dist/subscriptions/postgresRenewalStore.js +61 -0
  219. package/dist/subscriptions/postgresRetryStore.d.ts +78 -0
  220. package/dist/subscriptions/postgresRetryStore.js +142 -0
  221. package/dist/subscriptions/renewalCycleFailureMechanism.d.ts +34 -0
  222. package/dist/subscriptions/renewalCycleFailureMechanism.js +79 -0
  223. package/dist/subscriptions/renewalCycleMechanism.d.ts +46 -0
  224. package/dist/subscriptions/renewalCycleMechanism.js +157 -0
  225. package/dist/subscriptions/renewalCycleRefusalMechanism.d.ts +41 -0
  226. package/dist/subscriptions/renewalCycleRefusalMechanism.js +160 -0
  227. package/dist/subscriptions/renewalIdentity.d.ts +3 -0
  228. package/dist/subscriptions/renewalIdentity.js +4 -0
  229. package/package.json +37 -2
  230. package/release-gates.json +97 -3
  231. package/sql/20260808210000_fulfillment_shipment_rail.sql +810 -0
  232. package/sql/20260819150000_fulfillment_shipment_sequence.sql +98 -0
  233. package/sql/20261022080000_fulfillment_command_ledger.sql +786 -0
  234. package/sql/20261022090000_fulfillment_delivery_alignment.sql +1106 -0
  235. package/sql/20261022160000_subscription_retry_lifecycle.sql +328 -0
  236. package/sql/20261022165000_fulfillment_stock_evidence_replay_reopen.sql +30 -0
  237. package/src/composition/composeBundle.ts +4 -0
  238. package/src/composition/fulfillmentContribution.ts +28 -0
  239. package/src/composition/index.ts +1 -0
  240. package/src/fulfillment/adapterConformance.ts +195 -0
  241. package/src/fulfillment/bindings.ts +26 -0
  242. package/src/fulfillment/commerceFulfillmentHandlers.ts +263 -0
  243. package/src/fulfillment/commerceFulfillmentReadModel.ts +257 -0
  244. package/src/fulfillment/contracts/alignment.ts +13 -0
  245. package/src/fulfillment/contracts/bindings.ts +30 -0
  246. package/src/fulfillment/contracts/capabilities.ts +15 -0
  247. package/src/fulfillment/contracts/conformance.ts +63 -0
  248. package/src/fulfillment/contracts/customerAlignment.ts +4 -0
  249. package/src/fulfillment/contracts/dispatch.ts +73 -0
  250. package/src/fulfillment/contracts/index.ts +18 -0
  251. package/src/fulfillment/contracts/label.ts +9 -0
  252. package/src/fulfillment/contracts/nativeUnsupported.ts +6 -0
  253. package/src/fulfillment/contracts/observation.ts +26 -0
  254. package/src/fulfillment/contracts/operator.ts +31 -0
  255. package/src/fulfillment/contracts/read.ts +42 -0
  256. package/src/fulfillment/contracts/readback.ts +24 -0
  257. package/src/fulfillment/contracts/replacement.ts +15 -0
  258. package/src/fulfillment/contracts/store.ts +27 -0
  259. package/src/fulfillment/contracts/sync.ts +72 -0
  260. package/src/fulfillment/currentFulfillmentParcel.ts +2 -0
  261. package/src/fulfillment/delayReadModel.ts +60 -0
  262. package/src/fulfillment/deliveryAlignmentReadModel.ts +15 -0
  263. package/src/fulfillment/dispatchProjection.ts +105 -0
  264. package/src/fulfillment/fulfillmentObservationEffects.ts +86 -0
  265. package/src/fulfillment/handlerSchemas.ts +255 -0
  266. package/src/fulfillment/handlerSupport.ts +25 -0
  267. package/src/fulfillment/index.ts +39 -0
  268. package/src/fulfillment/labelLifecycle.ts +11 -0
  269. package/src/fulfillment/lowStockEvidenceHandler.ts +60 -0
  270. package/src/fulfillment/migrations.ts +9 -0
  271. package/src/fulfillment/nativeUnsupported.ts +23 -0
  272. package/src/fulfillment/normalizedFulfillmentFacts.ts +2 -0
  273. package/src/fulfillment/observationProjection.ts +92 -0
  274. package/src/fulfillment/omnipack/capabilities.ts +18 -0
  275. package/src/fulfillment/omnipack/client.ts +270 -0
  276. package/src/fulfillment/omnipack/index.ts +369 -0
  277. package/src/fulfillment/omnipack/mappers.ts +282 -0
  278. package/src/fulfillment/omnipack/observation.ts +79 -0
  279. package/src/fulfillment/omnipack/omnipackDispatchPayload.ts +93 -0
  280. package/src/fulfillment/omnipack/omnipackOutboundOrderPayload.ts +194 -0
  281. package/src/fulfillment/omnipack/omnipackProductPackPayload.ts +47 -0
  282. package/src/fulfillment/omnipack/omnipackProductPayload.ts +67 -0
  283. package/src/fulfillment/omnipack/omnipackReconciliationPayload.ts +7 -0
  284. package/src/fulfillment/omnipack/omnipackStatusVocabulary.ts +103 -0
  285. package/src/fulfillment/omnipack/omnipackWebhookPayload.ts +73 -0
  286. package/src/fulfillment/omnipack/productSyncMappers.ts +74 -0
  287. package/src/fulfillment/omnipack/providerError.ts +64 -0
  288. package/src/fulfillment/omnipack/reconciliation.ts +56 -0
  289. package/src/fulfillment/omnipack/trackingReferences.ts +77 -0
  290. package/src/fulfillment/paidFulfillmentRecovery.ts +252 -0
  291. package/src/fulfillment/paidHandoff.ts +122 -0
  292. package/src/fulfillment/paidHandoffPorts.ts +21 -0
  293. package/src/fulfillment/postgresDeliveryAlignment.ts +14 -0
  294. package/src/fulfillment/postgresDispatchStore.ts +55 -0
  295. package/src/fulfillment/postgresEvidenceReadPort.ts +59 -0
  296. package/src/fulfillment/postgresPaidFulfillmentRecovery.ts +29 -0
  297. package/src/fulfillment/postgresPaidHandoffStore.ts +11 -0
  298. package/src/fulfillment/postgresShipmentSpine.ts +338 -0
  299. package/src/fulfillment/postgresStockSyncPort.ts +68 -0
  300. package/src/fulfillment/productReconciliationEvidenceHandler.ts +64 -0
  301. package/src/fulfillment/providerCapabilities.ts +18 -0
  302. package/src/fulfillment/providerCommandLedger.ts +53 -0
  303. package/src/fulfillment/providerDispatchAcceptance.ts +37 -0
  304. package/src/fulfillment/providerDispatchError.ts +7 -0
  305. package/src/fulfillment/providerDispatchWorker.ts +159 -0
  306. package/src/fulfillment/providerProductSyncWorker.ts +154 -0
  307. package/src/fulfillment/providerReconciliationError.ts +20 -0
  308. package/src/fulfillment/providerReconciliationTerminalSkip.ts +8 -0
  309. package/src/fulfillment/providerReconciliationTimestamp.ts +34 -0
  310. package/src/fulfillment/providerReconciliationWorker.ts +206 -0
  311. package/src/fulfillment/providerStockAvailability.ts +60 -0
  312. package/src/fulfillment/providerStockSyncWorker.ts +318 -0
  313. package/src/fulfillment/providerTrackingReferences.ts +32 -0
  314. package/src/fulfillment/replacementRefusals.ts +43 -0
  315. package/src/fulfillment/replacementShipmentHandler.ts +47 -0
  316. package/src/fulfillment/schemaCapabilities.ts +7 -0
  317. package/src/fulfillment/shipmentsOverviewHandler.ts +73 -0
  318. package/src/fulfillment/statusMap.ts +2 -0
  319. package/src/fulfillment/trackingProgress.ts +1 -0
  320. package/src/fulfillment/verifiedIngress.ts +113 -0
  321. package/src/invoicing/capabilities.ts +9 -0
  322. package/src/invoicing/contracts/capabilities.ts +15 -0
  323. package/src/invoicing/contracts/companyLookup.ts +13 -0
  324. package/src/invoicing/contracts/delivery.ts +24 -0
  325. package/src/invoicing/contracts/facts.ts +60 -0
  326. package/src/invoicing/contracts/host.ts +85 -0
  327. package/src/invoicing/contracts/index.ts +16 -0
  328. package/src/invoicing/contracts/provider.ts +78 -0
  329. package/src/invoicing/contracts/settlement.ts +39 -0
  330. package/src/invoicing/contracts/store.ts +98 -0
  331. package/src/invoicing/index.ts +1 -0
  332. package/src/payments/stripe/index.ts +30 -0
  333. package/src/payments/tpay/index.ts +36 -0
  334. package/src/subscriptions/automaticRenewal.ts +87 -0
  335. package/src/subscriptions/automaticRenewalExecution.ts +39 -0
  336. package/src/subscriptions/contracts/commands.ts +46 -0
  337. package/src/subscriptions/contracts/dunning.ts +48 -0
  338. package/src/subscriptions/contracts/index.ts +6 -0
  339. package/src/subscriptions/contracts/messages.ts +18 -0
  340. package/src/subscriptions/contracts/renewal.ts +325 -0
  341. package/src/subscriptions/contracts/stockWait.ts +34 -0
  342. package/src/subscriptions/index.ts +24 -0
  343. package/src/subscriptions/paymentOutcomes.ts +23 -0
  344. package/src/subscriptions/postgresRenewalStore.ts +76 -0
  345. package/src/subscriptions/postgresRetryStore.ts +174 -0
  346. package/src/subscriptions/renewalCycleFailureMechanism.ts +119 -0
  347. package/src/subscriptions/renewalCycleMechanism.ts +225 -0
  348. package/src/subscriptions/renewalCycleRefusalMechanism.ts +215 -0
  349. package/src/subscriptions/renewalIdentity.ts +5 -0
@@ -0,0 +1,199 @@
1
+ import { mapOmnipackTrackingReferences, } from "./trackingReferences.js";
2
+ export function mapOmnipackOrderCreatedResponse(body) {
3
+ const response = asRecord(body);
4
+ const providerOrderId = readString(response.orderId);
5
+ if (!providerOrderId)
6
+ throw new Error("omnipack_order_response_invalid");
7
+ return {
8
+ provider: "omnipack",
9
+ providerOrderId,
10
+ raw: sanitizeOmnipackPayload(response),
11
+ };
12
+ }
13
+ // Catalog load (test-readiness). The product/inbound responses are evidence only — we read
14
+ // back authoritative stock via getStock. We tolerate a sparse response body and fall back to
15
+ // the request-side sku/reference so an idempotent re-create still yields usable evidence.
16
+ export function mapOmnipackProductCreatedResponse(body, requestSku) {
17
+ const response = asRecord(body);
18
+ return {
19
+ provider: "omnipack",
20
+ sku: readString(response.sku) || requestSku,
21
+ raw: sanitizeOmnipackPayload(response),
22
+ };
23
+ }
24
+ export function mapOmnipackStockResponse(body) {
25
+ const stockItems = readArray(asRecord(asRecord(body)._embedded).stockItems);
26
+ return stockItems.map((item) => {
27
+ const row = asRecord(item);
28
+ const totalQuantity = readNumber(row.totalQuantity);
29
+ const forSaleQuantity = readNumber(row.forSaleQuantity);
30
+ const unavailable = [
31
+ row.expireSoonQuantity,
32
+ row.faultyQuantity,
33
+ row.complaintsQuantity,
34
+ row.withheldQuantity,
35
+ row.packagingQuantity,
36
+ row.processingQuantity,
37
+ row.unpackingQuantity,
38
+ ].map(readNumber).reduce((sum, value) => sum + value, 0);
39
+ return {
40
+ provider: "omnipack",
41
+ sku: readString(row.sku),
42
+ totalQuantity,
43
+ forSaleQuantity,
44
+ reservedOrUnavailableQuantity: unavailable,
45
+ stockTruth: "external_stock_master_with_local_reservations",
46
+ };
47
+ });
48
+ }
49
+ export function mapOmnipackStockMovementsResponse(body) {
50
+ return readArray(asRecord(body)._embedded).map((item) => {
51
+ const row = asRecord(item);
52
+ return {
53
+ provider: "omnipack",
54
+ sku: readString(row.sku),
55
+ occurredAt: readNullableString(row.occurredAt),
56
+ quantity: readNumber(row.quantity),
57
+ operationType: readNullableString(row.operationType),
58
+ warehouseDocumentNumber: readNullableString(row.warehouseDocumentNumber),
59
+ lotNumber: readNullableString(row.productLotNumber),
60
+ expirationDate: readNullableString(row.expirationDate),
61
+ };
62
+ });
63
+ }
64
+ export function mapOmnipackFulfilmentsResponse(body) {
65
+ const fulfilments = readArray(asRecord(asRecord(body)._embedded).fulfilments);
66
+ return fulfilments.map((item) => {
67
+ const row = asRecord(item);
68
+ const trackingReferences = trackingReferencesFrom(row);
69
+ return {
70
+ provider: "omnipack",
71
+ providerOrderId: readNullableString(row.orderId) ?? readNullableString(row.providerOrderId),
72
+ fulfilmentNumber: readString(row.fulfilmentNumber),
73
+ externalNumber: readNullableString(row.externalNumber),
74
+ orderNumber: readNullableString(row.orderNumber),
75
+ createdAt: readNullableString(row.createdAt),
76
+ updatedAt: readNullableString(row.updatedAt),
77
+ status: readNullableString(row.status),
78
+ subStatus: readNullableString(row.subStatus),
79
+ trackingNumbers: trackingReferences.map((ref) => ref.trackingNumber),
80
+ trackingReferences,
81
+ items: readArray(row.items).map((rawItem) => {
82
+ const fulfilmentItem = asRecord(rawItem);
83
+ return {
84
+ sku: readString(fulfilmentItem.sku),
85
+ quantity: readNumber(fulfilmentItem.quantity),
86
+ lotNumber: readNullableString(fulfilmentItem.productLotNumber),
87
+ expirationDate: readNullableString(fulfilmentItem.expirationDate),
88
+ };
89
+ }),
90
+ };
91
+ });
92
+ }
93
+ export function mapOmnipackFulfilmentRequestsResponse(body) {
94
+ const requests = readArray(asRecord(asRecord(body)._embedded).fulfilmentRequests);
95
+ return requests.map((item) => {
96
+ const row = asRecord(item);
97
+ return {
98
+ provider: "omnipack",
99
+ warehouseDocumentNumber: readString(row.warehouseDocumentNumber),
100
+ warehouseName: readNullableString(row.warehouseName),
101
+ state: readNullableString(row.state),
102
+ };
103
+ });
104
+ }
105
+ export function mapOmnipackWebhookPayload(body, fallbackEvent = "", admitTrackingNumber, admitMetadata) {
106
+ const payload = asRecord(body);
107
+ const shipments = readArray(payload.shipments).map(asRecord);
108
+ let rejectedTrackingRefs = 0, rejectedServices = 0, rejectedTrackingUrls = 0;
109
+ // Count every supplied spelling before extraction, tracking refusal or first-wins deduplication.
110
+ if (admitMetadata)
111
+ for (const row of shipments) {
112
+ for (const value of [row.shippingMethod, row.service]) {
113
+ if (value != null && (typeof value !== "string" || !admitMetadata.service(value)))
114
+ rejectedServices++;
115
+ }
116
+ for (const value of [row.trackingUrl, row.trackingURL, row.trackingLink, row.publicTrackingUrl]) {
117
+ if (value != null && (typeof value !== "string" || !admitMetadata.url(value)))
118
+ rejectedTrackingUrls++;
119
+ }
120
+ }
121
+ // Admit and count original entries before the contributed extractor trims/deduplicates.
122
+ const admitted = admitTrackingNumber ? shipments.filter(row => {
123
+ if (admitTrackingNumber(readString(row.trackingNo) || readString(row.trackingNumber)))
124
+ return true;
125
+ rejectedTrackingRefs++;
126
+ return false;
127
+ }) : shipments;
128
+ const trackingReferences = trackingReferencesFrom({ shipments: admitted });
129
+ return {
130
+ provider: "omnipack",
131
+ event: readString(payload.event) || fallbackEvent,
132
+ ...(rejectedTrackingRefs ? { rejectedTrackingRefs } : {}),
133
+ ...(admitMetadata ? { rejectedServices, rejectedTrackingUrls } : {}),
134
+ providerOrderId: readNullableString(payload.orderId) ?? readNullableString(payload.providerOrderId),
135
+ orderNumber: readNullableString(payload.orderNumber),
136
+ fulfilmentNumber: readNullableString(payload.fulfilmentNumber),
137
+ occurredAt: readNullableString(payload.occurredAt),
138
+ trackingNumbers: trackingReferences.map((ref) => ref.trackingNumber),
139
+ trackingReferences,
140
+ shippingMethods: shipments.map((shipment) => readString(shipment.shippingMethod)).filter(Boolean),
141
+ };
142
+ }
143
+ export function sanitizeOmnipackPayload(input) {
144
+ const blocked = new Set([
145
+ "authorization",
146
+ "Authorization",
147
+ "password",
148
+ "email",
149
+ "phone",
150
+ "firstName",
151
+ "lastName",
152
+ "name",
153
+ "address",
154
+ "street",
155
+ "streetNumber",
156
+ "houseNo",
157
+ "flatNo",
158
+ "city",
159
+ "postalCode",
160
+ ]);
161
+ return sanitizeRecord(input, blocked);
162
+ }
163
+ function sanitizeRecord(input, blocked) {
164
+ return Object.fromEntries(Object.entries(input)
165
+ .filter(([key]) => !blocked.has(key))
166
+ .map(([key, value]) => [key, sanitizeValue(value, blocked)]));
167
+ }
168
+ function sanitizeValue(input, blocked) {
169
+ if (Array.isArray(input))
170
+ return input.map((value) => sanitizeValue(value, blocked));
171
+ if (input && typeof input === "object")
172
+ return sanitizeRecord(input, blocked);
173
+ return input;
174
+ }
175
+ function asRecord(input) {
176
+ return input && typeof input === "object" && !Array.isArray(input) ? input : {};
177
+ }
178
+ function readArray(input) {
179
+ return Array.isArray(input) ? input : [];
180
+ }
181
+ function readString(input) {
182
+ return typeof input === "string" ? input : "";
183
+ }
184
+ function readNullableString(input) {
185
+ const value = readString(input);
186
+ return value || null;
187
+ }
188
+ function readNumber(input) {
189
+ return typeof input === "number" && Number.isFinite(input) ? input : 0;
190
+ }
191
+ function trackingReferencesFrom(row) {
192
+ return mapOmnipackTrackingReferences({
193
+ shipments: readArray(row.shipments),
194
+ trackingNumbers: readArray(row.trackingNumbers),
195
+ readString,
196
+ readNullableString,
197
+ asRecord,
198
+ });
199
+ }
@@ -0,0 +1,28 @@
1
+ export { reference } from "../dispatchProjection.js";
2
+ import type { CanonicalLocalFulfillmentStatus, FulfillmentObservation, FulfillmentObservationCodecs, FulfillmentRefusal } from "../contracts/index.js";
3
+ import type { OmnipackWebhookEvidence } from "./mappers.js";
4
+ import { type OmnipackWebhookRouteEvent } from "./omnipackWebhookPayload.js";
5
+ export declare const refusal: (reason: FulfillmentRefusal["reason"], phase: FulfillmentRefusal["phase"], retryable?: boolean) => FulfillmentRefusal;
6
+ export declare const digest: (bytes: string | Uint8Array) => string;
7
+ /** Share admission with the durable sink, including explicit deny allowlists. */
8
+ export declare function correlationReference(value: string | null | undefined, codecs?: OmnipackObservationCodecs): string | null;
9
+ export interface OmnipackObservationCodecs extends FulfillmentObservationCodecs {
10
+ normalizeCarrier?(input: {
11
+ carrierRef: string | null;
12
+ serviceRef: string | null;
13
+ }): string | null;
14
+ }
15
+ export declare function timestamp(value: string | null): string | null;
16
+ export declare function eventKind(value: string): OmnipackWebhookRouteEvent | null;
17
+ export declare function observation(input: {
18
+ evidence: OmnipackWebhookEvidence;
19
+ event: FulfillmentObservation["eventKind"];
20
+ status?: CanonicalLocalFulfillmentStatus;
21
+ receivedAt: string;
22
+ rawDigest: string;
23
+ evidenceRef: `evidence:${string}`;
24
+ source: "provider_webhook" | "provider_reconciliation";
25
+ fulfillmentRef?: string;
26
+ approveTrackingUrl: (url: string) => boolean;
27
+ observationCodecs?: OmnipackObservationCodecs;
28
+ }): FulfillmentObservation;
@@ -0,0 +1,72 @@
1
+ import { admittedReference, reference } from "../dispatchProjection.js";
2
+ import { projectObservation, publicTrackingUrl } from "../observationProjection.js";
3
+ export { reference } from "../dispatchProjection.js";
4
+ import { createHash } from "node:crypto";
5
+ import { parseNormalizedFulfillmentFact } from "@openlup/core/fulfillment";
6
+ import { buildProviderEventId, EVENT_TO_STATUS } from "./omnipackWebhookPayload.js";
7
+ import { localStatusFor } from "./omnipackStatusVocabulary.js";
8
+ export const refusal = (reason, phase, retryable = false) => ({ reason, phase, retryable });
9
+ export const digest = (bytes) => createHash("sha256").update(bytes).digest("hex");
10
+ /** Share admission with the durable sink, including explicit deny allowlists. */
11
+ export function correlationReference(value, codecs = {}) {
12
+ return admittedReference(value, codecs.approveReference);
13
+ }
14
+ export function timestamp(value) {
15
+ return value && /^\d{4}-\d\d-\d\dT/u.test(value) && Number.isFinite(Date.parse(value)) ? new Date(value).toISOString() : null;
16
+ }
17
+ export function eventKind(value) {
18
+ return Object.hasOwn(EVENT_TO_STATUS, value) ? value : null;
19
+ }
20
+ function tracking(refs, codecs, approve) {
21
+ let rejectedTrackingRefs = 0, rejectedServices = 0, rejectedTrackingUrls = 0;
22
+ const trackingRefs = [];
23
+ for (const item of refs) {
24
+ if (item.service !== null && !correlationReference(item.service, codecs))
25
+ rejectedServices++;
26
+ if (item.trackingUrl !== null && !publicTrackingUrl(item.trackingUrl, approve, codecs.trackingUrl))
27
+ rejectedTrackingUrls++;
28
+ const trackingNumber = correlationReference(item.trackingNumber, codecs);
29
+ if (!trackingNumber) {
30
+ rejectedTrackingRefs++;
31
+ continue;
32
+ }
33
+ // Service admission precedes any derivation. A refused service cannot leak a prefix.
34
+ const serviceRef = correlationReference(item.service, codecs);
35
+ const carrierRef = item.service !== null && !serviceRef ? null : reference(codecs.normalizeCarrier
36
+ ? codecs.normalizeCarrier({ carrierRef: item.carrier, serviceRef })
37
+ : serviceRef?.split("_")[0]?.toLowerCase());
38
+ trackingRefs.push({ trackingNumber, carrierRef, serviceRef: item.service, publicUrl: item.trackingUrl });
39
+ }
40
+ return { trackingRefs, rejectedTrackingRefs, rejectedServices, rejectedTrackingUrls };
41
+ }
42
+ export function observation(input) {
43
+ const evidence = input.evidence;
44
+ const codecs = input.observationCodecs ?? {};
45
+ const externalRef = correlationReference(evidence.providerOrderId, codecs);
46
+ const providerFulfillmentRef = correlationReference(evidence.fulfilmentNumber, codecs);
47
+ const orderNumber = correlationReference(evidence.orderNumber, codecs);
48
+ const fulfillmentRef = reference(input.fulfillmentRef) ?? providerFulfillmentRef ?? externalRef ?? orderNumber;
49
+ if (!fulfillmentRef || input.source === "provider_webhook" && [evidence.providerOrderId, evidence.orderNumber, evidence.fulfilmentNumber].some(value => value !== null && !correlationReference(value, codecs)))
50
+ throw refusal("missing_correlation", "normalize");
51
+ const occurredAt = timestamp(evidence.occurredAt);
52
+ if (evidence.occurredAt && !occurredAt)
53
+ throw refusal("malformed", "normalize");
54
+ // Compose the key with the provider's
55
+ // original bytes, including minute precision and offsets, rather than the UTC fact.
56
+ const key = buildProviderEventId(evidence);
57
+ const normalizedTracking = tracking(evidence.trackingReferences, codecs, input.approveTrackingUrl);
58
+ const rejectedTrackingRefs = normalizedTracking.rejectedTrackingRefs + (evidence.rejectedTrackingRefs ?? 0)
59
+ + (evidence.rejectedServices ?? normalizedTracking.rejectedServices);
60
+ const status = input.status ?? localStatusFor(EVENT_TO_STATUS[input.event]);
61
+ const fact = parseNormalizedFulfillmentFact({
62
+ schemaVersion: 1, mapperVersion: "1", factId: digest(key), providerKind: "omnipack", fulfillmentReference: reference(fulfillmentRef) ?? digest(fulfillmentRef),
63
+ canonicalStatus: status, provenance: { source: input.source, authority: "provider_asserted" },
64
+ occurredAt, receivedAt: input.receivedAt,
65
+ rawEvent: { reference: input.evidenceRef, digestAlgorithm: "sha256", digest: input.rawDigest },
66
+ }, { isCanonicalStatus: (value) => ["provider_received", "picking", "packed", "in_transit", "delivered", "exception", "cancelled"].includes(value) });
67
+ return projectObservation({ fact, eventKind: input.event, eventKey: key, firstReceivedAt: input.receivedAt,
68
+ correlation: { orderRef: null, fulfillmentRef: reference(input.fulfillmentRef), externalRef: evidence.providerOrderId, orderNumber: evidence.orderNumber, providerFulfillmentRef: evidence.fulfilmentNumber, parcelRef: null },
69
+ trackingRefs: normalizedTracking.trackingRefs, diagnostics: { admission: {
70
+ rejectedTrackingRefs, rejectedTrackingUrls: evidence.rejectedTrackingUrls ?? normalizedTracking.rejectedTrackingUrls,
71
+ } } }, input.approveTrackingUrl, codecs);
72
+ }
@@ -0,0 +1,36 @@
1
+ import { buildOmnipackOutboundOrderEvidence, type OmnipackOutboundOrderPayload, type OmnipackOutboundDeliverySelection } from "./omnipackOutboundOrderPayload.js";
2
+ export interface OmnipackDispatchCandidate {
3
+ orderId: string;
4
+ orderNumber: string | null;
5
+ deliveryContact: {
6
+ revision: number;
7
+ recipientName: string | null;
8
+ contactEmail: string | null;
9
+ contactPhone: string | null;
10
+ line1: string;
11
+ city: string;
12
+ postalCode: string;
13
+ country: string;
14
+ selectedDelivery: OmnipackOutboundDeliverySelection | null;
15
+ } | null;
16
+ lines: Array<{
17
+ sku: string;
18
+ quantity: number;
19
+ productSnapshot: Record<string, unknown>;
20
+ }>;
21
+ }
22
+ export { buildOmnipackOutboundOrderEvidence as buildSanitizedEvidence };
23
+ export declare function buildOmnipackDispatchCommand(candidate: OmnipackDispatchCandidate): {
24
+ providerPayload: OmnipackOutboundOrderPayload;
25
+ body: string;
26
+ sanitizedRequest: {
27
+ deliveryContactRevision: number;
28
+ };
29
+ requestFingerprint: string;
30
+ };
31
+ export declare function buildOmnipackDispatchPayloadFromCandidate(candidate: OmnipackDispatchCandidate): OmnipackOutboundOrderPayload;
32
+ export declare function stableDispatchHash(value: unknown): string;
33
+ export declare function serializeOmnipackDispatchPayload(value: unknown): {
34
+ body: string;
35
+ requestFingerprint: string;
36
+ };
@@ -0,0 +1,63 @@
1
+ import { createHash } from "node:crypto";
2
+ import { buildOmnipackOutboundOrderEvidence, buildOmnipackOutboundOrderPayload, } from "./omnipackOutboundOrderPayload.js";
3
+ export { buildOmnipackOutboundOrderEvidence as buildSanitizedEvidence };
4
+ export function buildOmnipackDispatchCommand(candidate) {
5
+ const providerPayload = buildOmnipackDispatchPayloadFromCandidate(candidate);
6
+ const sanitizedRequest = {
7
+ ...buildOmnipackOutboundOrderEvidence(providerPayload),
8
+ deliveryContactRevision: candidate.deliveryContact?.revision ?? 0,
9
+ };
10
+ const serialized = serializeOmnipackDispatchPayload(providerPayload);
11
+ return {
12
+ providerPayload,
13
+ body: serialized.body,
14
+ sanitizedRequest,
15
+ // The hash commits to the request that may create a real provider effect.
16
+ // Only its digest is persisted; the PII-bearing input is never evidence.
17
+ requestFingerprint: serialized.requestFingerprint,
18
+ };
19
+ }
20
+ export function buildOmnipackDispatchPayloadFromCandidate(candidate) {
21
+ const contact = candidate.deliveryContact;
22
+ if (!contact)
23
+ throw new Error("omnipack_order_payload_missing_delivery_contact");
24
+ return buildOmnipackOutboundOrderPayload({
25
+ orderNumber: candidate.orderNumber ?? candidate.orderId,
26
+ deliverySelection: contact.selectedDelivery,
27
+ recipient: {
28
+ name: contact.recipientName ?? "",
29
+ email: contact.contactEmail,
30
+ phone: contact.contactPhone,
31
+ },
32
+ address: {
33
+ line1: contact.line1,
34
+ city: contact.city,
35
+ postalCode: contact.postalCode,
36
+ country: contact.country,
37
+ },
38
+ items: candidate.lines.map((line) => ({
39
+ sku: line.sku,
40
+ quantity: line.quantity,
41
+ lotNumber: nullableText(line.productSnapshot.lotNumber ?? line.productSnapshot.lotCode),
42
+ expirationDate: nullableText(line.productSnapshot.expirationDate ?? line.productSnapshot.expiresAt),
43
+ })),
44
+ });
45
+ }
46
+ export function stableDispatchHash(value) {
47
+ return serializeOmnipackDispatchPayload(value).requestFingerprint;
48
+ }
49
+ // Materialize once: the digest and createOrder consume these exact UTF-8 bytes.
50
+ export function serializeOmnipackDispatchPayload(value) {
51
+ const body = JSON.stringify(sortRecord(value));
52
+ return { body, requestFingerprint: createHash("sha256").update(body).digest("hex") };
53
+ }
54
+ function sortRecord(value) {
55
+ if (Array.isArray(value))
56
+ return value.map(sortRecord);
57
+ if (!value || typeof value !== "object")
58
+ return value;
59
+ return Object.fromEntries(Object.entries(value).sort().map(([key, child]) => [key, sortRecord(child)]));
60
+ }
61
+ function nullableText(value) {
62
+ return typeof value === "string" && value.trim() ? value.trim() : null;
63
+ }
@@ -0,0 +1,83 @@
1
+ export type OmnipackOutboundDeliveryKind = "courier" | "parcel-locker";
2
+ export interface OmnipackOutboundOrderInput {
3
+ orderNumber: string;
4
+ description?: string | null;
5
+ additionalCustomerOrderNumber?: string | null;
6
+ deliverySelection: OmnipackOutboundDeliverySelection | null;
7
+ recipient: {
8
+ name: string;
9
+ email: string | null;
10
+ phone: string | null;
11
+ };
12
+ address: {
13
+ line1: string;
14
+ city: string;
15
+ postalCode: string;
16
+ country: string;
17
+ };
18
+ items: Array<{
19
+ sku: string;
20
+ quantity: number;
21
+ lotNumber?: string | null;
22
+ expirationDate?: string | null;
23
+ }>;
24
+ orderValue?: {
25
+ amount: number;
26
+ currency: string;
27
+ } | null;
28
+ }
29
+ export interface OmnipackOutboundDeliverySelection {
30
+ providerKind?: string | null;
31
+ carrierKind?: string | null;
32
+ carrierCode?: string | null;
33
+ serviceCode?: string | null;
34
+ service?: string | null;
35
+ deliveryKind?: string | null;
36
+ kind?: string | null;
37
+ pickupPoint?: {
38
+ id?: string | null;
39
+ pointId?: string | null;
40
+ name?: string | null;
41
+ address?: {
42
+ line1?: string | null;
43
+ postalCode?: string | null;
44
+ city?: string | null;
45
+ country?: string | null;
46
+ } | null;
47
+ } | null;
48
+ }
49
+ export interface OmnipackOutboundOrderPayload {
50
+ orderNumber: string;
51
+ description?: string;
52
+ additionalCustomerOrderNumber?: string;
53
+ items: Array<{
54
+ sku: string;
55
+ quantity: number;
56
+ lotNumber?: string;
57
+ expirationDate?: string;
58
+ }>;
59
+ shippingDetails: {
60
+ carrier: string;
61
+ service: string;
62
+ address: {
63
+ name: string;
64
+ street: string;
65
+ city: string;
66
+ postCode: string;
67
+ phone: string;
68
+ email?: string;
69
+ country: string;
70
+ };
71
+ pickUpPoint?: string;
72
+ };
73
+ orderValue?: {
74
+ amount: number;
75
+ currency: string;
76
+ };
77
+ }
78
+ export declare class OmnipackOutboundOrderPayloadError extends Error {
79
+ readonly code: string;
80
+ constructor(code: string);
81
+ }
82
+ export declare function buildOmnipackOutboundOrderPayload(input: OmnipackOutboundOrderInput): OmnipackOutboundOrderPayload;
83
+ export declare function buildOmnipackOutboundOrderEvidence(payload: OmnipackOutboundOrderPayload): Record<string, unknown>;
@@ -0,0 +1,113 @@
1
+ export class OmnipackOutboundOrderPayloadError extends Error {
2
+ code;
3
+ constructor(code) {
4
+ super(code);
5
+ this.code = code;
6
+ this.name = "OmnipackOutboundOrderPayloadError";
7
+ }
8
+ }
9
+ export function buildOmnipackOutboundOrderPayload(input) {
10
+ const orderNumber = requiredText(input.orderNumber, "omnipack_order_payload_missing_order_number");
11
+ const selection = input.deliverySelection;
12
+ const providerKind = optionalText(selection?.providerKind);
13
+ if (providerKind !== "omnipack") {
14
+ throw new OmnipackOutboundOrderPayloadError("omnipack_order_payload_missing_omnipack_delivery_selection");
15
+ }
16
+ const service = requiredText(selection?.serviceCode ?? selection?.service, "omnipack_order_payload_missing_service");
17
+ const carrier = service;
18
+ const deliveryKind = readDeliveryKind(selection);
19
+ const pickUpPoint = readPickUpPoint(deliveryKind, selection);
20
+ const items = input.items.map((item) => {
21
+ const lotNumber = optionalText(item.lotNumber);
22
+ const expirationDate = optionalText(item.expirationDate);
23
+ return {
24
+ sku: requiredText(item.sku, "omnipack_order_payload_missing_sku"),
25
+ quantity: requiredQuantity(item.quantity),
26
+ ...(lotNumber ? { lotNumber } : {}),
27
+ ...(expirationDate ? { expirationDate } : {}),
28
+ };
29
+ });
30
+ if (items.length === 0) {
31
+ throw new OmnipackOutboundOrderPayloadError("omnipack_order_payload_missing_items");
32
+ }
33
+ return compactRecord({
34
+ orderNumber,
35
+ description: optionalText(input.description),
36
+ additionalCustomerOrderNumber: optionalText(input.additionalCustomerOrderNumber),
37
+ items,
38
+ shippingDetails: compactRecord({
39
+ carrier,
40
+ service,
41
+ address: compactRecord({
42
+ name: requiredText(input.recipient.name, "omnipack_order_payload_missing_recipient_name"),
43
+ street: requiredText(input.address.line1, "omnipack_order_payload_missing_address_street"),
44
+ city: requiredText(input.address.city, "omnipack_order_payload_missing_address_city"),
45
+ postCode: requiredText(input.address.postalCode, "omnipack_order_payload_missing_address_post_code"),
46
+ phone: requiredText(input.recipient.phone, "omnipack_order_payload_missing_recipient_phone"),
47
+ email: optionalText(input.recipient.email),
48
+ country: requiredText(input.address.country, "omnipack_order_payload_missing_address_country"),
49
+ }),
50
+ pickUpPoint,
51
+ }),
52
+ orderValue: validOrderValue(input.orderValue),
53
+ });
54
+ }
55
+ export function buildOmnipackOutboundOrderEvidence(payload) {
56
+ return {
57
+ provider: "omnipack",
58
+ requestKind: "outbound_order",
59
+ orderNumber: payload.orderNumber,
60
+ carrier: payload.shippingDetails.carrier,
61
+ service: payload.shippingDetails.service,
62
+ pickUpPoint: payload.shippingDetails.pickUpPoint ?? null,
63
+ itemCount: payload.items.length,
64
+ items: payload.items.map((item) => ({
65
+ sku: item.sku,
66
+ quantity: item.quantity,
67
+ lotNumber: item.lotNumber ?? null,
68
+ expirationDate: item.expirationDate ?? null,
69
+ })),
70
+ stockTruth: "external_stock_master_with_local_reservations",
71
+ };
72
+ }
73
+ function readDeliveryKind(selection) {
74
+ const value = optionalText(selection?.deliveryKind ?? selection?.kind);
75
+ if (value === "courier" || value === "parcel-locker")
76
+ return value;
77
+ throw new OmnipackOutboundOrderPayloadError("omnipack_order_payload_missing_delivery_kind");
78
+ }
79
+ function readPickUpPoint(deliveryKind, selection) {
80
+ if (deliveryKind !== "parcel-locker")
81
+ return undefined;
82
+ const point = optionalText(selection?.pickupPoint?.id ?? selection?.pickupPoint?.pointId);
83
+ if (!point)
84
+ throw new OmnipackOutboundOrderPayloadError("omnipack_order_payload_missing_pickup_point");
85
+ return point;
86
+ }
87
+ function requiredText(value, code) {
88
+ const text = optionalText(value);
89
+ if (!text)
90
+ throw new OmnipackOutboundOrderPayloadError(code);
91
+ return text;
92
+ }
93
+ function optionalText(value) {
94
+ return typeof value === "string" && value.trim() ? value.trim() : undefined;
95
+ }
96
+ function requiredQuantity(value) {
97
+ if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
98
+ throw new OmnipackOutboundOrderPayloadError("omnipack_order_payload_invalid_quantity");
99
+ }
100
+ return value;
101
+ }
102
+ function validOrderValue(value) {
103
+ if (!value)
104
+ return undefined;
105
+ if (typeof value.amount !== "number" || value.amount <= 0 || !Number.isFinite(value.amount)) {
106
+ throw new OmnipackOutboundOrderPayloadError("omnipack_order_payload_invalid_order_value");
107
+ }
108
+ const currency = requiredText(value.currency, "omnipack_order_payload_missing_order_value_currency");
109
+ return { amount: value.amount, currency };
110
+ }
111
+ function compactRecord(record) {
112
+ return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined));
113
+ }
@@ -0,0 +1,11 @@
1
+ export type OmnipackPackKind = "unit" | "collective";
2
+ export interface OmnipackProductPackInput {
3
+ ean: string;
4
+ quantity: number;
5
+ }
6
+ export declare class OmnipackProductPackPayloadError extends Error {
7
+ readonly code: string;
8
+ constructor(code: string);
9
+ }
10
+ export declare function omnipackPackKindForQuantity(quantity: number): OmnipackPackKind;
11
+ export declare function buildOmnipackProductPackPayload(input: OmnipackProductPackInput): Record<string, unknown>;
@@ -0,0 +1,38 @@
1
+ // Pure builder for the OmniPack product-pack request (POST /products/{sku}/packs). A pack is
2
+ // one EAN bound to a product: quantity === 1 is a sellable unit, quantity > 1 is a collective
3
+ // carton (N units behind one barcode). One SKU therefore maps to MANY packs (unit barcode / alternate barcode
4
+ // / collective carton). Mirrors the product/inbound payload convention (pure builder in
5
+ // server/_lib, wired through the client). The exact OmniPack request key names live behind the
6
+ // constants below so finalizing them against the (auth-gated) OmniPack product API docs is a
7
+ // one-line edit.
8
+ // Product-pack request key names (confirm against the OmniPack product-pack API docs).
9
+ const KEY_EAN = "ean";
10
+ const KEY_QUANTITY = "quantity";
11
+ export class OmnipackProductPackPayloadError extends Error {
12
+ code;
13
+ constructor(code) {
14
+ super(`omnipack_product_pack_payload_invalid: ${code}`);
15
+ this.code = code;
16
+ this.name = "OmnipackProductPackPayloadError";
17
+ }
18
+ }
19
+ function requireNonEmpty(value, code) {
20
+ const trimmed = value?.trim();
21
+ if (!trimmed)
22
+ throw new OmnipackProductPackPayloadError(code);
23
+ return trimmed;
24
+ }
25
+ // A pack with quantity 1 is a sellable unit; quantity > 1 is a collective carton. Pure so the
26
+ // push worker and the DB layer derive the same `kind` from the same rule.
27
+ export function omnipackPackKindForQuantity(quantity) {
28
+ return quantity > 1 ? "collective" : "unit";
29
+ }
30
+ // Builds the product-pack payload. EAN is required (OmniPack matches physical goods by barcode);
31
+ // quantity must be a positive integer (the number of sellable units behind this EAN).
32
+ export function buildOmnipackProductPackPayload(input) {
33
+ const ean = requireNonEmpty(input.ean, "missing_ean");
34
+ if (!Number.isInteger(input.quantity) || input.quantity <= 0) {
35
+ throw new OmnipackProductPackPayloadError("invalid_quantity");
36
+ }
37
+ return { [KEY_EAN]: ean, [KEY_QUANTITY]: input.quantity };
38
+ }
@@ -0,0 +1,18 @@
1
+ export interface OmnipackProductPack {
2
+ weightGrams: number;
3
+ lengthMm: number;
4
+ widthMm: number;
5
+ heightMm: number;
6
+ }
7
+ export interface OmnipackProductInput {
8
+ sku: string;
9
+ ean: string | null;
10
+ productGroup: string;
11
+ title: string;
12
+ pack: OmnipackProductPack | null;
13
+ }
14
+ export declare class OmnipackProductPayloadError extends Error {
15
+ readonly code: string;
16
+ constructor(code: string);
17
+ }
18
+ export declare function buildOmnipackProductPayload(input: OmnipackProductInput): Record<string, unknown>;