@openlup/platform 0.17.0 → 0.18.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 (486) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/README.md +284 -6
  3. package/dist/catalog/activeSkuSelection.d.ts +2 -0
  4. package/dist/catalog/activeSkuSelection.js +20 -0
  5. package/dist/catalog/adminBindings.d.ts +72 -0
  6. package/dist/catalog/adminBindings.js +1 -0
  7. package/dist/catalog/adminBundleHandler.d.ts +26 -0
  8. package/dist/catalog/adminBundleHandler.js +111 -0
  9. package/dist/catalog/adminBundleReadHandler.d.ts +20 -0
  10. package/dist/catalog/adminBundleReadHandler.js +185 -0
  11. package/dist/catalog/adminBundleWritePort.d.ts +85 -0
  12. package/dist/catalog/adminBundleWritePort.js +1 -0
  13. package/dist/catalog/bundleAvailability.d.ts +63 -0
  14. package/dist/catalog/bundleAvailability.js +78 -0
  15. package/dist/catalog/bundleAvailabilityService.d.ts +65 -0
  16. package/dist/catalog/bundleAvailabilityService.js +89 -0
  17. package/dist/catalog/bundleBindings.d.ts +33 -0
  18. package/dist/catalog/bundleBindings.js +1 -0
  19. package/dist/catalog/bundleCatalogQueries.d.ts +28 -0
  20. package/dist/catalog/bundleCatalogQueries.js +84 -0
  21. package/dist/catalog/bundleCatalogReadPort.d.ts +166 -0
  22. package/dist/catalog/bundleCatalogReadPort.js +36 -0
  23. package/dist/catalog/bundleCatalogStore.d.ts +3 -0
  24. package/dist/catalog/bundleCatalogStore.js +152 -0
  25. package/dist/catalog/bundleRuleCodes.d.ts +41 -0
  26. package/dist/catalog/bundleRuleCodes.js +110 -0
  27. package/dist/catalog/bundleRules.d.ts +69 -0
  28. package/dist/catalog/bundleRules.js +102 -0
  29. package/dist/catalog/catalogDraftStore.d.ts +4 -0
  30. package/dist/catalog/catalogDraftStore.js +63 -0
  31. package/dist/catalog/catalogSkuEnvelope.d.ts +7 -0
  32. package/dist/catalog/catalogSkuEnvelope.js +142 -0
  33. package/dist/catalog/catalogSkuEnvelopeMapper.d.ts +38 -0
  34. package/dist/catalog/catalogSkuEnvelopeMapper.js +88 -0
  35. package/dist/catalog/contracts/bundleAdmin.d.ts +143 -0
  36. package/dist/catalog/contracts/bundleAdmin.js +1 -0
  37. package/dist/catalog/contracts/bundleAvailability.d.ts +61 -0
  38. package/dist/catalog/contracts/bundleAvailability.js +1 -0
  39. package/dist/catalog/contracts/bundleRead.d.ts +223 -0
  40. package/dist/catalog/contracts/bundleRead.js +1 -0
  41. package/dist/catalog/contracts/draft.d.ts +79 -0
  42. package/dist/catalog/contracts/draft.js +47 -0
  43. package/dist/catalog/contracts/foundation.d.ts +78 -0
  44. package/dist/catalog/contracts/foundation.js +53 -0
  45. package/dist/catalog/contracts/index.d.ts +14 -0
  46. package/dist/catalog/contracts/index.js +6 -0
  47. package/dist/catalog/contracts/lifecycle.d.ts +77 -0
  48. package/dist/catalog/contracts/lifecycle.js +1 -0
  49. package/dist/catalog/contracts/productMediaContracts.d.ts +77 -0
  50. package/dist/catalog/contracts/productMediaContracts.js +149 -0
  51. package/dist/catalog/contracts/productTypes.d.ts +54 -0
  52. package/dist/catalog/contracts/productTypes.js +16 -0
  53. package/dist/catalog/contracts/resolveProductMedia.d.ts +3 -0
  54. package/dist/catalog/contracts/resolveProductMedia.js +78 -0
  55. package/dist/catalog/contracts/sellable.d.ts +23 -0
  56. package/dist/catalog/contracts/sellable.js +1 -0
  57. package/dist/catalog/draftHandler.d.ts +25 -0
  58. package/dist/catalog/draftHandler.js +118 -0
  59. package/dist/catalog/draftPorts.d.ts +18 -0
  60. package/dist/catalog/draftPorts.js +8 -0
  61. package/dist/catalog/draftSchemas.d.ts +423 -0
  62. package/dist/catalog/draftSchemas.js +89 -0
  63. package/dist/catalog/draftValidation.d.ts +21 -0
  64. package/dist/catalog/draftValidation.js +125 -0
  65. package/dist/catalog/foundationSchemas.d.ts +98 -0
  66. package/dist/catalog/foundationSchemas.js +110 -0
  67. package/dist/catalog/index.d.ts +43 -0
  68. package/dist/catalog/index.js +25 -0
  69. package/dist/catalog/mediaSourcePack.d.ts +51 -0
  70. package/dist/catalog/mediaSourcePack.js +247 -0
  71. package/dist/catalog/productTypeSchemas.d.ts +46 -0
  72. package/dist/catalog/productTypeSchemas.js +72 -0
  73. package/dist/catalog/publicationPorts.d.ts +42 -0
  74. package/dist/catalog/publicationPorts.js +1 -0
  75. package/dist/catalog/readPorts.d.ts +51 -0
  76. package/dist/catalog/readPorts.js +1 -0
  77. package/dist/catalog/referenceCatalogHandler.d.ts +7 -0
  78. package/dist/catalog/referenceCatalogHandler.js +27 -0
  79. package/dist/catalog/resolvedSkuProjection.d.ts +88 -0
  80. package/dist/catalog/resolvedSkuProjection.js +60 -0
  81. package/dist/catalog/sellableBundleHandler.d.ts +46 -0
  82. package/dist/catalog/sellableBundleHandler.js +84 -0
  83. package/dist/catalog/sellableSchemas.d.ts +46 -0
  84. package/dist/catalog/sellableSchemas.js +27 -0
  85. package/dist/catalog/sql.d.ts +46 -0
  86. package/dist/catalog/sql.js +13 -0
  87. package/dist/catalog/validation.d.ts +2 -0
  88. package/dist/catalog/validation.js +3 -0
  89. package/dist/communications/contracts/index.d.ts +1 -0
  90. package/dist/communications/contracts/marketingSync.d.ts +194 -0
  91. package/dist/communications/contracts/marketingSync.js +1 -0
  92. package/dist/communications/index.d.ts +1 -0
  93. package/dist/communications/klaviyo/consentPush.d.ts +51 -0
  94. package/dist/communications/klaviyo/consentPush.js +19 -0
  95. package/dist/communications/klaviyo/index.d.ts +110 -0
  96. package/dist/communications/klaviyo/index.js +860 -0
  97. package/dist/communications/newsletterIntegrationContracts.d.ts +3 -3
  98. package/dist/communications/resend/index.d.ts +40 -0
  99. package/dist/communications/resend/index.js +310 -0
  100. package/dist/composition/catalogContribution.d.ts +18 -0
  101. package/dist/composition/catalogContribution.js +21 -0
  102. package/dist/composition/index.d.ts +1 -0
  103. package/dist/composition/index.js +1 -0
  104. package/dist/identity/customerContracts.d.ts +2 -2
  105. package/dist/inventory/adminInventory.d.ts +13 -0
  106. package/dist/inventory/adminInventory.js +214 -0
  107. package/dist/inventory/contracts/forecast.d.ts +86 -0
  108. package/dist/inventory/contracts/forecast.js +1 -0
  109. package/dist/inventory/contracts/index.d.ts +4 -0
  110. package/dist/inventory/contracts/index.js +1 -0
  111. package/dist/inventory/contracts/inventory.d.ts +157 -0
  112. package/dist/inventory/contracts/inventory.js +1 -0
  113. package/dist/inventory/contracts/newPurchaseStock.d.ts +20 -0
  114. package/dist/inventory/contracts/newPurchaseStock.js +1 -0
  115. package/dist/inventory/contracts/reservation.d.ts +18 -0
  116. package/dist/inventory/contracts/reservation.js +1 -0
  117. package/dist/inventory/forecast.d.ts +24 -0
  118. package/dist/inventory/forecast.js +200 -0
  119. package/dist/inventory/index.d.ts +13 -0
  120. package/dist/inventory/index.js +10 -0
  121. package/dist/inventory/inventoryHandlers.d.ts +53 -0
  122. package/dist/inventory/inventoryHandlers.js +151 -0
  123. package/dist/inventory/newPurchaseStockAvailability.d.ts +47 -0
  124. package/dist/inventory/newPurchaseStockAvailability.js +75 -0
  125. package/dist/inventory/ports.d.ts +21 -0
  126. package/dist/inventory/ports.js +16 -0
  127. package/dist/inventory/renewalReservation.d.ts +27 -0
  128. package/dist/inventory/renewalReservation.js +61 -0
  129. package/dist/inventory/reservationPolicy.d.ts +6 -0
  130. package/dist/inventory/reservationPolicy.js +19 -0
  131. package/dist/inventory/schemas.d.ts +137 -0
  132. package/dist/inventory/schemas.js +112 -0
  133. package/dist/inventory/sql.d.ts +14 -0
  134. package/dist/inventory/sql.js +5 -0
  135. package/dist/inventory/subscriptionForecastCalculation.d.ts +4 -0
  136. package/dist/inventory/subscriptionForecastCalculation.js +133 -0
  137. package/dist/pricing/acquisitionFinancialPolicy.d.ts +26 -0
  138. package/dist/pricing/acquisitionFinancialPolicy.js +1 -0
  139. package/dist/pricing/acquisitionOfferPricing.d.ts +27 -0
  140. package/dist/pricing/acquisitionOfferPricing.js +25 -0
  141. package/dist/pricing/acquisitionOfferPricingHandler.d.ts +20 -0
  142. package/dist/pricing/acquisitionOfferPricingHandler.js +105 -0
  143. package/dist/pricing/acquisitionOfferPricingSchemas.d.ts +31 -0
  144. package/dist/pricing/acquisitionOfferPricingSchemas.js +33 -0
  145. package/dist/pricing/acquisitionQuoteBinding.d.ts +12 -0
  146. package/dist/pricing/acquisitionQuoteBinding.js +12 -0
  147. package/dist/pricing/acquisitionReadiness.d.ts +31 -0
  148. package/dist/pricing/acquisitionReadiness.js +117 -0
  149. package/dist/pricing/acquisitionTerms.d.ts +19 -0
  150. package/dist/pricing/acquisitionTerms.js +126 -0
  151. package/dist/pricing/acquisitionTermsSchemas.d.ts +59 -0
  152. package/dist/pricing/acquisitionTermsSchemas.js +42 -0
  153. package/dist/pricing/catalogFactsProvenance.d.ts +33 -0
  154. package/dist/pricing/catalogFactsProvenance.js +64 -0
  155. package/dist/pricing/catalogFactsSchemas.d.ts +45 -0
  156. package/dist/pricing/catalogFactsSchemas.js +58 -0
  157. package/dist/pricing/commerceOfferPricing.d.ts +25 -0
  158. package/dist/pricing/commerceOfferPricing.js +139 -0
  159. package/dist/pricing/commerceOfferPricingCache.d.ts +10 -0
  160. package/dist/pricing/commerceOfferPricingCache.js +44 -0
  161. package/dist/pricing/commerceOfferPricingHandler.d.ts +21 -0
  162. package/dist/pricing/commerceOfferPricingHandler.js +78 -0
  163. package/dist/pricing/commercePriceAuthority.d.ts +26 -0
  164. package/dist/pricing/commercePriceAuthority.js +79 -0
  165. package/dist/pricing/commercePricingPolicyErrors.d.ts +40 -0
  166. package/dist/pricing/commercePricingPolicyErrors.js +67 -0
  167. package/dist/pricing/commerceQuoteBatchHandler.d.ts +37 -0
  168. package/dist/pricing/commerceQuoteBatchHandler.js +83 -0
  169. package/dist/pricing/commerceQuoteCatalogReadPort.d.ts +27 -0
  170. package/dist/pricing/commerceQuoteCatalogReadPort.js +8 -0
  171. package/dist/pricing/commerceQuoteHandler.d.ts +31 -0
  172. package/dist/pricing/commerceQuoteHandler.js +110 -0
  173. package/dist/pricing/commerceQuoteSnapshotExpect.d.ts +9 -0
  174. package/dist/pricing/commerceQuoteSnapshotExpect.js +22 -0
  175. package/dist/pricing/contracts/acquisitionTerms.d.ts +32 -0
  176. package/dist/pricing/contracts/acquisitionTerms.js +2 -0
  177. package/dist/pricing/contracts/authority.d.ts +27 -0
  178. package/dist/pricing/contracts/authority.js +1 -0
  179. package/dist/pricing/contracts/evidence.d.ts +33 -0
  180. package/dist/pricing/contracts/evidence.js +1 -0
  181. package/dist/pricing/contracts/index.d.ts +17 -0
  182. package/dist/pricing/contracts/index.js +7 -0
  183. package/dist/pricing/contracts/money.d.ts +27 -0
  184. package/dist/pricing/contracts/money.js +1 -0
  185. package/dist/pricing/contracts/offer.d.ts +52 -0
  186. package/dist/pricing/contracts/offer.js +4 -0
  187. package/dist/pricing/contracts/offerPolicy.d.ts +16 -0
  188. package/dist/pricing/contracts/offerPolicy.js +5 -0
  189. package/dist/pricing/contracts/policy.d.ts +22 -0
  190. package/dist/pricing/contracts/policy.js +3 -0
  191. package/dist/pricing/contracts/provenance.d.ts +24 -0
  192. package/dist/pricing/contracts/provenance.js +2 -0
  193. package/dist/pricing/contracts/quote.d.ts +94 -0
  194. package/dist/pricing/contracts/quote.js +1 -0
  195. package/dist/pricing/dbBackedCommerceQuoteHelpers.d.ts +78 -0
  196. package/dist/pricing/dbBackedCommerceQuoteHelpers.js +146 -0
  197. package/dist/pricing/dbBackedCommerceQuotePort.d.ts +66 -0
  198. package/dist/pricing/dbBackedCommerceQuotePort.js +206 -0
  199. package/dist/pricing/dbBackedCommerceQuoteSnapshotVerifier.d.ts +4 -0
  200. package/dist/pricing/dbBackedCommerceQuoteSnapshotVerifier.js +25 -0
  201. package/dist/pricing/index.d.ts +51 -0
  202. package/dist/pricing/index.js +36 -0
  203. package/dist/pricing/offerPolicyReadiness.d.ts +21 -0
  204. package/dist/pricing/offerPolicyReadiness.js +79 -0
  205. package/dist/pricing/offerPolicySchemas.d.ts +25 -0
  206. package/dist/pricing/offerPolicySchemas.js +15 -0
  207. package/dist/pricing/offerPricingSchemas.d.ts +315 -0
  208. package/dist/pricing/offerPricingSchemas.js +65 -0
  209. package/dist/pricing/ports.d.ts +13 -0
  210. package/dist/pricing/ports.js +9 -0
  211. package/dist/pricing/pricingPolicyToken.d.ts +39 -0
  212. package/dist/pricing/pricingPolicyToken.js +84 -0
  213. package/dist/pricing/quoteAcquisitionTerms.d.ts +2 -0
  214. package/dist/pricing/quoteAcquisitionTerms.js +4 -0
  215. package/dist/pricing/quoteCodeRejectionDetails.d.ts +20 -0
  216. package/dist/pricing/quoteCodeRejectionDetails.js +22 -0
  217. package/dist/pricing/quotePorts.d.ts +30 -0
  218. package/dist/pricing/quotePorts.js +20 -0
  219. package/dist/pricing/quotePrimitives.d.ts +13 -0
  220. package/dist/pricing/quotePrimitives.js +18 -0
  221. package/dist/pricing/quotePromotionEvidence.d.ts +39 -0
  222. package/dist/pricing/quotePromotionEvidence.js +73 -0
  223. package/dist/pricing/quoteSchemas.d.ts +1176 -0
  224. package/dist/pricing/quoteSchemas.js +196 -0
  225. package/dist/pricing/subscriptionPricePolicy.d.ts +52 -0
  226. package/dist/pricing/subscriptionPricePolicy.js +96 -0
  227. package/dist/pricing/taxProfileGuard.d.ts +2 -0
  228. package/dist/pricing/taxProfileGuard.js +24 -0
  229. package/dist/pricing/validation.d.ts +2 -0
  230. package/dist/pricing/validation.js +3 -0
  231. package/dist/promotions/adminBindings.d.ts +72 -0
  232. package/dist/promotions/adminBindings.js +1 -0
  233. package/dist/promotions/adminPromotionCodesContracts.d.ts +498 -0
  234. package/dist/promotions/adminPromotionCodesContracts.js +211 -0
  235. package/dist/promotions/adminPromotionCodesDataPort.d.ts +47 -0
  236. package/dist/promotions/adminPromotionCodesDataPort.js +1 -0
  237. package/dist/promotions/adminPromotionCodesHandler.d.ts +14 -0
  238. package/dist/promotions/adminPromotionCodesHandler.js +194 -0
  239. package/dist/promotions/adminPromotionsContracts.d.ts +235 -0
  240. package/dist/promotions/adminPromotionsContracts.js +99 -0
  241. package/dist/promotions/adminPromotionsDataPort.d.ts +42 -0
  242. package/dist/promotions/adminPromotionsDataPort.js +1 -0
  243. package/dist/promotions/adminPromotionsHandler.d.ts +16 -0
  244. package/dist/promotions/adminPromotionsHandler.js +47 -0
  245. package/dist/promotions/contracts/index.d.ts +387 -0
  246. package/dist/promotions/contracts/index.js +1 -0
  247. package/dist/promotions/index.d.ts +22 -0
  248. package/dist/promotions/index.js +21 -0
  249. package/dist/promotions/promoDataPort.d.ts +47 -0
  250. package/dist/promotions/promoDataPort.js +14 -0
  251. package/dist/promotions/promotionAcceptanceTelemetry.d.ts +29 -0
  252. package/dist/promotions/promotionAcceptanceTelemetry.js +45 -0
  253. package/dist/promotions/promotionBenefitDefinition.d.ts +37 -0
  254. package/dist/promotions/promotionBenefitDefinition.js +33 -0
  255. package/dist/promotions/promotionClaimSweepPort.d.ts +14 -0
  256. package/dist/promotions/promotionClaimSweepPort.js +8 -0
  257. package/dist/promotions/promotionClaims.d.ts +5 -0
  258. package/dist/promotions/promotionClaims.js +57 -0
  259. package/dist/promotions/promotionCodePreview.d.ts +11 -0
  260. package/dist/promotions/promotionCodePreview.js +154 -0
  261. package/dist/promotions/promotionCodeQuotePort.d.ts +25 -0
  262. package/dist/promotions/promotionCodeQuotePort.js +1 -0
  263. package/dist/promotions/promotionQuoteAcceptance.d.ts +65 -0
  264. package/dist/promotions/promotionQuoteAcceptance.js +202 -0
  265. package/dist/promotions/promotionQuoteBinding.d.ts +71 -0
  266. package/dist/promotions/promotionQuoteBinding.js +85 -0
  267. package/dist/promotions/quoteAutomaticPromotions.d.ts +24 -0
  268. package/dist/promotions/quoteAutomaticPromotions.js +36 -0
  269. package/dist/promotions/quotePromoDiscounts.d.ts +32 -0
  270. package/dist/promotions/quotePromoDiscounts.js +140 -0
  271. package/dist/promotions/quotePromotionCodeAdjustments.d.ts +27 -0
  272. package/dist/promotions/quotePromotionCodeAdjustments.js +223 -0
  273. package/dist/promotions/quotePromotionV2.d.ts +29 -0
  274. package/dist/promotions/quotePromotionV2.js +174 -0
  275. package/dist/promotions/sql.d.ts +14 -0
  276. package/dist/promotions/sql.js +5 -0
  277. package/dist/promotions/validation.d.ts +2 -0
  278. package/dist/promotions/validation.js +3 -0
  279. package/dist/shipping/addressCanonLookupHandler.d.ts +7 -0
  280. package/dist/shipping/addressCanonLookupHandler.js +105 -0
  281. package/dist/shipping/addressCanonical.d.ts +2 -0
  282. package/dist/shipping/addressCanonical.js +26 -0
  283. package/dist/shipping/addressPorts.d.ts +39 -0
  284. package/dist/shipping/addressPorts.js +1 -0
  285. package/dist/shipping/addressSchemas.d.ts +30 -0
  286. package/dist/shipping/addressSchemas.js +1 -0
  287. package/dist/shipping/adminShippingRateHandler.d.ts +4 -0
  288. package/dist/shipping/adminShippingRateHandler.js +64 -0
  289. package/dist/shipping/contracts/address.d.ts +144 -0
  290. package/dist/shipping/contracts/address.js +1 -0
  291. package/dist/shipping/contracts/delivery.d.ts +110 -0
  292. package/dist/shipping/contracts/delivery.js +1 -0
  293. package/dist/shipping/contracts/index.d.ts +3 -0
  294. package/dist/shipping/contracts/index.js +1 -0
  295. package/dist/shipping/contracts/shippingRate.d.ts +11 -0
  296. package/dist/shipping/contracts/shippingRate.js +1 -0
  297. package/dist/shipping/customerAddressesHandler.d.ts +5 -0
  298. package/dist/shipping/customerAddressesHandler.js +80 -0
  299. package/dist/shipping/customerSelfServiceAddressModels.d.ts +27 -0
  300. package/dist/shipping/customerSelfServiceAddressModels.js +101 -0
  301. package/dist/shipping/deliverySelectionHandler.d.ts +10 -0
  302. package/dist/shipping/deliverySelectionHandler.js +77 -0
  303. package/dist/shipping/deliverySelectionPort.d.ts +8 -0
  304. package/dist/shipping/deliverySelectionPort.js +1 -0
  305. package/dist/shipping/deliverySelectionSummary.d.ts +2 -0
  306. package/dist/shipping/deliverySelectionSummary.js +53 -0
  307. package/dist/shipping/handlerSchemas.d.ts +21 -0
  308. package/dist/shipping/handlerSchemas.js +1 -0
  309. package/dist/shipping/index.d.ts +17 -0
  310. package/dist/shipping/index.js +8 -0
  311. package/dist/shipping/pickupPointSearchPort.d.ts +4 -0
  312. package/dist/shipping/pickupPointSearchPort.js +1 -0
  313. package/dist/shipping/readDeliverySelectionEvidence.d.ts +2 -0
  314. package/dist/shipping/readDeliverySelectionEvidence.js +44 -0
  315. package/dist/shipping/shippingRatePorts.d.ts +52 -0
  316. package/dist/shipping/shippingRatePorts.js +1 -0
  317. package/package.json +62 -2
  318. package/release-gates.json +218 -10
  319. package/sql/20260807140000_read_parity_catalog.sql +94 -0
  320. package/sql/20260810120000_storefront_catalog_attributes.sql +51 -0
  321. package/sql/20260812140000_sellable_bundle_catalog.sql +124 -0
  322. package/sql/20260812210000_bundle_operator_write_boundary.sql +567 -0
  323. package/sql/20260814000000_fulfillment_stock_evidence.sql +239 -0
  324. package/sql/20260815120000_automatic_subscription_renewal.sql +1083 -0
  325. package/sql/20260817180000_promotion_claim_lifecycle.sql +591 -0
  326. package/sql/20260817180100_promotion_claim_lifecycle_validation.sql +23 -0
  327. package/sql/20260827220000_catalog_document_revision_foundation.sql +226 -0
  328. package/sql/20260827220001_catalog_document_revision_foundation_validate.sql +10 -0
  329. package/sql/20260908100000_catalog_draft_foundation.sql +217 -0
  330. package/src/catalog/activeSkuSelection.ts +20 -0
  331. package/src/catalog/adminBindings.ts +59 -0
  332. package/src/catalog/adminBundleHandler.ts +165 -0
  333. package/src/catalog/adminBundleReadHandler.ts +261 -0
  334. package/src/catalog/adminBundleWritePort.ts +102 -0
  335. package/src/catalog/bundleAvailability.ts +129 -0
  336. package/src/catalog/bundleAvailabilityService.ts +171 -0
  337. package/src/catalog/bundleBindings.ts +29 -0
  338. package/src/catalog/bundleCatalogQueries.ts +98 -0
  339. package/src/catalog/bundleCatalogReadPort.ts +177 -0
  340. package/src/catalog/bundleCatalogStore.ts +269 -0
  341. package/src/catalog/bundleRuleCodes.ts +134 -0
  342. package/src/catalog/bundleRules.ts +153 -0
  343. package/src/catalog/catalogDraftStore.ts +71 -0
  344. package/src/catalog/catalogSkuEnvelope.ts +214 -0
  345. package/src/catalog/catalogSkuEnvelopeMapper.ts +160 -0
  346. package/src/catalog/contracts/bundleAdmin.ts +20 -0
  347. package/src/catalog/contracts/bundleAvailability.ts +5 -0
  348. package/src/catalog/contracts/bundleRead.ts +13 -0
  349. package/src/catalog/contracts/draft.ts +69 -0
  350. package/src/catalog/contracts/foundation.ts +104 -0
  351. package/src/catalog/contracts/index.ts +14 -0
  352. package/src/catalog/contracts/lifecycle.ts +74 -0
  353. package/src/catalog/contracts/productMediaContracts.ts +170 -0
  354. package/src/catalog/contracts/productTypes.ts +35 -0
  355. package/src/catalog/contracts/resolveProductMedia.ts +85 -0
  356. package/src/catalog/contracts/sellable.ts +12 -0
  357. package/src/catalog/draftHandler.ts +105 -0
  358. package/src/catalog/draftPorts.ts +18 -0
  359. package/src/catalog/draftSchemas.ts +88 -0
  360. package/src/catalog/draftValidation.ts +100 -0
  361. package/src/catalog/foundationSchemas.ts +123 -0
  362. package/src/catalog/index.ts +43 -0
  363. package/src/catalog/mediaSourcePack.ts +219 -0
  364. package/src/catalog/productTypeSchemas.ts +70 -0
  365. package/src/catalog/publicationPorts.ts +44 -0
  366. package/src/catalog/readPorts.ts +61 -0
  367. package/src/catalog/referenceCatalogHandler.ts +39 -0
  368. package/src/catalog/resolvedSkuProjection.ts +76 -0
  369. package/src/catalog/sellableBundleHandler.ts +133 -0
  370. package/src/catalog/sellableSchemas.ts +33 -0
  371. package/src/catalog/sql.ts +14 -0
  372. package/src/catalog/validation.ts +3 -0
  373. package/src/communications/contracts/index.ts +1 -0
  374. package/src/communications/contracts/marketingSync.ts +109 -0
  375. package/src/communications/index.ts +1 -0
  376. package/src/communications/klaviyo/consentPush.ts +19 -0
  377. package/src/communications/klaviyo/index.ts +649 -0
  378. package/src/communications/resend/index.ts +350 -0
  379. package/src/composition/catalogContribution.ts +32 -0
  380. package/src/composition/index.ts +1 -0
  381. package/src/inventory/adminInventory.ts +251 -0
  382. package/src/inventory/contracts/forecast.ts +96 -0
  383. package/src/inventory/contracts/index.ts +18 -0
  384. package/src/inventory/contracts/inventory.ts +14 -0
  385. package/src/inventory/contracts/newPurchaseStock.ts +23 -0
  386. package/src/inventory/contracts/reservation.ts +20 -0
  387. package/src/inventory/forecast.ts +239 -0
  388. package/src/inventory/index.ts +21 -0
  389. package/src/inventory/inventoryHandlers.ts +215 -0
  390. package/src/inventory/newPurchaseStockAvailability.ts +120 -0
  391. package/src/inventory/ports.ts +46 -0
  392. package/src/inventory/renewalReservation.ts +88 -0
  393. package/src/inventory/reservationPolicy.ts +27 -0
  394. package/src/inventory/schemas.ts +128 -0
  395. package/src/inventory/sql.ts +5 -0
  396. package/src/inventory/subscriptionForecastCalculation.ts +157 -0
  397. package/src/pricing/acquisitionFinancialPolicy.ts +26 -0
  398. package/src/pricing/acquisitionOfferPricing.ts +38 -0
  399. package/src/pricing/acquisitionOfferPricingHandler.ts +157 -0
  400. package/src/pricing/acquisitionOfferPricingSchemas.ts +35 -0
  401. package/src/pricing/acquisitionQuoteBinding.ts +12 -0
  402. package/src/pricing/acquisitionReadiness.ts +148 -0
  403. package/src/pricing/acquisitionTerms.ts +125 -0
  404. package/src/pricing/acquisitionTermsSchemas.ts +52 -0
  405. package/src/pricing/catalogFactsProvenance.ts +102 -0
  406. package/src/pricing/catalogFactsSchemas.ts +69 -0
  407. package/src/pricing/commerceOfferPricing.ts +224 -0
  408. package/src/pricing/commerceOfferPricingCache.ts +53 -0
  409. package/src/pricing/commerceOfferPricingHandler.ts +137 -0
  410. package/src/pricing/commercePriceAuthority.ts +104 -0
  411. package/src/pricing/commercePricingPolicyErrors.ts +88 -0
  412. package/src/pricing/commerceQuoteBatchHandler.ts +129 -0
  413. package/src/pricing/commerceQuoteCatalogReadPort.ts +42 -0
  414. package/src/pricing/commerceQuoteHandler.ts +184 -0
  415. package/src/pricing/commerceQuoteSnapshotExpect.ts +48 -0
  416. package/src/pricing/contracts/acquisitionTerms.ts +26 -0
  417. package/src/pricing/contracts/authority.ts +44 -0
  418. package/src/pricing/contracts/evidence.ts +25 -0
  419. package/src/pricing/contracts/index.ts +17 -0
  420. package/src/pricing/contracts/money.ts +32 -0
  421. package/src/pricing/contracts/offer.ts +42 -0
  422. package/src/pricing/contracts/offerPolicy.ts +17 -0
  423. package/src/pricing/contracts/policy.ts +26 -0
  424. package/src/pricing/contracts/provenance.ts +19 -0
  425. package/src/pricing/contracts/quote.ts +106 -0
  426. package/src/pricing/dbBackedCommerceQuoteHelpers.ts +256 -0
  427. package/src/pricing/dbBackedCommerceQuotePort.ts +260 -0
  428. package/src/pricing/dbBackedCommerceQuoteSnapshotVerifier.ts +49 -0
  429. package/src/pricing/index.ts +52 -0
  430. package/src/pricing/offerPolicyReadiness.ts +110 -0
  431. package/src/pricing/offerPolicySchemas.ts +23 -0
  432. package/src/pricing/offerPricingSchemas.ts +92 -0
  433. package/src/pricing/ports.ts +17 -0
  434. package/src/pricing/pricingPolicyToken.ts +119 -0
  435. package/src/pricing/quoteAcquisitionTerms.ts +10 -0
  436. package/src/pricing/quoteCodeRejectionDetails.ts +23 -0
  437. package/src/pricing/quotePorts.ts +58 -0
  438. package/src/pricing/quotePrimitives.ts +21 -0
  439. package/src/pricing/quotePromotionEvidence.ts +82 -0
  440. package/src/pricing/quoteSchemas.ts +230 -0
  441. package/src/pricing/subscriptionPricePolicy.ts +113 -0
  442. package/src/pricing/taxProfileGuard.ts +33 -0
  443. package/src/pricing/validation.ts +3 -0
  444. package/src/promotions/adminBindings.ts +53 -0
  445. package/src/promotions/adminPromotionCodesContracts.ts +244 -0
  446. package/src/promotions/adminPromotionCodesDataPort.ts +56 -0
  447. package/src/promotions/adminPromotionCodesHandler.ts +254 -0
  448. package/src/promotions/adminPromotionsContracts.ts +121 -0
  449. package/src/promotions/adminPromotionsDataPort.ts +48 -0
  450. package/src/promotions/adminPromotionsHandler.ts +72 -0
  451. package/src/promotions/contracts/index.ts +387 -0
  452. package/src/promotions/index.ts +22 -0
  453. package/src/promotions/promoDataPort.ts +65 -0
  454. package/src/promotions/promotionAcceptanceTelemetry.ts +73 -0
  455. package/src/promotions/promotionBenefitDefinition.ts +48 -0
  456. package/src/promotions/promotionClaimSweepPort.ts +23 -0
  457. package/src/promotions/promotionClaims.ts +70 -0
  458. package/src/promotions/promotionCodePreview.ts +183 -0
  459. package/src/promotions/promotionCodeQuotePort.ts +35 -0
  460. package/src/promotions/promotionQuoteAcceptance.ts +284 -0
  461. package/src/promotions/promotionQuoteBinding.ts +158 -0
  462. package/src/promotions/quoteAutomaticPromotions.ts +58 -0
  463. package/src/promotions/quotePromoDiscounts.ts +185 -0
  464. package/src/promotions/quotePromotionCodeAdjustments.ts +277 -0
  465. package/src/promotions/quotePromotionV2.ts +223 -0
  466. package/src/promotions/sql.ts +5 -0
  467. package/src/promotions/validation.ts +3 -0
  468. package/src/shipping/addressCanonLookupHandler.ts +114 -0
  469. package/src/shipping/addressCanonical.ts +31 -0
  470. package/src/shipping/addressPorts.ts +48 -0
  471. package/src/shipping/addressSchemas.ts +28 -0
  472. package/src/shipping/adminShippingRateHandler.ts +72 -0
  473. package/src/shipping/contracts/address.ts +71 -0
  474. package/src/shipping/contracts/delivery.ts +114 -0
  475. package/src/shipping/contracts/index.ts +18 -0
  476. package/src/shipping/contracts/shippingRate.ts +7 -0
  477. package/src/shipping/customerAddressesHandler.ts +100 -0
  478. package/src/shipping/customerSelfServiceAddressModels.ts +124 -0
  479. package/src/shipping/deliverySelectionHandler.ts +94 -0
  480. package/src/shipping/deliverySelectionPort.ts +10 -0
  481. package/src/shipping/deliverySelectionSummary.ts +56 -0
  482. package/src/shipping/handlerSchemas.ts +19 -0
  483. package/src/shipping/index.ts +23 -0
  484. package/src/shipping/pickupPointSearchPort.ts +8 -0
  485. package/src/shipping/readDeliverySelectionEvidence.ts +51 -0
  486. package/src/shipping/shippingRatePorts.ts +36 -0
