@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.
- package/CHANGELOG.md +96 -0
- package/README.md +284 -6
- package/dist/catalog/activeSkuSelection.d.ts +2 -0
- package/dist/catalog/activeSkuSelection.js +20 -0
- package/dist/catalog/adminBindings.d.ts +72 -0
- package/dist/catalog/adminBindings.js +1 -0
- package/dist/catalog/adminBundleHandler.d.ts +26 -0
- package/dist/catalog/adminBundleHandler.js +111 -0
- package/dist/catalog/adminBundleReadHandler.d.ts +20 -0
- package/dist/catalog/adminBundleReadHandler.js +185 -0
- package/dist/catalog/adminBundleWritePort.d.ts +85 -0
- package/dist/catalog/adminBundleWritePort.js +1 -0
- package/dist/catalog/bundleAvailability.d.ts +63 -0
- package/dist/catalog/bundleAvailability.js +78 -0
- package/dist/catalog/bundleAvailabilityService.d.ts +65 -0
- package/dist/catalog/bundleAvailabilityService.js +89 -0
- package/dist/catalog/bundleBindings.d.ts +33 -0
- package/dist/catalog/bundleBindings.js +1 -0
- package/dist/catalog/bundleCatalogQueries.d.ts +28 -0
- package/dist/catalog/bundleCatalogQueries.js +84 -0
- package/dist/catalog/bundleCatalogReadPort.d.ts +166 -0
- package/dist/catalog/bundleCatalogReadPort.js +36 -0
- package/dist/catalog/bundleCatalogStore.d.ts +3 -0
- package/dist/catalog/bundleCatalogStore.js +152 -0
- package/dist/catalog/bundleRuleCodes.d.ts +41 -0
- package/dist/catalog/bundleRuleCodes.js +110 -0
- package/dist/catalog/bundleRules.d.ts +69 -0
- package/dist/catalog/bundleRules.js +102 -0
- package/dist/catalog/catalogDraftStore.d.ts +4 -0
- package/dist/catalog/catalogDraftStore.js +63 -0
- package/dist/catalog/catalogSkuEnvelope.d.ts +7 -0
- package/dist/catalog/catalogSkuEnvelope.js +142 -0
- package/dist/catalog/catalogSkuEnvelopeMapper.d.ts +38 -0
- package/dist/catalog/catalogSkuEnvelopeMapper.js +88 -0
- package/dist/catalog/contracts/bundleAdmin.d.ts +143 -0
- package/dist/catalog/contracts/bundleAdmin.js +1 -0
- package/dist/catalog/contracts/bundleAvailability.d.ts +61 -0
- package/dist/catalog/contracts/bundleAvailability.js +1 -0
- package/dist/catalog/contracts/bundleRead.d.ts +223 -0
- package/dist/catalog/contracts/bundleRead.js +1 -0
- package/dist/catalog/contracts/draft.d.ts +79 -0
- package/dist/catalog/contracts/draft.js +47 -0
- package/dist/catalog/contracts/foundation.d.ts +78 -0
- package/dist/catalog/contracts/foundation.js +53 -0
- package/dist/catalog/contracts/index.d.ts +14 -0
- package/dist/catalog/contracts/index.js +6 -0
- package/dist/catalog/contracts/lifecycle.d.ts +77 -0
- package/dist/catalog/contracts/lifecycle.js +1 -0
- package/dist/catalog/contracts/productMediaContracts.d.ts +77 -0
- package/dist/catalog/contracts/productMediaContracts.js +149 -0
- package/dist/catalog/contracts/productTypes.d.ts +54 -0
- package/dist/catalog/contracts/productTypes.js +16 -0
- package/dist/catalog/contracts/resolveProductMedia.d.ts +3 -0
- package/dist/catalog/contracts/resolveProductMedia.js +78 -0
- package/dist/catalog/contracts/sellable.d.ts +23 -0
- package/dist/catalog/contracts/sellable.js +1 -0
- package/dist/catalog/draftHandler.d.ts +25 -0
- package/dist/catalog/draftHandler.js +118 -0
- package/dist/catalog/draftPorts.d.ts +18 -0
- package/dist/catalog/draftPorts.js +8 -0
- package/dist/catalog/draftSchemas.d.ts +423 -0
- package/dist/catalog/draftSchemas.js +89 -0
- package/dist/catalog/draftValidation.d.ts +21 -0
- package/dist/catalog/draftValidation.js +125 -0
- package/dist/catalog/foundationSchemas.d.ts +98 -0
- package/dist/catalog/foundationSchemas.js +110 -0
- package/dist/catalog/index.d.ts +43 -0
- package/dist/catalog/index.js +25 -0
- package/dist/catalog/mediaSourcePack.d.ts +51 -0
- package/dist/catalog/mediaSourcePack.js +247 -0
- package/dist/catalog/productTypeSchemas.d.ts +46 -0
- package/dist/catalog/productTypeSchemas.js +72 -0
- package/dist/catalog/publicationPorts.d.ts +42 -0
- package/dist/catalog/publicationPorts.js +1 -0
- package/dist/catalog/readPorts.d.ts +51 -0
- package/dist/catalog/readPorts.js +1 -0
- package/dist/catalog/referenceCatalogHandler.d.ts +7 -0
- package/dist/catalog/referenceCatalogHandler.js +27 -0
- package/dist/catalog/resolvedSkuProjection.d.ts +88 -0
- package/dist/catalog/resolvedSkuProjection.js +60 -0
- package/dist/catalog/sellableBundleHandler.d.ts +46 -0
- package/dist/catalog/sellableBundleHandler.js +84 -0
- package/dist/catalog/sellableSchemas.d.ts +46 -0
- package/dist/catalog/sellableSchemas.js +27 -0
- package/dist/catalog/sql.d.ts +46 -0
- package/dist/catalog/sql.js +13 -0
- package/dist/catalog/validation.d.ts +2 -0
- package/dist/catalog/validation.js +3 -0
- package/dist/communications/contracts/index.d.ts +1 -0
- package/dist/communications/contracts/marketingSync.d.ts +194 -0
- package/dist/communications/contracts/marketingSync.js +1 -0
- package/dist/communications/index.d.ts +1 -0
- package/dist/communications/klaviyo/consentPush.d.ts +51 -0
- package/dist/communications/klaviyo/consentPush.js +19 -0
- package/dist/communications/klaviyo/index.d.ts +110 -0
- package/dist/communications/klaviyo/index.js +860 -0
- package/dist/communications/newsletterIntegrationContracts.d.ts +3 -3
- package/dist/communications/resend/index.d.ts +40 -0
- package/dist/communications/resend/index.js +310 -0
- package/dist/composition/catalogContribution.d.ts +18 -0
- package/dist/composition/catalogContribution.js +21 -0
- package/dist/composition/index.d.ts +1 -0
- package/dist/composition/index.js +1 -0
- package/dist/identity/customerContracts.d.ts +2 -2
- package/dist/inventory/adminInventory.d.ts +13 -0
- package/dist/inventory/adminInventory.js +214 -0
- package/dist/inventory/contracts/forecast.d.ts +86 -0
- package/dist/inventory/contracts/forecast.js +1 -0
- package/dist/inventory/contracts/index.d.ts +4 -0
- package/dist/inventory/contracts/index.js +1 -0
- package/dist/inventory/contracts/inventory.d.ts +157 -0
- package/dist/inventory/contracts/inventory.js +1 -0
- package/dist/inventory/contracts/newPurchaseStock.d.ts +20 -0
- package/dist/inventory/contracts/newPurchaseStock.js +1 -0
- package/dist/inventory/contracts/reservation.d.ts +18 -0
- package/dist/inventory/contracts/reservation.js +1 -0
- package/dist/inventory/forecast.d.ts +24 -0
- package/dist/inventory/forecast.js +200 -0
- package/dist/inventory/index.d.ts +13 -0
- package/dist/inventory/index.js +10 -0
- package/dist/inventory/inventoryHandlers.d.ts +53 -0
- package/dist/inventory/inventoryHandlers.js +151 -0
- package/dist/inventory/newPurchaseStockAvailability.d.ts +47 -0
- package/dist/inventory/newPurchaseStockAvailability.js +75 -0
- package/dist/inventory/ports.d.ts +21 -0
- package/dist/inventory/ports.js +16 -0
- package/dist/inventory/renewalReservation.d.ts +27 -0
- package/dist/inventory/renewalReservation.js +61 -0
- package/dist/inventory/reservationPolicy.d.ts +6 -0
- package/dist/inventory/reservationPolicy.js +19 -0
- package/dist/inventory/schemas.d.ts +137 -0
- package/dist/inventory/schemas.js +112 -0
- package/dist/inventory/sql.d.ts +14 -0
- package/dist/inventory/sql.js +5 -0
- package/dist/inventory/subscriptionForecastCalculation.d.ts +4 -0
- package/dist/inventory/subscriptionForecastCalculation.js +133 -0
- package/dist/pricing/acquisitionFinancialPolicy.d.ts +26 -0
- package/dist/pricing/acquisitionFinancialPolicy.js +1 -0
- package/dist/pricing/acquisitionOfferPricing.d.ts +27 -0
- package/dist/pricing/acquisitionOfferPricing.js +25 -0
- package/dist/pricing/acquisitionOfferPricingHandler.d.ts +20 -0
- package/dist/pricing/acquisitionOfferPricingHandler.js +105 -0
- package/dist/pricing/acquisitionOfferPricingSchemas.d.ts +31 -0
- package/dist/pricing/acquisitionOfferPricingSchemas.js +33 -0
- package/dist/pricing/acquisitionQuoteBinding.d.ts +12 -0
- package/dist/pricing/acquisitionQuoteBinding.js +12 -0
- package/dist/pricing/acquisitionReadiness.d.ts +31 -0
- package/dist/pricing/acquisitionReadiness.js +117 -0
- package/dist/pricing/acquisitionTerms.d.ts +19 -0
- package/dist/pricing/acquisitionTerms.js +126 -0
- package/dist/pricing/acquisitionTermsSchemas.d.ts +59 -0
- package/dist/pricing/acquisitionTermsSchemas.js +42 -0
- package/dist/pricing/catalogFactsProvenance.d.ts +33 -0
- package/dist/pricing/catalogFactsProvenance.js +64 -0
- package/dist/pricing/catalogFactsSchemas.d.ts +45 -0
- package/dist/pricing/catalogFactsSchemas.js +58 -0
- package/dist/pricing/commerceOfferPricing.d.ts +25 -0
- package/dist/pricing/commerceOfferPricing.js +139 -0
- package/dist/pricing/commerceOfferPricingCache.d.ts +10 -0
- package/dist/pricing/commerceOfferPricingCache.js +44 -0
- package/dist/pricing/commerceOfferPricingHandler.d.ts +21 -0
- package/dist/pricing/commerceOfferPricingHandler.js +78 -0
- package/dist/pricing/commercePriceAuthority.d.ts +26 -0
- package/dist/pricing/commercePriceAuthority.js +79 -0
- package/dist/pricing/commercePricingPolicyErrors.d.ts +40 -0
- package/dist/pricing/commercePricingPolicyErrors.js +67 -0
- package/dist/pricing/commerceQuoteBatchHandler.d.ts +37 -0
- package/dist/pricing/commerceQuoteBatchHandler.js +83 -0
- package/dist/pricing/commerceQuoteCatalogReadPort.d.ts +27 -0
- package/dist/pricing/commerceQuoteCatalogReadPort.js +8 -0
- package/dist/pricing/commerceQuoteHandler.d.ts +31 -0
- package/dist/pricing/commerceQuoteHandler.js +110 -0
- package/dist/pricing/commerceQuoteSnapshotExpect.d.ts +9 -0
- package/dist/pricing/commerceQuoteSnapshotExpect.js +22 -0
- package/dist/pricing/contracts/acquisitionTerms.d.ts +32 -0
- package/dist/pricing/contracts/acquisitionTerms.js +2 -0
- package/dist/pricing/contracts/authority.d.ts +27 -0
- package/dist/pricing/contracts/authority.js +1 -0
- package/dist/pricing/contracts/evidence.d.ts +33 -0
- package/dist/pricing/contracts/evidence.js +1 -0
- package/dist/pricing/contracts/index.d.ts +17 -0
- package/dist/pricing/contracts/index.js +7 -0
- package/dist/pricing/contracts/money.d.ts +27 -0
- package/dist/pricing/contracts/money.js +1 -0
- package/dist/pricing/contracts/offer.d.ts +52 -0
- package/dist/pricing/contracts/offer.js +4 -0
- package/dist/pricing/contracts/offerPolicy.d.ts +16 -0
- package/dist/pricing/contracts/offerPolicy.js +5 -0
- package/dist/pricing/contracts/policy.d.ts +22 -0
- package/dist/pricing/contracts/policy.js +3 -0
- package/dist/pricing/contracts/provenance.d.ts +24 -0
- package/dist/pricing/contracts/provenance.js +2 -0
- package/dist/pricing/contracts/quote.d.ts +94 -0
- package/dist/pricing/contracts/quote.js +1 -0
- package/dist/pricing/dbBackedCommerceQuoteHelpers.d.ts +78 -0
- package/dist/pricing/dbBackedCommerceQuoteHelpers.js +146 -0
- package/dist/pricing/dbBackedCommerceQuotePort.d.ts +66 -0
- package/dist/pricing/dbBackedCommerceQuotePort.js +206 -0
- package/dist/pricing/dbBackedCommerceQuoteSnapshotVerifier.d.ts +4 -0
- package/dist/pricing/dbBackedCommerceQuoteSnapshotVerifier.js +25 -0
- package/dist/pricing/index.d.ts +51 -0
- package/dist/pricing/index.js +36 -0
- package/dist/pricing/offerPolicyReadiness.d.ts +21 -0
- package/dist/pricing/offerPolicyReadiness.js +79 -0
- package/dist/pricing/offerPolicySchemas.d.ts +25 -0
- package/dist/pricing/offerPolicySchemas.js +15 -0
- package/dist/pricing/offerPricingSchemas.d.ts +315 -0
- package/dist/pricing/offerPricingSchemas.js +65 -0
- package/dist/pricing/ports.d.ts +13 -0
- package/dist/pricing/ports.js +9 -0
- package/dist/pricing/pricingPolicyToken.d.ts +39 -0
- package/dist/pricing/pricingPolicyToken.js +84 -0
- package/dist/pricing/quoteAcquisitionTerms.d.ts +2 -0
- package/dist/pricing/quoteAcquisitionTerms.js +4 -0
- package/dist/pricing/quoteCodeRejectionDetails.d.ts +20 -0
- package/dist/pricing/quoteCodeRejectionDetails.js +22 -0
- package/dist/pricing/quotePorts.d.ts +30 -0
- package/dist/pricing/quotePorts.js +20 -0
- package/dist/pricing/quotePrimitives.d.ts +13 -0
- package/dist/pricing/quotePrimitives.js +18 -0
- package/dist/pricing/quotePromotionEvidence.d.ts +39 -0
- package/dist/pricing/quotePromotionEvidence.js +73 -0
- package/dist/pricing/quoteSchemas.d.ts +1176 -0
- package/dist/pricing/quoteSchemas.js +196 -0
- package/dist/pricing/subscriptionPricePolicy.d.ts +52 -0
- package/dist/pricing/subscriptionPricePolicy.js +96 -0
- package/dist/pricing/taxProfileGuard.d.ts +2 -0
- package/dist/pricing/taxProfileGuard.js +24 -0
- package/dist/pricing/validation.d.ts +2 -0
- package/dist/pricing/validation.js +3 -0
- package/dist/promotions/adminBindings.d.ts +72 -0
- package/dist/promotions/adminBindings.js +1 -0
- package/dist/promotions/adminPromotionCodesContracts.d.ts +498 -0
- package/dist/promotions/adminPromotionCodesContracts.js +211 -0
- package/dist/promotions/adminPromotionCodesDataPort.d.ts +47 -0
- package/dist/promotions/adminPromotionCodesDataPort.js +1 -0
- package/dist/promotions/adminPromotionCodesHandler.d.ts +14 -0
- package/dist/promotions/adminPromotionCodesHandler.js +194 -0
- package/dist/promotions/adminPromotionsContracts.d.ts +235 -0
- package/dist/promotions/adminPromotionsContracts.js +99 -0
- package/dist/promotions/adminPromotionsDataPort.d.ts +42 -0
- package/dist/promotions/adminPromotionsDataPort.js +1 -0
- package/dist/promotions/adminPromotionsHandler.d.ts +16 -0
- package/dist/promotions/adminPromotionsHandler.js +47 -0
- package/dist/promotions/contracts/index.d.ts +387 -0
- package/dist/promotions/contracts/index.js +1 -0
- package/dist/promotions/index.d.ts +22 -0
- package/dist/promotions/index.js +21 -0
- package/dist/promotions/promoDataPort.d.ts +47 -0
- package/dist/promotions/promoDataPort.js +14 -0
- package/dist/promotions/promotionAcceptanceTelemetry.d.ts +29 -0
- package/dist/promotions/promotionAcceptanceTelemetry.js +45 -0
- package/dist/promotions/promotionBenefitDefinition.d.ts +37 -0
- package/dist/promotions/promotionBenefitDefinition.js +33 -0
- package/dist/promotions/promotionClaimSweepPort.d.ts +14 -0
- package/dist/promotions/promotionClaimSweepPort.js +8 -0
- package/dist/promotions/promotionClaims.d.ts +5 -0
- package/dist/promotions/promotionClaims.js +57 -0
- package/dist/promotions/promotionCodePreview.d.ts +11 -0
- package/dist/promotions/promotionCodePreview.js +154 -0
- package/dist/promotions/promotionCodeQuotePort.d.ts +25 -0
- package/dist/promotions/promotionCodeQuotePort.js +1 -0
- package/dist/promotions/promotionQuoteAcceptance.d.ts +65 -0
- package/dist/promotions/promotionQuoteAcceptance.js +202 -0
- package/dist/promotions/promotionQuoteBinding.d.ts +71 -0
- package/dist/promotions/promotionQuoteBinding.js +85 -0
- package/dist/promotions/quoteAutomaticPromotions.d.ts +24 -0
- package/dist/promotions/quoteAutomaticPromotions.js +36 -0
- package/dist/promotions/quotePromoDiscounts.d.ts +32 -0
- package/dist/promotions/quotePromoDiscounts.js +140 -0
- package/dist/promotions/quotePromotionCodeAdjustments.d.ts +27 -0
- package/dist/promotions/quotePromotionCodeAdjustments.js +223 -0
- package/dist/promotions/quotePromotionV2.d.ts +29 -0
- package/dist/promotions/quotePromotionV2.js +174 -0
- package/dist/promotions/sql.d.ts +14 -0
- package/dist/promotions/sql.js +5 -0
- package/dist/promotions/validation.d.ts +2 -0
- package/dist/promotions/validation.js +3 -0
- package/dist/shipping/addressCanonLookupHandler.d.ts +7 -0
- package/dist/shipping/addressCanonLookupHandler.js +105 -0
- package/dist/shipping/addressCanonical.d.ts +2 -0
- package/dist/shipping/addressCanonical.js +26 -0
- package/dist/shipping/addressPorts.d.ts +39 -0
- package/dist/shipping/addressPorts.js +1 -0
- package/dist/shipping/addressSchemas.d.ts +30 -0
- package/dist/shipping/addressSchemas.js +1 -0
- package/dist/shipping/adminShippingRateHandler.d.ts +4 -0
- package/dist/shipping/adminShippingRateHandler.js +64 -0
- package/dist/shipping/contracts/address.d.ts +144 -0
- package/dist/shipping/contracts/address.js +1 -0
- package/dist/shipping/contracts/delivery.d.ts +110 -0
- package/dist/shipping/contracts/delivery.js +1 -0
- package/dist/shipping/contracts/index.d.ts +3 -0
- package/dist/shipping/contracts/index.js +1 -0
- package/dist/shipping/contracts/shippingRate.d.ts +11 -0
- package/dist/shipping/contracts/shippingRate.js +1 -0
- package/dist/shipping/customerAddressesHandler.d.ts +5 -0
- package/dist/shipping/customerAddressesHandler.js +80 -0
- package/dist/shipping/customerSelfServiceAddressModels.d.ts +27 -0
- package/dist/shipping/customerSelfServiceAddressModels.js +101 -0
- package/dist/shipping/deliverySelectionHandler.d.ts +10 -0
- package/dist/shipping/deliverySelectionHandler.js +77 -0
- package/dist/shipping/deliverySelectionPort.d.ts +8 -0
- package/dist/shipping/deliverySelectionPort.js +1 -0
- package/dist/shipping/deliverySelectionSummary.d.ts +2 -0
- package/dist/shipping/deliverySelectionSummary.js +53 -0
- package/dist/shipping/handlerSchemas.d.ts +21 -0
- package/dist/shipping/handlerSchemas.js +1 -0
- package/dist/shipping/index.d.ts +17 -0
- package/dist/shipping/index.js +8 -0
- package/dist/shipping/pickupPointSearchPort.d.ts +4 -0
- package/dist/shipping/pickupPointSearchPort.js +1 -0
- package/dist/shipping/readDeliverySelectionEvidence.d.ts +2 -0
- package/dist/shipping/readDeliverySelectionEvidence.js +44 -0
- package/dist/shipping/shippingRatePorts.d.ts +52 -0
- package/dist/shipping/shippingRatePorts.js +1 -0
- package/package.json +62 -2
- package/release-gates.json +218 -10
- package/sql/20260807140000_read_parity_catalog.sql +94 -0
- package/sql/20260810120000_storefront_catalog_attributes.sql +51 -0
- package/sql/20260812140000_sellable_bundle_catalog.sql +124 -0
- package/sql/20260812210000_bundle_operator_write_boundary.sql +567 -0
- package/sql/20260814000000_fulfillment_stock_evidence.sql +239 -0
- package/sql/20260815120000_automatic_subscription_renewal.sql +1083 -0
- package/sql/20260817180000_promotion_claim_lifecycle.sql +591 -0
- package/sql/20260817180100_promotion_claim_lifecycle_validation.sql +23 -0
- package/sql/20260827220000_catalog_document_revision_foundation.sql +226 -0
- package/sql/20260827220001_catalog_document_revision_foundation_validate.sql +10 -0
- package/sql/20260908100000_catalog_draft_foundation.sql +217 -0
- package/src/catalog/activeSkuSelection.ts +20 -0
- package/src/catalog/adminBindings.ts +59 -0
- package/src/catalog/adminBundleHandler.ts +165 -0
- package/src/catalog/adminBundleReadHandler.ts +261 -0
- package/src/catalog/adminBundleWritePort.ts +102 -0
- package/src/catalog/bundleAvailability.ts +129 -0
- package/src/catalog/bundleAvailabilityService.ts +171 -0
- package/src/catalog/bundleBindings.ts +29 -0
- package/src/catalog/bundleCatalogQueries.ts +98 -0
- package/src/catalog/bundleCatalogReadPort.ts +177 -0
- package/src/catalog/bundleCatalogStore.ts +269 -0
- package/src/catalog/bundleRuleCodes.ts +134 -0
- package/src/catalog/bundleRules.ts +153 -0
- package/src/catalog/catalogDraftStore.ts +71 -0
- package/src/catalog/catalogSkuEnvelope.ts +214 -0
- package/src/catalog/catalogSkuEnvelopeMapper.ts +160 -0
- package/src/catalog/contracts/bundleAdmin.ts +20 -0
- package/src/catalog/contracts/bundleAvailability.ts +5 -0
- package/src/catalog/contracts/bundleRead.ts +13 -0
- package/src/catalog/contracts/draft.ts +69 -0
- package/src/catalog/contracts/foundation.ts +104 -0
- package/src/catalog/contracts/index.ts +14 -0
- package/src/catalog/contracts/lifecycle.ts +74 -0
- package/src/catalog/contracts/productMediaContracts.ts +170 -0
- package/src/catalog/contracts/productTypes.ts +35 -0
- package/src/catalog/contracts/resolveProductMedia.ts +85 -0
- package/src/catalog/contracts/sellable.ts +12 -0
- package/src/catalog/draftHandler.ts +105 -0
- package/src/catalog/draftPorts.ts +18 -0
- package/src/catalog/draftSchemas.ts +88 -0
- package/src/catalog/draftValidation.ts +100 -0
- package/src/catalog/foundationSchemas.ts +123 -0
- package/src/catalog/index.ts +43 -0
- package/src/catalog/mediaSourcePack.ts +219 -0
- package/src/catalog/productTypeSchemas.ts +70 -0
- package/src/catalog/publicationPorts.ts +44 -0
- package/src/catalog/readPorts.ts +61 -0
- package/src/catalog/referenceCatalogHandler.ts +39 -0
- package/src/catalog/resolvedSkuProjection.ts +76 -0
- package/src/catalog/sellableBundleHandler.ts +133 -0
- package/src/catalog/sellableSchemas.ts +33 -0
- package/src/catalog/sql.ts +14 -0
- package/src/catalog/validation.ts +3 -0
- package/src/communications/contracts/index.ts +1 -0
- package/src/communications/contracts/marketingSync.ts +109 -0
- package/src/communications/index.ts +1 -0
- package/src/communications/klaviyo/consentPush.ts +19 -0
- package/src/communications/klaviyo/index.ts +649 -0
- package/src/communications/resend/index.ts +350 -0
- package/src/composition/catalogContribution.ts +32 -0
- package/src/composition/index.ts +1 -0
- package/src/inventory/adminInventory.ts +251 -0
- package/src/inventory/contracts/forecast.ts +96 -0
- package/src/inventory/contracts/index.ts +18 -0
- package/src/inventory/contracts/inventory.ts +14 -0
- package/src/inventory/contracts/newPurchaseStock.ts +23 -0
- package/src/inventory/contracts/reservation.ts +20 -0
- package/src/inventory/forecast.ts +239 -0
- package/src/inventory/index.ts +21 -0
- package/src/inventory/inventoryHandlers.ts +215 -0
- package/src/inventory/newPurchaseStockAvailability.ts +120 -0
- package/src/inventory/ports.ts +46 -0
- package/src/inventory/renewalReservation.ts +88 -0
- package/src/inventory/reservationPolicy.ts +27 -0
- package/src/inventory/schemas.ts +128 -0
- package/src/inventory/sql.ts +5 -0
- package/src/inventory/subscriptionForecastCalculation.ts +157 -0
- package/src/pricing/acquisitionFinancialPolicy.ts +26 -0
- package/src/pricing/acquisitionOfferPricing.ts +38 -0
- package/src/pricing/acquisitionOfferPricingHandler.ts +157 -0
- package/src/pricing/acquisitionOfferPricingSchemas.ts +35 -0
- package/src/pricing/acquisitionQuoteBinding.ts +12 -0
- package/src/pricing/acquisitionReadiness.ts +148 -0
- package/src/pricing/acquisitionTerms.ts +125 -0
- package/src/pricing/acquisitionTermsSchemas.ts +52 -0
- package/src/pricing/catalogFactsProvenance.ts +102 -0
- package/src/pricing/catalogFactsSchemas.ts +69 -0
- package/src/pricing/commerceOfferPricing.ts +224 -0
- package/src/pricing/commerceOfferPricingCache.ts +53 -0
- package/src/pricing/commerceOfferPricingHandler.ts +137 -0
- package/src/pricing/commercePriceAuthority.ts +104 -0
- package/src/pricing/commercePricingPolicyErrors.ts +88 -0
- package/src/pricing/commerceQuoteBatchHandler.ts +129 -0
- package/src/pricing/commerceQuoteCatalogReadPort.ts +42 -0
- package/src/pricing/commerceQuoteHandler.ts +184 -0
- package/src/pricing/commerceQuoteSnapshotExpect.ts +48 -0
- package/src/pricing/contracts/acquisitionTerms.ts +26 -0
- package/src/pricing/contracts/authority.ts +44 -0
- package/src/pricing/contracts/evidence.ts +25 -0
- package/src/pricing/contracts/index.ts +17 -0
- package/src/pricing/contracts/money.ts +32 -0
- package/src/pricing/contracts/offer.ts +42 -0
- package/src/pricing/contracts/offerPolicy.ts +17 -0
- package/src/pricing/contracts/policy.ts +26 -0
- package/src/pricing/contracts/provenance.ts +19 -0
- package/src/pricing/contracts/quote.ts +106 -0
- package/src/pricing/dbBackedCommerceQuoteHelpers.ts +256 -0
- package/src/pricing/dbBackedCommerceQuotePort.ts +260 -0
- package/src/pricing/dbBackedCommerceQuoteSnapshotVerifier.ts +49 -0
- package/src/pricing/index.ts +52 -0
- package/src/pricing/offerPolicyReadiness.ts +110 -0
- package/src/pricing/offerPolicySchemas.ts +23 -0
- package/src/pricing/offerPricingSchemas.ts +92 -0
- package/src/pricing/ports.ts +17 -0
- package/src/pricing/pricingPolicyToken.ts +119 -0
- package/src/pricing/quoteAcquisitionTerms.ts +10 -0
- package/src/pricing/quoteCodeRejectionDetails.ts +23 -0
- package/src/pricing/quotePorts.ts +58 -0
- package/src/pricing/quotePrimitives.ts +21 -0
- package/src/pricing/quotePromotionEvidence.ts +82 -0
- package/src/pricing/quoteSchemas.ts +230 -0
- package/src/pricing/subscriptionPricePolicy.ts +113 -0
- package/src/pricing/taxProfileGuard.ts +33 -0
- package/src/pricing/validation.ts +3 -0
- package/src/promotions/adminBindings.ts +53 -0
- package/src/promotions/adminPromotionCodesContracts.ts +244 -0
- package/src/promotions/adminPromotionCodesDataPort.ts +56 -0
- package/src/promotions/adminPromotionCodesHandler.ts +254 -0
- package/src/promotions/adminPromotionsContracts.ts +121 -0
- package/src/promotions/adminPromotionsDataPort.ts +48 -0
- package/src/promotions/adminPromotionsHandler.ts +72 -0
- package/src/promotions/contracts/index.ts +387 -0
- package/src/promotions/index.ts +22 -0
- package/src/promotions/promoDataPort.ts +65 -0
- package/src/promotions/promotionAcceptanceTelemetry.ts +73 -0
- package/src/promotions/promotionBenefitDefinition.ts +48 -0
- package/src/promotions/promotionClaimSweepPort.ts +23 -0
- package/src/promotions/promotionClaims.ts +70 -0
- package/src/promotions/promotionCodePreview.ts +183 -0
- package/src/promotions/promotionCodeQuotePort.ts +35 -0
- package/src/promotions/promotionQuoteAcceptance.ts +284 -0
- package/src/promotions/promotionQuoteBinding.ts +158 -0
- package/src/promotions/quoteAutomaticPromotions.ts +58 -0
- package/src/promotions/quotePromoDiscounts.ts +185 -0
- package/src/promotions/quotePromotionCodeAdjustments.ts +277 -0
- package/src/promotions/quotePromotionV2.ts +223 -0
- package/src/promotions/sql.ts +5 -0
- package/src/promotions/validation.ts +3 -0
- package/src/shipping/addressCanonLookupHandler.ts +114 -0
- package/src/shipping/addressCanonical.ts +31 -0
- package/src/shipping/addressPorts.ts +48 -0
- package/src/shipping/addressSchemas.ts +28 -0
- package/src/shipping/adminShippingRateHandler.ts +72 -0
- package/src/shipping/contracts/address.ts +71 -0
- package/src/shipping/contracts/delivery.ts +114 -0
- package/src/shipping/contracts/index.ts +18 -0
- package/src/shipping/contracts/shippingRate.ts +7 -0
- package/src/shipping/customerAddressesHandler.ts +100 -0
- package/src/shipping/customerSelfServiceAddressModels.ts +124 -0
- package/src/shipping/deliverySelectionHandler.ts +94 -0
- package/src/shipping/deliverySelectionPort.ts +10 -0
- package/src/shipping/deliverySelectionSummary.ts +56 -0
- package/src/shipping/handlerSchemas.ts +19 -0
- package/src/shipping/index.ts +23 -0
- package/src/shipping/pickupPointSearchPort.ts +8 -0
- package/src/shipping/readDeliverySelectionEvidence.ts +51 -0
- package/src/shipping/shippingRatePorts.ts +36 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bundle write rules — the named, enforced invariants of the agent-operable
|
|
3
|
+
* bundle write path. These codes are the single vocabulary shared by the request
|
|
4
|
+
* contracts, the pure rule predicates (`bundleRules.ts`), managed write routines
|
|
5
|
+
* and the over-the-wire error taxonomy. Managed routines re-derive state rules;
|
|
6
|
+
* native actor-kind enforcement relies on the handler, not an independent
|
|
7
|
+
* database gate.
|
|
8
|
+
*
|
|
9
|
+
* The catalog rules use this same shape; the lifecycle subset is expressed
|
|
10
|
+
* through the host lifecycle kit, and the codes stay here as
|
|
11
|
+
* this domain's registry.
|
|
12
|
+
*/
|
|
13
|
+
export const BUNDLE_RULE_CODES = [
|
|
14
|
+
// Machine (agent) actors compose, price and archive drafts, but may NOT
|
|
15
|
+
// activate or deactivate. Enforced by the handler (allowedActorKinds); the
|
|
16
|
+
// managed activate/deactivate routines also re-derive and RAISE it, while the
|
|
17
|
+
// native routines rely on the handler gate.
|
|
18
|
+
"DRAFT_ONLY_FOR_MACHINE",
|
|
19
|
+
// A bundle with no components is not a bill of materials. Request-decidable on
|
|
20
|
+
// the whole-set composition replace.
|
|
21
|
+
"MIN_COMPONENTS",
|
|
22
|
+
// Every component being an add-on leaves nothing that is always in the box.
|
|
23
|
+
// At least one non-addon component is required. Request-decidable.
|
|
24
|
+
"ADDON_ONLY_COMPOSITION",
|
|
25
|
+
// One row per unit per bundle: multiplicity is the quantity, never a repeated
|
|
26
|
+
// component. Request-decidable on the whole-set replace.
|
|
27
|
+
"DUPLICATE_COMPONENT",
|
|
28
|
+
// Creating a bundle whose code is already used is rejected (unique code).
|
|
29
|
+
"CODE_TAKEN",
|
|
30
|
+
// A composition entry naming a unit that does not exist is rejected.
|
|
31
|
+
"COMPONENT_NOT_FOUND",
|
|
32
|
+
// A component must itself be sellable: active AND sellable on its own. A bundle
|
|
33
|
+
// must not become the only way an unsellable unit reaches a customer.
|
|
34
|
+
"COMPONENT_NOT_SELLABLE",
|
|
35
|
+
// Every component must be priced in the currency of the bundle's price list;
|
|
36
|
+
// a mixed-currency bill of materials has no single reference total.
|
|
37
|
+
"COMPONENT_CURRENCY_MISMATCH",
|
|
38
|
+
// A bundle is never priced above the sum of its parts. Hard refusal, not a
|
|
39
|
+
// warning: the discount framing is the product, and the kernel allocator
|
|
40
|
+
// returns the same decision as one comparison.
|
|
41
|
+
"TARGET_ABOVE_COMPONENT_SUM",
|
|
42
|
+
// The target cannot cover every component's minimum payable amount.
|
|
43
|
+
"TARGET_BELOW_FLOOR",
|
|
44
|
+
// Activation requires an active target price on the bundle.
|
|
45
|
+
"PRICE_REQUIRED_TO_SELL",
|
|
46
|
+
// Activation requires a non-empty composition.
|
|
47
|
+
"COMPOSITION_REQUIRED_TO_SELL",
|
|
48
|
+
// Target-price changes INSERT a new price row and deactivate the old one; an
|
|
49
|
+
// existing row is never mutated in place.
|
|
50
|
+
"APPEND_ONLY_PRICE",
|
|
51
|
+
// A bundle referenced by an order or a subscription is never hard-deleted;
|
|
52
|
+
// removal is an archive (status flip).
|
|
53
|
+
"NO_HARD_DELETE",
|
|
54
|
+
// Restore is the inverse of archive: it applies only to an ARCHIVED bundle.
|
|
55
|
+
"RESTORE_REQUIRES_ARCHIVED",
|
|
56
|
+
// Deactivate (unpublish) applies only to a LIVE bundle.
|
|
57
|
+
"DEACTIVATE_REQUIRES_ACTIVE",
|
|
58
|
+
// Only the exploded fulfillment mode has a runtime. The stored column admits
|
|
59
|
+
// the pre-packed mode so it never has to be widened; the refusal lives here.
|
|
60
|
+
"FULFILLMENT_MODE_UNSUPPORTED",
|
|
61
|
+
// A non-empty composition constraint is validated by the injected
|
|
62
|
+
// CompositionRulesPort; its refusal surfaces under this code.
|
|
63
|
+
"CONSTRAINT_VALIDATION_FAILED",
|
|
64
|
+
// Clone reads its source before replaying a fresh draft; a missing source is
|
|
65
|
+
// rejected before the replay.
|
|
66
|
+
"CLONE_SOURCE_NOT_FOUND",
|
|
67
|
+
];
|
|
68
|
+
/**
|
|
69
|
+
* The two target-price codes are NOT re-derived here — they are the kernel
|
|
70
|
+
* allocator's own failure vocabulary, projected onto this domain's registry.
|
|
71
|
+
*
|
|
72
|
+
* Declared as an exhaustive `Record` over `BundleAllocationFailureCode` on
|
|
73
|
+
* purpose: when `@openlup/core/pricing` learns a new failure code, this object
|
|
74
|
+
* stops compiling until the domain decides which rule it is. `REFERENCE_TOTAL_ZERO`
|
|
75
|
+
* means the composition weighed nothing, which is the same condition
|
|
76
|
+
* `MIN_COMPONENTS` names from the request side.
|
|
77
|
+
*/
|
|
78
|
+
export const BUNDLE_ALLOCATION_RULE_CODE = {
|
|
79
|
+
REFERENCE_TOTAL_ZERO: "MIN_COMPONENTS",
|
|
80
|
+
TARGET_ABOVE_COMPONENT_SUM: "TARGET_ABOVE_COMPONENT_SUM",
|
|
81
|
+
TARGET_BELOW_FLOOR: "TARGET_BELOW_FLOOR",
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Which rules are decidable from the request alone (pure, pre-flight) and which
|
|
85
|
+
* are state-dependent and authoritatively enforced by the write routine. This
|
|
86
|
+
* documents intent and keeps the handler honest about what it can decide before
|
|
87
|
+
* the write. `CONSTRAINT_VALIDATION_FAILED` is `port`: it is decided by the
|
|
88
|
+
* injected `CompositionRulesPort`, which is neither the request nor the database.
|
|
89
|
+
*/
|
|
90
|
+
export const BUNDLE_RULE_ENFORCEMENT = {
|
|
91
|
+
DRAFT_ONLY_FOR_MACHINE: "request",
|
|
92
|
+
MIN_COMPONENTS: "request",
|
|
93
|
+
ADDON_ONLY_COMPOSITION: "request",
|
|
94
|
+
DUPLICATE_COMPONENT: "request",
|
|
95
|
+
FULFILLMENT_MODE_UNSUPPORTED: "request",
|
|
96
|
+
CONSTRAINT_VALIDATION_FAILED: "port",
|
|
97
|
+
CODE_TAKEN: "rpc",
|
|
98
|
+
COMPONENT_NOT_FOUND: "rpc",
|
|
99
|
+
COMPONENT_NOT_SELLABLE: "rpc",
|
|
100
|
+
COMPONENT_CURRENCY_MISMATCH: "rpc",
|
|
101
|
+
TARGET_ABOVE_COMPONENT_SUM: "rpc",
|
|
102
|
+
TARGET_BELOW_FLOOR: "rpc",
|
|
103
|
+
PRICE_REQUIRED_TO_SELL: "rpc",
|
|
104
|
+
COMPOSITION_REQUIRED_TO_SELL: "rpc",
|
|
105
|
+
APPEND_ONLY_PRICE: "rpc",
|
|
106
|
+
NO_HARD_DELETE: "rpc",
|
|
107
|
+
RESTORE_REQUIRES_ARCHIVED: "rpc",
|
|
108
|
+
DEACTIVATE_REQUIRES_ACTIVE: "rpc",
|
|
109
|
+
CLONE_SOURCE_NOT_FOUND: "rpc",
|
|
110
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { BundleComponentInput } from "@openlup/core/pricing";
|
|
2
|
+
import type { CompositionConstraint, CompositionRulesPort } from "@openlup/core/bundle";
|
|
3
|
+
import type { BundleRuleBindings } from "./bundleBindings.js";
|
|
4
|
+
import { type BundleActorKind, type BundleRuleResult } from "./bundleRuleCodes.js";
|
|
5
|
+
/**
|
|
6
|
+
* Pure, request-checkable bundle write rules.
|
|
7
|
+
*
|
|
8
|
+
* Only what is decidable from the request alone lives here. The state-dependent
|
|
9
|
+
* rules (code uniqueness, component existence/sellability/currency, the target
|
|
10
|
+
* price against real component prices, the activation preconditions, append-only
|
|
11
|
+
* pricing, archive-not-delete) are re-derived by the managed write routines.
|
|
12
|
+
* This layer fast-fails request-checkable violations without replacing those
|
|
13
|
+
* state checks. Actor-kind enforcement is separate: managed publication routines
|
|
14
|
+
* independently check it, while native publication relies on the handler gate.
|
|
15
|
+
*/
|
|
16
|
+
/** The composition shape the request-layer rules can reason about. */
|
|
17
|
+
export interface BundleCompositionEntry {
|
|
18
|
+
readonly sku: string;
|
|
19
|
+
readonly quantity: number;
|
|
20
|
+
readonly isAddon: boolean;
|
|
21
|
+
}
|
|
22
|
+
/** The only fulfillment mode with a runtime. The column admits more; this does not. */
|
|
23
|
+
export declare const SUPPORTED_BUNDLE_FULFILLMENT_MODES: readonly ["virtual"];
|
|
24
|
+
export type SupportedBundleFulfillmentMode = (typeof SUPPORTED_BUNDLE_FULFILLMENT_MODES)[number];
|
|
25
|
+
/**
|
|
26
|
+
* The lifecycle/actor gate every operation passes. Machine actors are confined to
|
|
27
|
+
* drafts: they may compose, price, archive, restore and clone, but neither
|
|
28
|
+
* activate nor deactivate.
|
|
29
|
+
*/
|
|
30
|
+
export declare function createBundleWriteRules({ assertActivateNotMachineActor }: Pick<BundleRuleBindings, "assertActivateNotMachineActor">): {
|
|
31
|
+
evaluateBundleWriteRules: (input: {
|
|
32
|
+
operation: string;
|
|
33
|
+
actorKind: BundleActorKind;
|
|
34
|
+
}) => BundleRuleResult;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Whole-set composition rules, decidable from the replacement set alone: it must
|
|
38
|
+
* carry at least one entry, at least one entry that is not an add-on, and no unit
|
|
39
|
+
* twice (multiplicity is the quantity, never a repeated row).
|
|
40
|
+
*/
|
|
41
|
+
export declare function evaluateBundleComposition(components: readonly BundleCompositionEntry[]): BundleRuleResult;
|
|
42
|
+
/** The runtime refusal of every fulfillment mode the stored column admits but no code honours. */
|
|
43
|
+
export declare function evaluateBundleFulfillmentMode(mode: string): BundleRuleResult;
|
|
44
|
+
/**
|
|
45
|
+
* Project the kernel allocator's decision onto this domain's rule vocabulary.
|
|
46
|
+
*
|
|
47
|
+
* The allocator (`@openlup/core/pricing`) owns the arithmetic and the two
|
|
48
|
+
* refusals a target price can earn; this maps its failure code through the
|
|
49
|
+
* exhaustive `BUNDLE_ALLOCATION_RULE_CODE` table so the codes cannot drift apart.
|
|
50
|
+
* It is pure: the caller supplies the component reference prices it already holds.
|
|
51
|
+
* The authority for a committed write remains the write routine, which holds the
|
|
52
|
+
* live prices.
|
|
53
|
+
*/
|
|
54
|
+
export declare function evaluateBundleTargetPrice(input: {
|
|
55
|
+
components: readonly BundleComponentInput[];
|
|
56
|
+
targetPriceMinor: number;
|
|
57
|
+
minimumUnitPayableMinor?: number;
|
|
58
|
+
}): BundleRuleResult;
|
|
59
|
+
/** An empty envelope means "unconstrained"; there is nothing for the port to decide. */
|
|
60
|
+
export declare function isEmptyCompositionConstraint(constraint: CompositionConstraint | null | undefined): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Delegate a non-empty composition constraint to the injected rules port. The
|
|
63
|
+
* platform stores the envelope and never interprets it, so this domain does not
|
|
64
|
+
* either: it asks the adopter's port and reports the refusal under one code.
|
|
65
|
+
*/
|
|
66
|
+
export declare function evaluateBundleCompositionConstraint(port: CompositionRulesPort | undefined, input: {
|
|
67
|
+
readonly components: readonly BundleCompositionEntry[];
|
|
68
|
+
readonly constraint: CompositionConstraint | null | undefined;
|
|
69
|
+
}): Promise<BundleRuleResult>;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { allocateBundleTargetPrice } from "@openlup/core/pricing";
|
|
2
|
+
import { BUNDLE_ALLOCATION_RULE_CODE, } from "./bundleRuleCodes.js";
|
|
3
|
+
/** The only fulfillment mode with a runtime. The column admits more; this does not. */
|
|
4
|
+
export const SUPPORTED_BUNDLE_FULFILLMENT_MODES = ["virtual"];
|
|
5
|
+
function isSupportedFulfillmentMode(mode) {
|
|
6
|
+
return SUPPORTED_BUNDLE_FULFILLMENT_MODES.includes(mode);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The lifecycle/actor gate every operation passes. Machine actors are confined to
|
|
10
|
+
* drafts: they may compose, price, archive, restore and clone, but neither
|
|
11
|
+
* activate nor deactivate.
|
|
12
|
+
*/
|
|
13
|
+
export function createBundleWriteRules({ assertActivateNotMachineActor }) {
|
|
14
|
+
function evaluateBundleWriteRules(input) {
|
|
15
|
+
const violations = [];
|
|
16
|
+
const activateViolation = assertActivateNotMachineActor(input);
|
|
17
|
+
if (activateViolation)
|
|
18
|
+
violations.push(activateViolation);
|
|
19
|
+
// `assertActivateNotMachineActor` only knows the publish direction it was written
|
|
20
|
+
// for. Unpublish is the same class of transition and carries the same code.
|
|
21
|
+
if (input.operation === "deactivate" && input.actorKind === "machine") {
|
|
22
|
+
violations.push("DRAFT_ONLY_FOR_MACHINE");
|
|
23
|
+
}
|
|
24
|
+
return { ok: violations.length === 0, violations };
|
|
25
|
+
}
|
|
26
|
+
return { evaluateBundleWriteRules };
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Whole-set composition rules, decidable from the replacement set alone: it must
|
|
30
|
+
* carry at least one entry, at least one entry that is not an add-on, and no unit
|
|
31
|
+
* twice (multiplicity is the quantity, never a repeated row).
|
|
32
|
+
*/
|
|
33
|
+
export function evaluateBundleComposition(components) {
|
|
34
|
+
const violations = [];
|
|
35
|
+
if (components.length === 0)
|
|
36
|
+
violations.push("MIN_COMPONENTS");
|
|
37
|
+
else if (components.every((component) => component.isAddon))
|
|
38
|
+
violations.push("ADDON_ONLY_COMPOSITION");
|
|
39
|
+
const seen = new Set();
|
|
40
|
+
for (const component of components) {
|
|
41
|
+
if (seen.has(component.sku)) {
|
|
42
|
+
violations.push("DUPLICATE_COMPONENT");
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
seen.add(component.sku);
|
|
46
|
+
}
|
|
47
|
+
return { ok: violations.length === 0, violations };
|
|
48
|
+
}
|
|
49
|
+
/** The runtime refusal of every fulfillment mode the stored column admits but no code honours. */
|
|
50
|
+
export function evaluateBundleFulfillmentMode(mode) {
|
|
51
|
+
return isSupportedFulfillmentMode(mode)
|
|
52
|
+
? { ok: true, violations: [] }
|
|
53
|
+
: { ok: false, violations: ["FULFILLMENT_MODE_UNSUPPORTED"] };
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Project the kernel allocator's decision onto this domain's rule vocabulary.
|
|
57
|
+
*
|
|
58
|
+
* The allocator (`@openlup/core/pricing`) owns the arithmetic and the two
|
|
59
|
+
* refusals a target price can earn; this maps its failure code through the
|
|
60
|
+
* exhaustive `BUNDLE_ALLOCATION_RULE_CODE` table so the codes cannot drift apart.
|
|
61
|
+
* It is pure: the caller supplies the component reference prices it already holds.
|
|
62
|
+
* The authority for a committed write remains the write routine, which holds the
|
|
63
|
+
* live prices.
|
|
64
|
+
*/
|
|
65
|
+
export function evaluateBundleTargetPrice(input) {
|
|
66
|
+
const outcome = allocateBundleTargetPrice({
|
|
67
|
+
components: input.components,
|
|
68
|
+
targetPriceMinor: input.targetPriceMinor,
|
|
69
|
+
...(input.minimumUnitPayableMinor === undefined
|
|
70
|
+
? {}
|
|
71
|
+
: { minimumUnitPayableMinor: input.minimumUnitPayableMinor }),
|
|
72
|
+
});
|
|
73
|
+
// Narrowed by presence rather than by the `ok` literal: the app compiler runs
|
|
74
|
+
// without strictNullChecks, where a boolean-literal discriminant does not narrow.
|
|
75
|
+
if (!("code" in outcome))
|
|
76
|
+
return { ok: true, violations: [] };
|
|
77
|
+
return { ok: false, violations: [BUNDLE_ALLOCATION_RULE_CODE[outcome.code]] };
|
|
78
|
+
}
|
|
79
|
+
/** An empty envelope means "unconstrained"; there is nothing for the port to decide. */
|
|
80
|
+
export function isEmptyCompositionConstraint(constraint) {
|
|
81
|
+
return !constraint || constraint.kind.trim() === "";
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Delegate a non-empty composition constraint to the injected rules port. The
|
|
85
|
+
* platform stores the envelope and never interprets it, so this domain does not
|
|
86
|
+
* either: it asks the adopter's port and reports the refusal under one code.
|
|
87
|
+
*/
|
|
88
|
+
export async function evaluateBundleCompositionConstraint(port, input) {
|
|
89
|
+
if (isEmptyCompositionConstraint(input.constraint) || !port)
|
|
90
|
+
return { ok: true, violations: [] };
|
|
91
|
+
const constraint = input.constraint;
|
|
92
|
+
const outcome = await port.validateComposition({
|
|
93
|
+
coreLines: input.components
|
|
94
|
+
.filter((component) => !component.isAddon)
|
|
95
|
+
.map((component) => ({ variantId: component.sku, qty: component.quantity, isAddon: false })),
|
|
96
|
+
addonLines: input.components
|
|
97
|
+
.filter((component) => component.isAddon)
|
|
98
|
+
.map((component) => ({ variantId: component.sku, qty: component.quantity, isAddon: true })),
|
|
99
|
+
constraint,
|
|
100
|
+
});
|
|
101
|
+
return outcome.ok ? { ok: true, violations: [] } : { ok: false, violations: ["CONSTRAINT_VALIDATION_FAILED"] };
|
|
102
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type CatalogDraftStorePort } from "./draftPorts.js";
|
|
2
|
+
import type { PgQueryExecutor } from "../data/index.js";
|
|
3
|
+
/** Dark owner-only storage. Composition must verify the operator before use. */
|
|
4
|
+
export declare function createPostgresCatalogDraftStore(client: PgQueryExecutor): CatalogDraftStorePort;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { catalogDraftApplyResultSchema, catalogDraftGetQuerySchema, catalogDraftListQuerySchema, catalogDraftPageSchema, catalogDraftRecordSchema, } from "./draftSchemas.js";
|
|
2
|
+
import { CatalogDraftStoreError } from "./draftPorts.js";
|
|
3
|
+
/** Dark owner-only storage. Composition must verify the operator before use. */
|
|
4
|
+
export function createPostgresCatalogDraftStore(client) {
|
|
5
|
+
async function call(sql, values) {
|
|
6
|
+
try {
|
|
7
|
+
const { rows } = await client.query(sql, values);
|
|
8
|
+
if (rows.length !== 1 || !("result" in rows[0])) {
|
|
9
|
+
throw new CatalogDraftStoreError({ outcome: "dependency_unavailable", reason: "invalid_store_response" });
|
|
10
|
+
}
|
|
11
|
+
return rows[0].result;
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
if (error instanceof CatalogDraftStoreError)
|
|
15
|
+
throw error;
|
|
16
|
+
throw new CatalogDraftStoreError(refusal(error));
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
async apply(request) {
|
|
21
|
+
try {
|
|
22
|
+
const result = await call("SELECT public.catalog_draft_apply($1::text, $2::text, $3::text) AS result", [request.canonicalCommand, request.fingerprint, request.actorId]);
|
|
23
|
+
const parsed = catalogDraftApplyResultSchema.safeParse(result);
|
|
24
|
+
if (!parsed.success)
|
|
25
|
+
return { outcome: "dependency_unavailable", reason: "invalid_store_response" };
|
|
26
|
+
return parsed.data;
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
return error instanceof CatalogDraftStoreError ? error.refusal : refusal(error);
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
async get(query) {
|
|
33
|
+
const input = catalogDraftGetQuerySchema.safeParse(query);
|
|
34
|
+
if (!input.success)
|
|
35
|
+
throw new CatalogDraftStoreError({ outcome: "validation_issue", reason: "invalid_get_query" });
|
|
36
|
+
const result = await call("SELECT public.catalog_draft_get($1::uuid, $2::integer, $3::text) AS result", [input.data.draftId, input.data.revision ?? null, input.data.commandKey ?? null]);
|
|
37
|
+
const parsed = catalogDraftRecordSchema.nullable().safeParse(result);
|
|
38
|
+
if (!parsed.success)
|
|
39
|
+
throw new CatalogDraftStoreError({ outcome: "dependency_unavailable", reason: "invalid_store_response" });
|
|
40
|
+
return parsed.data;
|
|
41
|
+
},
|
|
42
|
+
async list(query) {
|
|
43
|
+
const input = catalogDraftListQuerySchema.safeParse(query);
|
|
44
|
+
if (!input.success)
|
|
45
|
+
throw new CatalogDraftStoreError({ outcome: "validation_issue", reason: "invalid_list_query" });
|
|
46
|
+
const result = await call("SELECT public.catalog_draft_list($1::uuid, $2::integer) AS result", [input.data.afterDraftId ?? null, input.data.limit]);
|
|
47
|
+
const parsed = catalogDraftPageSchema.safeParse(result);
|
|
48
|
+
if (!parsed.success)
|
|
49
|
+
throw new CatalogDraftStoreError({ outcome: "dependency_unavailable", reason: "invalid_store_response" });
|
|
50
|
+
return parsed.data;
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function refusal(error) {
|
|
55
|
+
const code = error && typeof error === "object" && "code" in error ? error.code : null;
|
|
56
|
+
if (code === "42501")
|
|
57
|
+
return { outcome: "unauthorized", reason: "operator_required" };
|
|
58
|
+
if (code === "22023")
|
|
59
|
+
return { outcome: "validation_issue", reason: "invalid_store_request" };
|
|
60
|
+
if (code === "23505")
|
|
61
|
+
return { outcome: "conflict", reason: "identity_reserved" };
|
|
62
|
+
return { outcome: "dependency_unavailable", reason: "store_unavailable" };
|
|
63
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { PublicCatalogSkuEnvelopeReadPort } from "./readPorts.js";
|
|
2
|
+
import type { PgQueryExecutor } from "../data/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Portable W2a envelope reader. It reads only product/SKU/revision references
|
|
5
|
+
* and neutral identifiers; application document content never crosses this seam.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createPostgresCatalogSkuEnvelopeReadPort(executor: PgQueryExecutor): PublicCatalogSkuEnvelopeReadPort;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { CatalogSkuAuthorityError, catalogSkuEnvelopeSelectorSchema, } from "./foundationSchemas.js";
|
|
2
|
+
import { parseCatalogActiveSkuSelection } from "./activeSkuSelection.js";
|
|
3
|
+
import { mapPostgresCatalogSkuEnvelope, readPostgresCatalogSkuIdentifiers, requirePostgresCatalogSkuEnvelopeRow, } from "./catalogSkuEnvelopeMapper.js";
|
|
4
|
+
const ENVELOPE_COLUMNS_SQL = `
|
|
5
|
+
product.id AS product_id,
|
|
6
|
+
product.slug AS product_slug,
|
|
7
|
+
product.primary_sku_id,
|
|
8
|
+
product.current_document_revision_id,
|
|
9
|
+
sku.id AS sku_id,
|
|
10
|
+
sku.product_id AS sku_product_id,
|
|
11
|
+
sku.sku AS sku_code,
|
|
12
|
+
sku.net_weight_g AS net_content_unscaled,
|
|
13
|
+
sku.status AS sku_status,
|
|
14
|
+
sku.sellable_standalone AS sellable_one_time,
|
|
15
|
+
sku.sellable_in_subscription AS sellable_subscription,
|
|
16
|
+
sku.is_addon,
|
|
17
|
+
sku.asset_ref,
|
|
18
|
+
revision.id AS document_revision_id,
|
|
19
|
+
revision.product_id AS document_product_id,
|
|
20
|
+
revision.revision_no AS document_revision_no,
|
|
21
|
+
revision.schema_id AS document_schema_id,
|
|
22
|
+
revision.document_ref AS document_ref,
|
|
23
|
+
revision.source_ref AS document_source_ref,
|
|
24
|
+
revision.digest AS document_digest`;
|
|
25
|
+
const SKU_ENVELOPE_FROM_SQL = `
|
|
26
|
+
SELECT ${ENVELOPE_COLUMNS_SQL}
|
|
27
|
+
FROM public.catalog_skus AS sku
|
|
28
|
+
JOIN public.catalog_products AS product
|
|
29
|
+
ON product.id = sku.product_id
|
|
30
|
+
LEFT JOIN public.catalog_product_document_revisions AS revision
|
|
31
|
+
ON revision.id = product.current_document_revision_id`;
|
|
32
|
+
const LIST_ENVELOPES_SQL = `${SKU_ENVELOPE_FROM_SQL}
|
|
33
|
+
WHERE ($1::uuid IS NULL OR sku.id > $1::uuid)
|
|
34
|
+
ORDER BY sku.id
|
|
35
|
+
LIMIT $2::integer`;
|
|
36
|
+
const LIST_ACTIVE_ENVELOPES_SQL = `${SKU_ENVELOPE_FROM_SQL}
|
|
37
|
+
WHERE sku.status = 'active'
|
|
38
|
+
AND (sku.sellable_standalone OR sku.sellable_in_subscription)
|
|
39
|
+
AND ($3::text[] IS NULL OR sku.sku = ANY($3::text[]))
|
|
40
|
+
AND ($1::uuid IS NULL OR sku.id > $1::uuid)
|
|
41
|
+
ORDER BY sku.id
|
|
42
|
+
LIMIT $2::integer`;
|
|
43
|
+
const LIST_PUBLIC_ACTIVE_ENVELOPES_SQL = `${SKU_ENVELOPE_FROM_SQL}
|
|
44
|
+
WHERE sku.status = 'active'
|
|
45
|
+
AND ($1::uuid IS NULL OR sku.id > $1::uuid)
|
|
46
|
+
ORDER BY sku.id
|
|
47
|
+
LIMIT $2::integer`;
|
|
48
|
+
const LIST_PUBLIC_ACTIVE_PRODUCT_ENVELOPES_SQL = `${SKU_ENVELOPE_FROM_SQL}
|
|
49
|
+
WHERE sku.product_id = $1::uuid
|
|
50
|
+
AND sku.status = 'active'
|
|
51
|
+
AND ($2::uuid IS NULL OR sku.id > $2::uuid)
|
|
52
|
+
ORDER BY sku.id
|
|
53
|
+
LIMIT $3::integer`;
|
|
54
|
+
const DETAIL_ENVELOPE_BY_ID_SQL = `${SKU_ENVELOPE_FROM_SQL}
|
|
55
|
+
WHERE sku.id = $1::uuid`;
|
|
56
|
+
const DETAIL_ENVELOPE_BY_SKU_CODE_SQL = `${SKU_ENVELOPE_FROM_SQL}
|
|
57
|
+
WHERE sku.sku = $1
|
|
58
|
+
LIMIT 2`;
|
|
59
|
+
const DETAIL_ENVELOPE_BY_PRIMARY_PRODUCT_SLUG_SQL = `
|
|
60
|
+
SELECT ${ENVELOPE_COLUMNS_SQL}
|
|
61
|
+
FROM public.catalog_products AS product
|
|
62
|
+
LEFT JOIN public.catalog_skus AS sku
|
|
63
|
+
ON sku.id = product.primary_sku_id
|
|
64
|
+
LEFT JOIN public.catalog_product_document_revisions AS revision
|
|
65
|
+
ON revision.id = product.current_document_revision_id
|
|
66
|
+
WHERE product.slug = $1
|
|
67
|
+
LIMIT 2`;
|
|
68
|
+
/**
|
|
69
|
+
* Portable W2a envelope reader. It reads only product/SKU/revision references
|
|
70
|
+
* and neutral identifiers; application document content never crosses this seam.
|
|
71
|
+
*/
|
|
72
|
+
export function createPostgresCatalogSkuEnvelopeReadPort(executor) {
|
|
73
|
+
return {
|
|
74
|
+
async listSkuEnvelopes(query) {
|
|
75
|
+
return listEnvelopes(executor, query, LIST_ENVELOPES_SQL);
|
|
76
|
+
},
|
|
77
|
+
async listActiveSkuEnvelopes(query) {
|
|
78
|
+
const skuCodes = parseCatalogActiveSkuSelection(query.skuCodes);
|
|
79
|
+
return listEnvelopes(executor, query, LIST_ACTIVE_ENVELOPES_SQL, [], [skuCodes ?? null]);
|
|
80
|
+
},
|
|
81
|
+
async listPublicActiveSkuEnvelopes(query) {
|
|
82
|
+
return listEnvelopes(executor, query, LIST_PUBLIC_ACTIVE_ENVELOPES_SQL);
|
|
83
|
+
},
|
|
84
|
+
async listPublicActiveProductSkuEnvelopes(productId, query) {
|
|
85
|
+
return listEnvelopes(executor, query, LIST_PUBLIC_ACTIVE_PRODUCT_ENVELOPES_SQL, [productId]);
|
|
86
|
+
},
|
|
87
|
+
async getSkuEnvelope(selector) {
|
|
88
|
+
const parsed = catalogSkuEnvelopeSelectorSchema.parse(selector);
|
|
89
|
+
const rows = await readRows(executor, parsed.kind === "sku_code"
|
|
90
|
+
? DETAIL_ENVELOPE_BY_SKU_CODE_SQL
|
|
91
|
+
: DETAIL_ENVELOPE_BY_PRIMARY_PRODUCT_SLUG_SQL, [parsed.kind === "sku_code" ? parsed.skuCode : parsed.productSlug]);
|
|
92
|
+
const row = uniqueDetailRow(rows, parsed.kind === "sku_code"
|
|
93
|
+
? "catalog_sku_authority_sku_absent"
|
|
94
|
+
: "catalog_sku_authority_product_absent");
|
|
95
|
+
requirePostgresCatalogSkuEnvelopeRow(row, parsed.kind === "primary_product_slug"
|
|
96
|
+
? "catalog_sku_authority_primary_sku_invalid"
|
|
97
|
+
: "catalog_sku_authority_current_document_invalid");
|
|
98
|
+
if (parsed.kind === "primary_product_slug"
|
|
99
|
+
&& (row.primary_sku_id !== row.sku_id || row.product_id !== row.sku_product_id)) {
|
|
100
|
+
throw new CatalogSkuAuthorityError("catalog_sku_authority_primary_sku_invalid");
|
|
101
|
+
}
|
|
102
|
+
const identifiers = await readPostgresCatalogSkuIdentifiers(executor, [row.sku_id]);
|
|
103
|
+
return mapPostgresCatalogSkuEnvelope(row, identifiers.get(row.sku_id) ?? []);
|
|
104
|
+
},
|
|
105
|
+
async getSkuEnvelopeById(skuId) {
|
|
106
|
+
const row = uniqueDetailRow(await readRows(executor, DETAIL_ENVELOPE_BY_ID_SQL, [skuId]), "catalog_sku_authority_sku_absent");
|
|
107
|
+
requirePostgresCatalogSkuEnvelopeRow(row, "catalog_sku_authority_current_document_invalid");
|
|
108
|
+
const identifiers = await readPostgresCatalogSkuIdentifiers(executor, [row.sku_id]);
|
|
109
|
+
return mapPostgresCatalogSkuEnvelope(row, identifiers.get(row.sku_id) ?? []);
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
async function listEnvelopes(executor, query, sql, prefixValues = [], suffixValues = []) {
|
|
114
|
+
const rows = await readRows(executor, sql, [...prefixValues, query.cursor, checkedLimit(query.limit) + 1, ...suffixValues]);
|
|
115
|
+
const pageRows = rows.slice(0, query.limit).map((row) => {
|
|
116
|
+
requirePostgresCatalogSkuEnvelopeRow(row, "catalog_sku_authority_current_document_invalid");
|
|
117
|
+
return row;
|
|
118
|
+
});
|
|
119
|
+
const identifiers = await readPostgresCatalogSkuIdentifiers(executor, pageRows.map((row) => row.sku_id));
|
|
120
|
+
return {
|
|
121
|
+
items: pageRows.map((row) => mapPostgresCatalogSkuEnvelope(row, identifiers.get(row.sku_id) ?? [])),
|
|
122
|
+
nextCursor: rows.length > query.limit ? pageRows[pageRows.length - 1]?.sku_id ?? null : null,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
function uniqueDetailRow(rows, absent) {
|
|
126
|
+
if (rows.length === 0)
|
|
127
|
+
throw new CatalogSkuAuthorityError(absent);
|
|
128
|
+
if (rows.length !== 1) {
|
|
129
|
+
throw new CatalogSkuAuthorityError("catalog_sku_authority_selector_ambiguous");
|
|
130
|
+
}
|
|
131
|
+
return rows[0];
|
|
132
|
+
}
|
|
133
|
+
async function readRows(executor, sql, values) {
|
|
134
|
+
const { rows } = await executor.query(sql, values);
|
|
135
|
+
return rows;
|
|
136
|
+
}
|
|
137
|
+
function checkedLimit(limit) {
|
|
138
|
+
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 500) {
|
|
139
|
+
throw new RangeError("catalog_sku_envelope_invalid_limit");
|
|
140
|
+
}
|
|
141
|
+
return limit;
|
|
142
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { CatalogSkuAuthorityError, type CatalogSkuIdentifier, type NeutralSkuEnvelopeV1 } from "./foundationSchemas.js";
|
|
2
|
+
import type { PgQueryExecutor } from "../data/index.js";
|
|
3
|
+
export interface PostgresCatalogSkuEnvelopeRow {
|
|
4
|
+
product_id: string;
|
|
5
|
+
product_slug: string;
|
|
6
|
+
primary_sku_id: string | null;
|
|
7
|
+
current_document_revision_id: string | null;
|
|
8
|
+
sku_id: string | null;
|
|
9
|
+
sku_product_id: string | null;
|
|
10
|
+
sku_code: string | null;
|
|
11
|
+
net_content_unscaled: number | null;
|
|
12
|
+
sku_status: "draft" | "active" | "archived" | null;
|
|
13
|
+
sellable_one_time: boolean | null;
|
|
14
|
+
sellable_subscription: boolean | null;
|
|
15
|
+
is_addon: boolean | null;
|
|
16
|
+
asset_ref: string | null;
|
|
17
|
+
document_revision_id: string | null;
|
|
18
|
+
document_product_id: string | null;
|
|
19
|
+
document_revision_no: number | null;
|
|
20
|
+
document_schema_id: string | null;
|
|
21
|
+
document_ref: string | null;
|
|
22
|
+
document_source_ref: string | null;
|
|
23
|
+
document_digest: string | null;
|
|
24
|
+
}
|
|
25
|
+
export type CompletePostgresCatalogSkuEnvelopeRow = PostgresCatalogSkuEnvelopeRow & {
|
|
26
|
+
primary_sku_id: string;
|
|
27
|
+
sku_id: string;
|
|
28
|
+
sku_product_id: string;
|
|
29
|
+
sku_code: string;
|
|
30
|
+
net_content_unscaled: number;
|
|
31
|
+
sku_status: "draft" | "active" | "archived";
|
|
32
|
+
sellable_one_time: boolean;
|
|
33
|
+
sellable_subscription: boolean;
|
|
34
|
+
is_addon: boolean;
|
|
35
|
+
};
|
|
36
|
+
export declare function requirePostgresCatalogSkuEnvelopeRow(row: PostgresCatalogSkuEnvelopeRow, refusal: CatalogSkuAuthorityError["code"]): asserts row is CompletePostgresCatalogSkuEnvelopeRow;
|
|
37
|
+
export declare function readPostgresCatalogSkuIdentifiers(executor: PgQueryExecutor, skuIds: string[]): Promise<Map<string, CatalogSkuIdentifier[]>>;
|
|
38
|
+
export declare function mapPostgresCatalogSkuEnvelope(row: CompletePostgresCatalogSkuEnvelopeRow, identifiers: CatalogSkuIdentifier[]): NeutralSkuEnvelopeV1;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { CATALOG_FOUNDATION_CONTRACT_VERSION, CatalogSkuAuthorityError, assertPrimaryUnitGtinAuthority, neutralSkuEnvelopeV1Schema, requireCurrentCatalogDocumentAuthority, } from "./foundationSchemas.js";
|
|
2
|
+
const IDENTIFIERS_SQL = `
|
|
3
|
+
SELECT catalog_sku_id, issuer, identifier_kind, normalized_value,
|
|
4
|
+
pack_kind, quantity, is_primary
|
|
5
|
+
FROM public.catalog_sku_identifiers
|
|
6
|
+
WHERE catalog_sku_id = ANY($1::uuid[])
|
|
7
|
+
ORDER BY catalog_sku_id, identifier_kind, is_primary DESC, issuer, normalized_value`;
|
|
8
|
+
export function requirePostgresCatalogSkuEnvelopeRow(row, refusal) {
|
|
9
|
+
if (!row.primary_sku_id) {
|
|
10
|
+
throw new CatalogSkuAuthorityError("catalog_sku_authority_primary_sku_invalid");
|
|
11
|
+
}
|
|
12
|
+
if (!row.sku_id
|
|
13
|
+
|| !row.sku_product_id
|
|
14
|
+
|| !row.sku_code
|
|
15
|
+
|| row.net_content_unscaled === null
|
|
16
|
+
|| row.sku_status === null
|
|
17
|
+
|| row.sellable_one_time === null
|
|
18
|
+
|| row.sellable_subscription === null
|
|
19
|
+
|| row.is_addon === null) {
|
|
20
|
+
throw new CatalogSkuAuthorityError(refusal);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export async function readPostgresCatalogSkuIdentifiers(executor, skuIds) {
|
|
24
|
+
if (skuIds.length === 0)
|
|
25
|
+
return new Map();
|
|
26
|
+
const { rows } = await executor.query(IDENTIFIERS_SQL, [skuIds]);
|
|
27
|
+
const grouped = new Map();
|
|
28
|
+
for (const row of rows) {
|
|
29
|
+
const identifiers = grouped.get(row.catalog_sku_id) ?? [];
|
|
30
|
+
identifiers.push({
|
|
31
|
+
issuer: row.issuer,
|
|
32
|
+
normalizedValue: row.normalized_value,
|
|
33
|
+
kind: row.identifier_kind,
|
|
34
|
+
packKind: row.pack_kind,
|
|
35
|
+
packQuantity: row.quantity,
|
|
36
|
+
isPrimary: row.is_primary,
|
|
37
|
+
});
|
|
38
|
+
grouped.set(row.catalog_sku_id, identifiers);
|
|
39
|
+
}
|
|
40
|
+
return grouped;
|
|
41
|
+
}
|
|
42
|
+
export function mapPostgresCatalogSkuEnvelope(row, identifiers) {
|
|
43
|
+
assertPrimaryUnitGtinAuthority(identifiers);
|
|
44
|
+
const revision = requireCurrentCatalogDocumentAuthority(row.product_id, row.current_document_revision_id, row.document_revision_id
|
|
45
|
+
&& row.document_product_id
|
|
46
|
+
&& row.document_revision_no !== null
|
|
47
|
+
&& row.document_schema_id
|
|
48
|
+
&& row.document_ref
|
|
49
|
+
&& row.document_source_ref
|
|
50
|
+
&& row.document_digest
|
|
51
|
+
? {
|
|
52
|
+
id: row.document_revision_id,
|
|
53
|
+
productId: row.document_product_id,
|
|
54
|
+
revisionNo: row.document_revision_no,
|
|
55
|
+
schemaId: row.document_schema_id,
|
|
56
|
+
documentRef: row.document_ref,
|
|
57
|
+
sourceRef: row.document_source_ref,
|
|
58
|
+
digest: row.document_digest,
|
|
59
|
+
}
|
|
60
|
+
: null);
|
|
61
|
+
return neutralSkuEnvelopeV1Schema.parse({
|
|
62
|
+
contractVersion: CATALOG_FOUNDATION_CONTRACT_VERSION,
|
|
63
|
+
product: { id: row.product_id, slug: row.product_slug, primarySkuId: row.primary_sku_id },
|
|
64
|
+
sku: {
|
|
65
|
+
id: row.sku_id,
|
|
66
|
+
productId: row.sku_product_id,
|
|
67
|
+
code: row.sku_code,
|
|
68
|
+
netContent: { unscaled: row.net_content_unscaled, scale: 0, unit: "GRAM" },
|
|
69
|
+
sellability: {
|
|
70
|
+
status: row.sku_status,
|
|
71
|
+
oneTime: row.sellable_one_time,
|
|
72
|
+
subscription: row.sellable_subscription,
|
|
73
|
+
},
|
|
74
|
+
isAddon: row.is_addon,
|
|
75
|
+
assetRef: row.asset_ref,
|
|
76
|
+
},
|
|
77
|
+
documentRevision: {
|
|
78
|
+
id: revision.id,
|
|
79
|
+
productId: revision.productId,
|
|
80
|
+
revisionNo: revision.revisionNo,
|
|
81
|
+
schemaId: revision.schemaId,
|
|
82
|
+
documentRef: revision.documentRef,
|
|
83
|
+
sourceRef: revision.sourceRef,
|
|
84
|
+
digest: revision.digest,
|
|
85
|
+
},
|
|
86
|
+
identifiers,
|
|
87
|
+
});
|
|
88
|
+
}
|