@@ -0,0 +1,591 @@
1
+ -- Public promotion definition and claim lifecycle.
2
+ --
3
+ -- CHANGE. This forward adds a neutral, content-addressed promotion definition
4
+ -- catalogue, a durable reserved/redeemed/released claim ledger, append-only
5
+ -- claim events, read routines for the existing pure quote evaluator, an
6
+ -- idempotent promoted-order wrapper with deterministic effective-line
7
+ -- allocation, order transition hooks and one bounded stale-draft sweep.
8
+ --
9
+ -- WHY. The public bundle already owns catalogue pricing, idempotent order drafts,
10
+ -- settlement truth and the pure promotion evaluator. It could not persist the
11
+ -- evaluator's neutral inputs or reserve the selected benefit, so its mounted
12
+ -- quote silently omitted promotions and its scheduled sweep was managed-only.
13
+ --
14
+ -- SAFETY. This is additive and copies no private promotion/code schema. A
15
+ -- definition is an opaque reviewed JSON contract, not editable presentation or
16
+ -- provider data. Product discounts are allocated only to the fresh item rows
17
+ -- created inside the same uncommitted draft transaction; legacy, renewal,
18
+ -- payment-truth and accounting functions are untouched. Positive net shipping,
19
+ -- line-targeted and zero-payable drafts fail before any write. Reservation
20
+ -- happens in that same transaction.
21
+ -- Every lifecycle mutation locks order before claim, matching settlement's lock
22
+ -- order. Sweep refuses any settlement intent or active renewal inventory before
23
+ -- terminally marking a stale draft. It preserves the order, receipt, claim and
24
+ -- outbox rows as audit evidence and fences later replay; no durable row is deleted.
25
+ -- Routines are invoker-rights, role-free and revoked from PUBLIC.
26
+ --
27
+ -- ROLLBACK. Disable the direct promotion adopter and scheduler, then drop the
28
+ -- capability triggers, routines and four capability-local tables. The receipt
29
+ -- audit columns and nullable item allocation evidence can remain. Existing orders, quote/catalog rows,
30
+ -- settlement intents and outbox facts remain valid.
31
+
32
+ CREATE TABLE public.commerce_promotion_definitions (
33
+ promotion_id text PRIMARY KEY,
34
+ revision integer NOT NULL DEFAULT 1,
35
+ definition jsonb NOT NULL,
36
+ definition_fingerprint text NOT NULL,
37
+ active boolean NOT NULL DEFAULT false,
38
+ created_at timestamptz NOT NULL DEFAULT now(),
39
+ updated_at timestamptz NOT NULL DEFAULT now(),
40
+ CONSTRAINT commerce_promotion_definitions_id_check
41
+ CHECK (promotion_id ~ '^[A-Za-z0-9][A-Za-z0-9._:-]{0,119}$'),
42
+ CONSTRAINT commerce_promotion_definitions_revision_check CHECK (revision > 0),
43
+ CONSTRAINT commerce_promotion_definitions_payload_check CHECK (
44
+ jsonb_typeof(definition) = 'object'
45
+ AND definition->>'id' = promotion_id
46
+ AND definition->>'status' IN ('draft', 'active', 'paused', 'archived')
47
+ AND definition->>'trigger_type' IN ('coupon_code', 'automatic', 'referral')
48
+ AND definition->>'discount_type' IN ('percentage', 'fixed_amount', 'free_shipping')
49
+ AND definition->>'applies_to_kind' IN ('order_total', 'line_with_variant', 'line_with_category')
50
+ AND definition->>'stacking_rule' IN ('exclusive', 'stackable_with_any', 'stackable_with_loyalty')
51
+ AND jsonb_typeof(definition->'eligibility') = 'object'
52
+ AND jsonb_typeof(definition->'applies_to_payload') = 'object'
53
+ AND jsonb_typeof(definition->'region_availability') = 'array'
54
+ )
55
+ );
56
+
57
+ COMMENT ON TABLE public.commerce_promotion_definitions IS
58
+ 'Provider-neutral inputs to the shared pure evaluator. Presentation, provider attempts and private promotion-code bindings are deliberately absent.';
59
+
60
+ CREATE FUNCTION public.commerce_promotion_definition_fingerprint()
61
+ RETURNS trigger LANGUAGE plpgsql SET search_path = pg_catalog AS $$
62
+ BEGIN
63
+ NEW.definition_fingerprint := encode(
64
+ sha256(convert_to(NEW.definition::text, 'UTF8')), 'hex'
65
+ );
66
+ RETURN NEW;
67
+ END;
68
+ $$;
69
+
70
+ CREATE TRIGGER commerce_promotion_definition_fingerprint_trigger
71
+ BEFORE INSERT OR UPDATE OF definition ON public.commerce_promotion_definitions
72
+ FOR EACH ROW EXECUTE FUNCTION public.commerce_promotion_definition_fingerprint();
73
+
74
+ CREATE TABLE public.commerce_order_adjustments (
75
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
76
+ order_id uuid NOT NULL REFERENCES public.commerce_orders(id) ON DELETE RESTRICT,
77
+ kind text NOT NULL,
78
+ scope text NOT NULL,
79
+ amount_minor bigint NOT NULL,
80
+ promotion_id text REFERENCES public.commerce_promotion_definitions(promotion_id) ON DELETE RESTRICT,
81
+ definition_fingerprint text,
82
+ created_at timestamptz NOT NULL DEFAULT now(),
83
+ CONSTRAINT commerce_order_adjustments_kind_check
84
+ CHECK (kind IN ('shipping_charge', 'promotion_discount')),
85
+ CONSTRAINT commerce_order_adjustments_scope_check
86
+ CHECK (scope IN ('order_total', 'line', 'shipping')),
87
+ CONSTRAINT commerce_order_adjustments_amount_check CHECK (amount_minor > 0),
88
+ CONSTRAINT commerce_order_adjustments_semantics_check CHECK (
89
+ (kind = 'shipping_charge' AND scope = 'shipping'
90
+ AND promotion_id IS NULL AND definition_fingerprint IS NULL)
91
+ OR
92
+ (kind = 'promotion_discount' AND promotion_id IS NOT NULL
93
+ AND definition_fingerprint ~ '^[0-9a-f]{64}$')
94
+ ),
95
+ CONSTRAINT commerce_order_adjustments_promotion_key UNIQUE (order_id, promotion_id)
96
+ );
97
+
98
+ CREATE UNIQUE INDEX commerce_order_adjustments_shipping_charge_key
99
+ ON public.commerce_order_adjustments (order_id)
100
+ WHERE kind = 'shipping_charge';
101
+
102
+ COMMENT ON TABLE public.commerce_order_adjustments IS
103
+ 'Immutable neutral money facts. Catalogue lines stay gross; charges add and promotion discounts subtract from the charged order total.';
104
+
105
+ ALTER TABLE public.commerce_order_items
106
+ ADD COLUMN source_line_ordinal integer,
107
+ ADD COLUMN catalog_unit_amount_minor bigint,
108
+ ADD COLUMN catalog_line_amount_minor bigint,
109
+ ADD COLUMN promotion_discount_allocated_minor bigint,
110
+ ADD COLUMN promotion_allocation_fingerprint text,
111
+ ADD CONSTRAINT commerce_order_items_promoted_allocation_check CHECK (
112
+ (source_line_ordinal IS NULL
113
+ AND catalog_unit_amount_minor IS NULL
114
+ AND catalog_line_amount_minor IS NULL
115
+ AND promotion_discount_allocated_minor IS NULL
116
+ AND promotion_allocation_fingerprint IS NULL)
117
+ OR
118
+ (source_line_ordinal > 0
119
+ AND catalog_unit_amount_minor >= 0
120
+ AND catalog_line_amount_minor = catalog_unit_amount_minor * quantity
121
+ AND promotion_discount_allocated_minor >= 0
122
+ AND promotion_discount_allocated_minor <= catalog_line_amount_minor
123
+ AND line_amount_minor + promotion_discount_allocated_minor = catalog_line_amount_minor
124
+ AND promotion_allocation_fingerprint ~ '^[0-9a-f]{64}$')
125
+ ) NOT VALID;
126
+
127
+ COMMENT ON COLUMN public.commerce_order_items.catalog_line_amount_minor IS
128
+ 'Catalogue subtotal retained only for promoted effective lines. Legacy and renewal rows remain structurally unchanged with all allocation columns NULL.';
129
+
130
+ CREATE TABLE public.commerce_promotion_claims (
131
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
132
+ promotion_id text NOT NULL REFERENCES public.commerce_promotion_definitions(promotion_id) ON DELETE RESTRICT,
133
+ definition_fingerprint text NOT NULL,
134
+ adjustment_id uuid NOT NULL UNIQUE REFERENCES public.commerce_order_adjustments(id) ON DELETE RESTRICT,
135
+ order_id uuid NOT NULL REFERENCES public.commerce_orders(id) ON DELETE RESTRICT,
136
+ client_id uuid REFERENCES public.clients(id) ON DELETE SET NULL,
137
+ status text NOT NULL DEFAULT 'reserved',
138
+ amount_off_minor bigint NOT NULL,
139
+ reserved_at timestamptz NOT NULL DEFAULT now(),
140
+ expires_at timestamptz NOT NULL,
141
+ redeemed_at timestamptz,
142
+ released_at timestamptz,
143
+ release_reason text,
144
+ updated_at timestamptz NOT NULL DEFAULT now(),
145
+ CONSTRAINT commerce_promotion_claims_definition_order_key UNIQUE (promotion_id, order_id),
146
+ CONSTRAINT commerce_promotion_claims_fingerprint_check
147
+ CHECK (definition_fingerprint ~ '^[0-9a-f]{64}$'),
148
+ CONSTRAINT commerce_promotion_claims_status_check
149
+ CHECK (status IN ('reserved', 'redeemed', 'released')),
150
+ CONSTRAINT commerce_promotion_claims_amount_check CHECK (amount_off_minor > 0),
151
+ CONSTRAINT commerce_promotion_claims_expiry_check CHECK (expires_at > reserved_at),
152
+ CONSTRAINT commerce_promotion_claims_terminal_check CHECK (
153
+ (status = 'reserved' AND redeemed_at IS NULL AND released_at IS NULL AND release_reason IS NULL)
154
+ OR (status = 'redeemed' AND redeemed_at IS NOT NULL AND released_at IS NULL AND release_reason IS NULL)
155
+ OR (status = 'released' AND redeemed_at IS NULL AND released_at IS NOT NULL AND btrim(release_reason) <> '')
156
+ )
157
+ );
158
+
159
+ CREATE INDEX commerce_promotion_claims_sweep
160
+ ON public.commerce_promotion_claims (expires_at, id)
161
+ WHERE status = 'reserved';
162
+
163
+ CREATE TABLE public.commerce_promotion_claim_events (
164
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
165
+ claim_id uuid NOT NULL REFERENCES public.commerce_promotion_claims(id) ON DELETE RESTRICT,
166
+ event_key text NOT NULL,
167
+ transition text NOT NULL,
168
+ reason text,
169
+ occurred_at timestamptz NOT NULL DEFAULT now(),
170
+ CONSTRAINT commerce_promotion_claim_events_key UNIQUE (claim_id, event_key),
171
+ CONSTRAINT commerce_promotion_claim_events_transition_check
172
+ CHECK (transition IN ('reserved', 'redeemed', 'released')),
173
+ CONSTRAINT commerce_promotion_claim_events_key_check CHECK (btrim(event_key) <> '')
174
+ );
175
+
176
+ ALTER TABLE public.commerce_order_draft_receipts
177
+ ADD COLUMN invalidated_at timestamptz,
178
+ ADD COLUMN invalidation_reason text;
179
+ ALTER TABLE public.commerce_order_draft_receipts
180
+ ADD CONSTRAINT commerce_order_draft_receipts_invalidation_check CHECK (
181
+ (invalidated_at IS NULL AND invalidation_reason IS NULL)
182
+ OR (invalidated_at IS NOT NULL AND btrim(invalidation_reason) <> '')
183
+ ) NOT VALID;
184
+
185
+ CREATE FUNCTION public.commerce_order_adjustments_append_only()
186
+ RETURNS trigger LANGUAGE plpgsql SET search_path = pg_catalog AS $$
187
+ BEGIN
188
+ RAISE EXCEPTION 'commerce_order_adjustments_append_only' USING ERRCODE = '55000';
189
+ END;
190
+ $$;
191
+
192
+ CREATE TRIGGER commerce_order_adjustments_append_only_trigger
193
+ BEFORE UPDATE OR DELETE ON public.commerce_order_adjustments
194
+ FOR EACH ROW EXECUTE FUNCTION public.commerce_order_adjustments_append_only();
195
+
196
+ CREATE FUNCTION public.commerce_promotion_claim_money_freeze()
197
+ RETURNS trigger
198
+ LANGUAGE plpgsql
199
+ SET search_path = public, pg_catalog
200
+ AS $$
201
+ BEGIN
202
+ IF EXISTS (
203
+ SELECT 1 FROM public.commerce_promotion_claims AS claim
204
+ WHERE claim.order_id = OLD.order_id
205
+ ) THEN
206
+ RAISE EXCEPTION 'commerce_promotion_claim_money_frozen' USING ERRCODE = '55000';
207
+ END IF;
208
+ IF TG_OP = 'DELETE' THEN RETURN OLD; END IF;
209
+ RETURN NEW;
210
+ END;
211
+ $$;
212
+
213
+ CREATE TRIGGER commerce_promotion_claim_money_freeze_trigger
214
+ BEFORE UPDATE OR DELETE ON public.commerce_order_items
215
+ FOR EACH ROW EXECUTE FUNCTION public.commerce_promotion_claim_money_freeze();
216
+
217
+ CREATE FUNCTION public.commerce_promotion_active_definitions()
218
+ RETURNS jsonb LANGUAGE sql STABLE SET search_path = pg_catalog AS $$
219
+ SELECT COALESCE(jsonb_agg(definition_row.definition ORDER BY definition_row.promotion_id), '[]'::jsonb)
220
+ FROM public.commerce_promotion_definitions AS definition_row
221
+ WHERE definition_row.active AND definition_row.definition->>'status' = 'active';
222
+ $$;
223
+
224
+ CREATE FUNCTION public.commerce_promotion_paid_order_counts(p_client_id uuid)
225
+ RETURNS jsonb LANGUAGE sql STABLE SET search_path = pg_catalog AS $$
226
+ SELECT jsonb_build_object(
227
+ 'oneTime', count(*) FILTER (WHERE order_row.subscription_cycle_id IS NULL),
228
+ 'subscription', count(*) FILTER (WHERE order_row.subscription_cycle_id IS NOT NULL)
229
+ )
230
+ FROM public.commerce_orders AS order_row
231
+ WHERE order_row.client_id = p_client_id
232
+ AND order_row.status IN ('paid', 'fulfillment_pending', 'fulfilled');
233
+ $$;
234
+
235
+ CREATE FUNCTION public.commerce_promotion_redemption_counts(p_client_id uuid DEFAULT NULL)
236
+ RETURNS TABLE (promotion_id text, global_count bigint, per_customer_count bigint)
237
+ LANGUAGE sql STABLE SET search_path = pg_catalog AS $$
238
+ SELECT claim.promotion_id,
239
+ count(*) FILTER (WHERE claim.status = 'redeemed') AS global_count,
240
+ count(*) FILTER (WHERE claim.status = 'redeemed' AND p_client_id IS NOT NULL
241
+ AND claim.client_id = p_client_id) AS per_customer_count
242
+ FROM public.commerce_promotion_claims AS claim GROUP BY claim.promotion_id;
243
+ $$;
244
+
245
+ CREATE FUNCTION public.commerce_promotion_device_first_order_redeemed(p_visitor_id text)
246
+ RETURNS boolean LANGUAGE sql STABLE SET search_path = pg_catalog AS $$
247
+ -- The public order-draft response stores no visitor identity, so the direct
248
+ -- adapter refuses to manufacture device evidence. Account counts remain real.
249
+ SELECT false;
250
+ $$;
251
+
252
+ CREATE FUNCTION public.commerce_create_promoted_order_draft_with_outbox(
253
+ p_idempotency_key text,
254
+ p_quote_snapshot jsonb,
255
+ p_order_draft_snapshot jsonb,
256
+ p_client_id uuid DEFAULT NULL
257
+ )
258
+ RETURNS jsonb
259
+ LANGUAGE plpgsql
260
+ SET search_path = pg_catalog
261
+ AS $$
262
+ DECLARE
263
+ v_receipt public.commerce_order_draft_receipts%ROWTYPE;
264
+ v_response jsonb;
265
+ v_order_id uuid;
266
+ v_discount jsonb;
267
+ v_definition public.commerce_promotion_definitions%ROWTYPE;
268
+ v_adjustment public.commerce_order_adjustments%ROWTYPE;
269
+ v_claim public.commerce_promotion_claims%ROWTYPE;
270
+ v_global bigint;
271
+ v_customer bigint;
272
+ v_global_limit integer;
273
+ v_customer_limit integer;
274
+ v_lines bigint;
275
+ v_order_discount bigint;
276
+ v_shipping bigint;
277
+ v_shipping_discount bigint;
278
+ v_total bigint;
279
+ v_allocation_fingerprint text;
280
+ BEGIN
281
+ IF p_idempotency_key IS NULL OR char_length(btrim(p_idempotency_key)) NOT BETWEEN 8 AND 120 THEN
282
+ RAISE EXCEPTION 'commerce_order_draft_invalid_idempotency_key' USING ERRCODE = '22023';
283
+ END IF;
284
+ PERFORM pg_advisory_xact_lock(hashtextextended(p_idempotency_key, 0));
285
+ SELECT * INTO v_receipt FROM public.commerce_order_draft_receipts
286
+ WHERE idempotency_key = p_idempotency_key FOR UPDATE;
287
+ IF FOUND AND v_receipt.invalidated_at IS NOT NULL THEN
288
+ RAISE EXCEPTION 'commerce_order_draft_expired' USING ERRCODE = '40001';
289
+ END IF;
290
+
291
+ SELECT COALESCE(sum((line.value#>>'{lineSubtotalGross,amountMinor}')::bigint), 0)
292
+ INTO v_lines
293
+ FROM jsonb_array_elements(p_order_draft_snapshot->'lines') AS line(value);
294
+ SELECT
295
+ COALESCE(sum((discount.value->>'amountOffMinor')::bigint)
296
+ FILTER (WHERE discount.value->>'appliesTo' <> 'shipping'), 0),
297
+ COALESCE(sum((discount.value->>'amountOffMinor')::bigint)
298
+ FILTER (WHERE discount.value->>'appliesTo' = 'shipping'), 0)
299
+ INTO v_order_discount, v_shipping_discount
300
+ FROM jsonb_array_elements(COALESCE(p_order_draft_snapshot->'discounts', '[]'::jsonb))
301
+ AS discount(value);
302
+ v_shipping := COALESCE((p_order_draft_snapshot#>>'{totals,shippingGross,amountMinor}')::bigint, 0);
303
+ IF v_shipping_discount IS DISTINCT FROM
304
+ COALESCE((p_order_draft_snapshot#>>'{totals,shippingDiscountGross,amountMinor}')::bigint, 0)
305
+ OR v_order_discount IS DISTINCT FROM
306
+ (p_order_draft_snapshot#>>'{totals,discountTotalGross,amountMinor}')::bigint
307
+ OR v_lines IS DISTINCT FROM
308
+ (p_order_draft_snapshot#>>'{totals,subtotalGross,amountMinor}')::bigint THEN
309
+ RAISE EXCEPTION 'commerce_order_draft_money_components_mismatch' USING ERRCODE = '22023';
310
+ END IF;
311
+ IF EXISTS (
312
+ SELECT 1 FROM jsonb_array_elements(COALESCE(p_order_draft_snapshot->'discounts', '[]'::jsonb))
313
+ AS discount(value)
314
+ WHERE discount.value->>'appliesTo' = 'line'
315
+ ) THEN
316
+ RAISE EXCEPTION 'commerce_promotion_line_allocation_unsupported' USING ERRCODE = '22023';
317
+ END IF;
318
+ IF v_shipping IS DISTINCT FROM v_shipping_discount THEN
319
+ RAISE EXCEPTION 'commerce_promoted_net_shipping_unsupported' USING ERRCODE = '22023';
320
+ END IF;
321
+ v_total := v_lines + v_shipping - v_order_discount - v_shipping_discount;
322
+ IF v_total IS DISTINCT FROM
323
+ (p_order_draft_snapshot#>>'{totals,totalGross,amountMinor}')::bigint THEN
324
+ RAISE EXCEPTION 'commerce_order_draft_money_equation_mismatch' USING ERRCODE = '22023';
325
+ END IF;
326
+ IF v_total <= 0 THEN
327
+ RAISE EXCEPTION 'commerce_zero_payable_order_unsupported' USING ERRCODE = '22023';
328
+ END IF;
329
+
330
+ v_response := public.commerce_create_order_draft_with_outbox(
331
+ p_idempotency_key, p_quote_snapshot, p_order_draft_snapshot, p_client_id
332
+ );
333
+ IF (v_response#>>'{orderDraft,replayed}')::boolean THEN RETURN v_response; END IF;
334
+ v_order_id := replace(v_response#>>'{orderDraft,orderId}', 'order_', '')::uuid;
335
+ v_allocation_fingerprint := encode(sha256(convert_to(
336
+ p_order_draft_snapshot::text || '|effective-line-allocation.v1', 'UTF8'
337
+ )), 'hex');
338
+
339
+ IF v_order_discount > 0 THEN
340
+ DELETE FROM public.commerce_order_items WHERE order_id = v_order_id;
341
+ WITH source_lines AS (
342
+ SELECT
343
+ line.ordinality::integer AS source_ordinal,
344
+ line.value->>'sku' AS sku,
345
+ (line.value->>'quantity')::integer AS quantity,
346
+ (line.value#>>'{unitPriceGross,amountMinor}')::bigint AS catalog_unit,
347
+ (line.value#>>'{lineSubtotalGross,amountMinor}')::bigint AS catalog_line
348
+ FROM jsonb_array_elements(p_order_draft_snapshot->'lines')
349
+ WITH ORDINALITY AS line(value, ordinality)
350
+ ), bases AS (
351
+ SELECT source.*,
352
+ floor(v_total::numeric * source.catalog_line / v_lines)::bigint AS effective_base,
353
+ (v_total::numeric * source.catalog_line / v_lines)
354
+ - floor(v_total::numeric * source.catalog_line / v_lines) AS fraction
355
+ FROM source_lines AS source
356
+ ), remainder AS (
357
+ SELECT v_total - sum(effective_base) AS cents FROM bases
358
+ ), allocated_lines AS (
359
+ SELECT base.*,
360
+ base.effective_base + CASE WHEN row_number() OVER (
361
+ ORDER BY base.fraction DESC, base.source_ordinal
362
+ ) <= remainder.cents THEN 1 ELSE 0 END AS effective_line
363
+ FROM bases AS base CROSS JOIN remainder
364
+ ), split_lines AS (
365
+ SELECT allocated.*,
366
+ allocated.quantity - (allocated.effective_line % allocated.quantity)::integer AS split_quantity,
367
+ allocated.effective_line / allocated.quantity AS effective_unit
368
+ FROM allocated_lines AS allocated
369
+ UNION ALL
370
+ SELECT allocated.*,
371
+ (allocated.effective_line % allocated.quantity)::integer,
372
+ allocated.effective_line / allocated.quantity + 1
373
+ FROM allocated_lines AS allocated
374
+ WHERE allocated.effective_line % allocated.quantity > 0
375
+ ), prepared AS (
376
+ SELECT split.*, sku_row.id AS sku_id,
377
+ row_number() OVER (
378
+ ORDER BY split.source_ordinal, split.effective_unit, split.split_quantity
379
+ )::integer AS final_ordinal
380
+ FROM split_lines AS split
381
+ JOIN public.catalog_skus AS sku_row ON sku_row.sku = split.sku
382
+ WHERE split.split_quantity > 0
383
+ )
384
+ INSERT INTO public.commerce_order_items (
385
+ order_id, sku_id, line_ordinal, quantity, unit_amount_minor, line_amount_minor,
386
+ source_line_ordinal, catalog_unit_amount_minor, catalog_line_amount_minor,
387
+ promotion_discount_allocated_minor, promotion_allocation_fingerprint
388
+ )
389
+ SELECT
390
+ v_order_id, prepared.sku_id, prepared.final_ordinal,
391
+ prepared.split_quantity, prepared.effective_unit,
392
+ prepared.effective_unit * prepared.split_quantity,
393
+ prepared.source_ordinal, prepared.catalog_unit,
394
+ prepared.catalog_unit * prepared.split_quantity,
395
+ (prepared.catalog_unit - prepared.effective_unit) * prepared.split_quantity,
396
+ v_allocation_fingerprint
397
+ FROM prepared ORDER BY prepared.final_ordinal;
398
+ END IF;
399
+
400
+ IF v_shipping > 0 THEN
401
+ INSERT INTO public.commerce_order_adjustments (
402
+ order_id, kind, scope, amount_minor
403
+ ) VALUES (v_order_id, 'shipping_charge', 'shipping', v_shipping);
404
+ END IF;
405
+
406
+ FOR v_discount IN
407
+ SELECT value FROM jsonb_array_elements(COALESCE(p_order_draft_snapshot->'discounts', '[]'::jsonb))
408
+ WHERE value ? 'promotionId' AND COALESCE((value->>'amountOffMinor')::bigint, 0) > 0
409
+ ORDER BY value->>'promotionId'
410
+ LOOP
411
+ SELECT * INTO v_definition FROM public.commerce_promotion_definitions AS definition_row
412
+ WHERE definition_row.promotion_id = v_discount->>'promotionId' FOR UPDATE;
413
+ IF NOT FOUND OR NOT v_definition.active OR v_definition.definition->>'status' <> 'active' THEN
414
+ RAISE EXCEPTION 'commerce_promotion_definition_not_active' USING ERRCODE = '40001';
415
+ END IF;
416
+ v_global_limit := NULLIF(v_definition.definition->>'redemption_limit_global', '')::integer;
417
+ v_customer_limit := NULLIF(v_definition.definition->>'redemption_limit_per_customer', '')::integer;
418
+ SELECT count(*) FILTER (WHERE status IN ('reserved', 'redeemed')),
419
+ count(*) FILTER (WHERE status IN ('reserved', 'redeemed') AND client_id = p_client_id)
420
+ INTO v_global, v_customer FROM public.commerce_promotion_claims
421
+ WHERE promotion_id = v_definition.promotion_id;
422
+ IF v_global_limit IS NOT NULL AND v_global >= v_global_limit THEN
423
+ RAISE EXCEPTION 'commerce_promotion_global_limit_reached' USING ERRCODE = '40001';
424
+ END IF;
425
+ IF v_customer_limit IS NOT NULL AND p_client_id IS NULL THEN
426
+ RAISE EXCEPTION 'commerce_promotion_client_required' USING ERRCODE = '22023';
427
+ END IF;
428
+ IF v_customer_limit IS NOT NULL AND v_customer >= v_customer_limit THEN
429
+ RAISE EXCEPTION 'commerce_promotion_customer_limit_reached' USING ERRCODE = '40001';
430
+ END IF;
431
+ INSERT INTO public.commerce_order_adjustments (
432
+ order_id, kind, scope, amount_minor, promotion_id, definition_fingerprint
433
+ ) VALUES (
434
+ v_order_id, 'promotion_discount', v_discount->>'appliesTo',
435
+ (v_discount->>'amountOffMinor')::bigint,
436
+ v_definition.promotion_id, v_definition.definition_fingerprint
437
+ ) RETURNING * INTO v_adjustment;
438
+ INSERT INTO public.commerce_promotion_claims (
439
+ promotion_id, definition_fingerprint, adjustment_id,
440
+ order_id, client_id, amount_off_minor, expires_at
441
+ ) VALUES (
442
+ v_definition.promotion_id, v_definition.definition_fingerprint, v_adjustment.id,
443
+ v_order_id, p_client_id, v_adjustment.amount_minor, now() + interval '24 hours'
444
+ ) RETURNING * INTO v_claim;
445
+ INSERT INTO public.commerce_promotion_claim_events (claim_id, event_key, transition)
446
+ VALUES (v_claim.id, 'reserved:' || v_order_id::text, 'reserved');
447
+ END LOOP;
448
+ RETURN v_response;
449
+ END;
450
+ $$;
451
+
452
+ CREATE FUNCTION public.commerce_transition_order_promotion_claims()
453
+ RETURNS trigger LANGUAGE plpgsql SET search_path = pg_catalog AS $$
454
+ DECLARE
455
+ v_claim public.commerce_promotion_claims%ROWTYPE;
456
+ v_transition text;
457
+ BEGIN
458
+ IF NEW.status IS NOT DISTINCT FROM OLD.status THEN RETURN NEW; END IF;
459
+ IF NEW.status IN ('paid', 'fulfillment_pending', 'fulfilled') THEN v_transition := 'redeemed';
460
+ ELSIF NEW.status IN ('cancelled', 'refunded') THEN v_transition := 'released';
461
+ ELSE RETURN NEW;
462
+ END IF;
463
+ FOR v_claim IN SELECT * FROM public.commerce_promotion_claims
464
+ WHERE order_id = NEW.id ORDER BY promotion_id FOR UPDATE
465
+ LOOP
466
+ IF v_transition = 'redeemed' AND v_claim.status <> 'redeemed' THEN
467
+ UPDATE public.commerce_promotion_claims
468
+ SET status = 'redeemed', redeemed_at = COALESCE(NEW.paid_at, now()),
469
+ released_at = NULL, release_reason = NULL, updated_at = now() WHERE id = v_claim.id;
470
+ ELSIF v_transition = 'released' AND v_claim.status = 'reserved' THEN
471
+ UPDATE public.commerce_promotion_claims
472
+ SET status = 'released', redeemed_at = NULL, released_at = now(),
473
+ release_reason = 'order_' || NEW.status, updated_at = now() WHERE id = v_claim.id;
474
+ ELSE CONTINUE;
475
+ END IF;
476
+ INSERT INTO public.commerce_promotion_claim_events (claim_id, event_key, transition, reason)
477
+ VALUES (v_claim.id, v_transition || ':' || NEW.status, v_transition,
478
+ CASE WHEN v_transition = 'released' THEN 'order_' || NEW.status ELSE NULL END)
479
+ ON CONFLICT (claim_id, event_key) DO NOTHING;
480
+ END LOOP;
481
+ RETURN NEW;
482
+ END;
483
+ $$;
484
+
485
+ CREATE TRIGGER commerce_transition_order_promotion_claims_trigger
486
+ AFTER UPDATE OF status ON public.commerce_orders
487
+ FOR EACH ROW EXECUTE FUNCTION public.commerce_transition_order_promotion_claims();
488
+
489
+ CREATE FUNCTION public.commerce_order_money_summary(p_order_id uuid)
490
+ RETURNS jsonb
491
+ LANGUAGE sql
492
+ STABLE
493
+ SET search_path = pg_catalog
494
+ AS $$
495
+ SELECT jsonb_build_object(
496
+ 'subtotalMinor', COALESCE((SELECT sum(item.line_amount_minor)
497
+ FROM public.commerce_order_items AS item WHERE item.order_id = p_order_id), 0),
498
+ 'discountMinor', COALESCE((SELECT sum(adjustment.amount_minor)
499
+ FROM public.commerce_order_adjustments AS adjustment
500
+ WHERE adjustment.order_id = p_order_id AND adjustment.kind = 'promotion_discount'
501
+ AND adjustment.scope <> 'shipping'), 0),
502
+ 'shippingMinor', COALESCE((SELECT sum(adjustment.amount_minor)
503
+ FROM public.commerce_order_adjustments AS adjustment
504
+ WHERE adjustment.order_id = p_order_id AND adjustment.kind = 'shipping_charge'), 0),
505
+ 'shippingDiscountMinor', COALESCE((SELECT sum(adjustment.amount_minor)
506
+ FROM public.commerce_order_adjustments AS adjustment
507
+ WHERE adjustment.order_id = p_order_id AND adjustment.kind = 'promotion_discount'
508
+ AND adjustment.scope = 'shipping'), 0)
509
+ );
510
+ $$;
511
+
512
+ CREATE FUNCTION public.commerce_sweep_stale_promotion_claims(
513
+ p_now timestamptz DEFAULT now(), p_limit integer DEFAULT 50,
514
+ p_claim_lease_minutes integer DEFAULT 15, p_grace_minutes integer DEFAULT 5
515
+ )
516
+ RETURNS jsonb LANGUAGE plpgsql SET search_path = pg_catalog AS $$
517
+ DECLARE
518
+ v_order public.commerce_orders%ROWTYPE;
519
+ v_checked integer := 0;
520
+ v_cancelled integer := 0;
521
+ v_skipped integer := 0;
522
+ BEGIN
523
+ IF p_now IS NULL OR p_limit < 1 OR p_limit > 200
524
+ OR p_claim_lease_minutes < 1 OR p_grace_minutes < 0 THEN
525
+ RAISE EXCEPTION 'promotion_claim_sweep_invalid_input' USING ERRCODE = '22023';
526
+ END IF;
527
+ FOR v_order IN
528
+ SELECT order_row.* FROM public.commerce_orders AS order_row
529
+ WHERE order_row.status = 'pending_payment'
530
+ AND order_row.created_at <= p_now - make_interval(mins => p_claim_lease_minutes)
531
+ AND EXISTS (SELECT 1 FROM public.commerce_promotion_claims AS claim
532
+ WHERE claim.order_id = order_row.id AND claim.status = 'reserved'
533
+ AND claim.expires_at <= p_now - make_interval(mins => p_grace_minutes))
534
+ ORDER BY order_row.created_at, order_row.id LIMIT p_limit
535
+ FOR UPDATE OF order_row SKIP LOCKED
536
+ LOOP
537
+ v_checked := v_checked + 1;
538
+ PERFORM 1 FROM public.commerce_promotion_claims WHERE order_id = v_order.id
539
+ AND status = 'reserved' ORDER BY promotion_id FOR UPDATE;
540
+ IF EXISTS (SELECT 1 FROM public.commerce_settlement_intents WHERE order_id = v_order.id)
541
+ OR EXISTS (SELECT 1 FROM public.subscription_cycles AS cycle
542
+ JOIN public.fulfillment_inventory_reservations AS reservation
543
+ ON reservation.renewal_operation_id = cycle.renewal_operation_id
544
+ WHERE cycle.id = v_order.subscription_cycle_id
545
+ AND reservation.status IN ('held', 'committed', 'consumed')) THEN
546
+ v_skipped := v_skipped + 1;
547
+ CONTINUE;
548
+ END IF;
549
+ UPDATE public.commerce_orders SET status = 'cancelled', cancelled_at = p_now, updated_at = p_now
550
+ WHERE id = v_order.id AND status = 'pending_payment';
551
+ IF NOT FOUND THEN v_skipped := v_skipped + 1; CONTINUE; END IF;
552
+ UPDATE public.commerce_order_draft_receipts
553
+ SET invalidated_at = p_now, invalidation_reason = 'stale_promotion_claim'
554
+ WHERE order_id = v_order.id AND invalidated_at IS NULL;
555
+ UPDATE public.outbox_events
556
+ SET processed_at = COALESCE(processed_at, p_now),
557
+ metadata = metadata || jsonb_build_object('terminalReason', 'stale_promotion_claim')
558
+ WHERE aggregate_id = v_order.id AND event_type = 'commerce.order_draft.created';
559
+ v_cancelled := v_cancelled + 1;
560
+ END LOOP;
561
+ RETURN jsonb_build_object('checked', v_checked, 'cancelled', v_cancelled, 'skipped', v_skipped);
562
+ END;
563
+ $$;
564
+
565
+ CREATE FUNCTION public.commerce_promotion_claim_readback(p_order_id uuid)
566
+ RETURNS jsonb LANGUAGE sql STABLE SET search_path = pg_catalog AS $$
567
+ SELECT COALESCE(jsonb_agg(jsonb_build_object(
568
+ 'claimId', claim.id, 'promotionId', claim.promotion_id, 'status', claim.status,
569
+ 'amountOffMinor', claim.amount_off_minor, 'definitionFingerprint', claim.definition_fingerprint,
570
+ 'reservedAt', claim.reserved_at, 'expiresAt', claim.expires_at,
571
+ 'redeemedAt', claim.redeemed_at, 'releasedAt', claim.released_at,
572
+ 'releaseReason', claim.release_reason
573
+ ) ORDER BY claim.promotion_id), '[]'::jsonb)
574
+ FROM public.commerce_promotion_claims AS claim WHERE claim.order_id = p_order_id;
575
+ $$;
576
+
577
+ REVOKE ALL ON TABLE public.commerce_promotion_definitions FROM PUBLIC;
578
+ REVOKE ALL ON TABLE public.commerce_order_adjustments FROM PUBLIC;
579
+ REVOKE ALL ON TABLE public.commerce_promotion_claims FROM PUBLIC;
580
+ REVOKE ALL ON TABLE public.commerce_promotion_claim_events FROM PUBLIC;
581
+ REVOKE ALL ON FUNCTION public.commerce_promotion_active_definitions() FROM PUBLIC;
582
+ REVOKE ALL ON FUNCTION public.commerce_promotion_paid_order_counts(uuid) FROM PUBLIC;
583
+ REVOKE ALL ON FUNCTION public.commerce_promotion_redemption_counts(uuid) FROM PUBLIC;
584
+ REVOKE ALL ON FUNCTION public.commerce_promotion_device_first_order_redeemed(text) FROM PUBLIC;
585
+ REVOKE ALL ON FUNCTION public.commerce_create_promoted_order_draft_with_outbox(text, jsonb, jsonb, uuid) FROM PUBLIC;
586
+ REVOKE ALL ON FUNCTION public.commerce_order_adjustments_append_only() FROM PUBLIC;
587
+ REVOKE ALL ON FUNCTION public.commerce_promotion_claim_money_freeze() FROM PUBLIC;
588
+ REVOKE ALL ON FUNCTION public.commerce_transition_order_promotion_claims() FROM PUBLIC;
589
+ REVOKE ALL ON FUNCTION public.commerce_order_money_summary(uuid) FROM PUBLIC;
590
+ REVOKE ALL ON FUNCTION public.commerce_sweep_stale_promotion_claims(timestamptz, integer, integer, integer) FROM PUBLIC;
591
+ REVOKE ALL ON FUNCTION public.commerce_promotion_claim_readback(uuid) FROM PUBLIC;
@@ -0,0 +1,23 @@
1
+ -- Validate promotion lifecycle constraints without coupling validation to DDL.
2
+ --
3
+ -- CHANGE. This forward validates the promoted order-item allocation constraint
4
+ -- and the draft-receipt invalidation constraint added as NOT VALID by the
5
+ -- preceding promotion-claim lifecycle forward.
6
+ --
7
+ -- WHY. Existing rows are structurally compatible, but validating in the same
8
+ -- transaction as ADD CONSTRAINT would retain the stronger DDL lock for the
9
+ -- table scan. A separate forward lets PostgreSQL validate under its lower-lock
10
+ -- validation path.
11
+ --
12
+ -- SAFETY. No data or routine body changes. New writes were already checked from
13
+ -- the moment the constraints were added; this pass only certifies historical
14
+ -- rows. Deployment order is fixed by the platform migration manifest.
15
+ --
16
+ -- ROLLBACK. No rollback is required. If validation finds legacy drift the
17
+ -- transaction aborts without changing data or constraint validity.
18
+
19
+ ALTER TABLE public.commerce_order_items
20
+ VALIDATE CONSTRAINT commerce_order_items_promoted_allocation_check;
21
+
22
+ ALTER TABLE public.commerce_order_draft_receipts
23
+ VALIDATE CONSTRAINT commerce_order_draft_receipts_invalidation_check;