@dainamite/cpq 0.2.2
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 +70 -0
- package/LICENSE +21 -0
- package/MIGRATION.md +236 -0
- package/README.md +108 -0
- package/dist/modules/cpq/acl.js +30 -0
- package/dist/modules/cpq/acl.js.map +7 -0
- package/dist/modules/cpq/api/_helpers/handleArcError.js +37 -0
- package/dist/modules/cpq/api/_helpers/handleArcError.js.map +7 -0
- package/dist/modules/cpq/api/attribute-options/route.js +47 -0
- package/dist/modules/cpq/api/attribute-options/route.js.map +7 -0
- package/dist/modules/cpq/api/bundle-slots/route.js +101 -0
- package/dist/modules/cpq/api/bundle-slots/route.js.map +7 -0
- package/dist/modules/cpq/api/bundle-tree/route.js +28 -0
- package/dist/modules/cpq/api/bundle-tree/route.js.map +7 -0
- package/dist/modules/cpq/api/context.js +29 -0
- package/dist/modules/cpq/api/context.js.map +7 -0
- package/dist/modules/cpq/api/inventory/assets/route.js +113 -0
- package/dist/modules/cpq/api/inventory/assets/route.js.map +7 -0
- package/dist/modules/cpq/api/inventory/assets/status/route.js +35 -0
- package/dist/modules/cpq/api/inventory/assets/status/route.js.map +7 -0
- package/dist/modules/cpq/api/inventory/customer/[customerId]/parent-items/route.js +30 -0
- package/dist/modules/cpq/api/inventory/customer/[customerId]/parent-items/route.js.map +7 -0
- package/dist/modules/cpq/api/inventory/customer/[customerId]/route.js +31 -0
- package/dist/modules/cpq/api/inventory/customer/[customerId]/route.js.map +7 -0
- package/dist/modules/cpq/api/inventory/subscription-items/route.js +99 -0
- package/dist/modules/cpq/api/inventory/subscription-items/route.js.map +7 -0
- package/dist/modules/cpq/api/inventory/subscriptions/[subscriptionId]/change-log/route.js +57 -0
- package/dist/modules/cpq/api/inventory/subscriptions/[subscriptionId]/change-log/route.js.map +7 -0
- package/dist/modules/cpq/api/inventory/subscriptions/expiring/route.js +62 -0
- package/dist/modules/cpq/api/inventory/subscriptions/expiring/route.js.map +7 -0
- package/dist/modules/cpq/api/inventory/subscriptions/route.js +116 -0
- package/dist/modules/cpq/api/inventory/subscriptions/route.js.map +7 -0
- package/dist/modules/cpq/api/inventory/subscriptions/status/route.js +35 -0
- package/dist/modules/cpq/api/inventory/subscriptions/status/route.js.map +7 -0
- package/dist/modules/cpq/api/offering-components/route.js +91 -0
- package/dist/modules/cpq/api/offering-components/route.js.map +7 -0
- package/dist/modules/cpq/api/orders/[orderId]/activate/route.js +39 -0
- package/dist/modules/cpq/api/orders/[orderId]/activate/route.js.map +7 -0
- package/dist/modules/cpq/api/orders/[orderId]/route.js +28 -0
- package/dist/modules/cpq/api/orders/[orderId]/route.js.map +7 -0
- package/dist/modules/cpq/api/orders/[orderId]/status/route.js +38 -0
- package/dist/modules/cpq/api/orders/[orderId]/status/route.js.map +7 -0
- package/dist/modules/cpq/api/orders/route.js +71 -0
- package/dist/modules/cpq/api/orders/route.js.map +7 -0
- package/dist/modules/cpq/api/price-rules/route.js +180 -0
- package/dist/modules/cpq/api/price-rules/route.js.map +7 -0
- package/dist/modules/cpq/api/pricing-table-entries/route.js +142 -0
- package/dist/modules/cpq/api/pricing-table-entries/route.js.map +7 -0
- package/dist/modules/cpq/api/pricing-tables/route.js +179 -0
- package/dist/modules/cpq/api/pricing-tables/route.js.map +7 -0
- package/dist/modules/cpq/api/product-attributes/route.js +160 -0
- package/dist/modules/cpq/api/product-attributes/route.js.map +7 -0
- package/dist/modules/cpq/api/product-charges/route.js +166 -0
- package/dist/modules/cpq/api/product-charges/route.js.map +7 -0
- package/dist/modules/cpq/api/product-offerings/route.js +294 -0
- package/dist/modules/cpq/api/product-offerings/route.js.map +7 -0
- package/dist/modules/cpq/api/product-relationships/route.js +144 -0
- package/dist/modules/cpq/api/product-relationships/route.js.map +7 -0
- package/dist/modules/cpq/api/product-specifications/route.js +292 -0
- package/dist/modules/cpq/api/product-specifications/route.js.map +7 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/cancel-meta/route.js +71 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/cancel-meta/route.js.map +7 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/clone/route.js +29 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/clone/route.js.map +7 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/items/[lineId]/route.js +54 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/items/[lineId]/route.js.map +7 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/items/route.js +27 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/items/route.js.map +7 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/merge-meta/route.js +72 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/merge-meta/route.js.map +7 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/recalculate/route.js +35 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/recalculate/route.js.map +7 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/route.js +102 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/route.js.map +7 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/status/route.js +27 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/status/route.js.map +7 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/target-subscriptions/[targetId]/route.js +79 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/target-subscriptions/[targetId]/route.js.map +7 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/target-subscriptions/route.js +95 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/target-subscriptions/route.js.map +7 -0
- package/dist/modules/cpq/api/quotes/attributes/route.js +52 -0
- package/dist/modules/cpq/api/quotes/attributes/route.js.map +7 -0
- package/dist/modules/cpq/api/quotes/from-subscription/route.js +72 -0
- package/dist/modules/cpq/api/quotes/from-subscription/route.js.map +7 -0
- package/dist/modules/cpq/api/quotes/price/route.js +69 -0
- package/dist/modules/cpq/api/quotes/price/route.js.map +7 -0
- package/dist/modules/cpq/api/quotes/route.js +97 -0
- package/dist/modules/cpq/api/quotes/route.js.map +7 -0
- package/dist/modules/cpq/api/quotes/validate-relationships/route.js +86 -0
- package/dist/modules/cpq/api/quotes/validate-relationships/route.js.map +7 -0
- package/dist/modules/cpq/api/resolveQuotingService.js +7 -0
- package/dist/modules/cpq/api/resolveQuotingService.js.map +7 -0
- package/dist/modules/cpq/api/wizards/resolve/route.js +38 -0
- package/dist/modules/cpq/api/wizards/resolve/route.js.map +7 -0
- package/dist/modules/cpq/api/wizards/route.js +111 -0
- package/dist/modules/cpq/api/wizards/route.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/inventory/AssetsTable.js +136 -0
- package/dist/modules/cpq/backend/cpq/inventory/AssetsTable.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/inventory/SubscriptionsTable.js +185 -0
- package/dist/modules/cpq/backend/cpq/inventory/SubscriptionsTable.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.js +343 -0
- package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.meta.js +13 -0
- package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.meta.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/inventory/page.js +35 -0
- package/dist/modules/cpq/backend/cpq/inventory/page.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/inventory/page.meta.js +18 -0
- package/dist/modules/cpq/backend/cpq/inventory/page.meta.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/inventory/shared.js +20 -0
- package/dist/modules/cpq/backend/cpq/inventory/shared.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.js +794 -0
- package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.meta.js +13 -0
- package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.meta.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/offerings/[id]/page.js +917 -0
- package/dist/modules/cpq/backend/cpq/offerings/[id]/page.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/offerings/page.js +405 -0
- package/dist/modules/cpq/backend/cpq/offerings/page.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/offerings/page.meta.js +18 -0
- package/dist/modules/cpq/backend/cpq/offerings/page.meta.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/orders/[id]/page.js +677 -0
- package/dist/modules/cpq/backend/cpq/orders/[id]/page.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/orders/page.js +134 -0
- package/dist/modules/cpq/backend/cpq/orders/page.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/orders/page.meta.js +18 -0
- package/dist/modules/cpq/backend/cpq/orders/page.meta.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/price-rules/PriceRuleForm.js +272 -0
- package/dist/modules/cpq/backend/cpq/price-rules/PriceRuleForm.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.js +407 -0
- package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.meta.js +13 -0
- package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.meta.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/price-rules/page.js +211 -0
- package/dist/modules/cpq/backend/cpq/price-rules/page.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/price-rules/page.meta.js +18 -0
- package/dist/modules/cpq/backend/cpq/price-rules/page.meta.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/pricing/[id]/EntriesEditor.js +275 -0
- package/dist/modules/cpq/backend/cpq/pricing/[id]/EntriesEditor.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/pricing/[id]/ImportPreview.js +112 -0
- package/dist/modules/cpq/backend/cpq/pricing/[id]/ImportPreview.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/pricing/[id]/page.js +492 -0
- package/dist/modules/cpq/backend/cpq/pricing/[id]/page.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/pricing/[id]/xlsxExport.js +50 -0
- package/dist/modules/cpq/backend/cpq/pricing/[id]/xlsxExport.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/pricing/[id]/xlsxImport.js +249 -0
- package/dist/modules/cpq/backend/cpq/pricing/[id]/xlsxImport.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/pricing/page.js +87 -0
- package/dist/modules/cpq/backend/cpq/pricing/page.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/pricing/page.meta.js +18 -0
- package/dist/modules/cpq/backend/cpq/pricing/page.meta.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/ArcQuoteConfigurator.js +652 -0
- package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/ArcQuoteConfigurator.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/quotes/[id]/page.js +1289 -0
- package/dist/modules/cpq/backend/cpq/quotes/[id]/page.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/quotes/page.js +283 -0
- package/dist/modules/cpq/backend/cpq/quotes/page.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/quotes/page.meta.js +18 -0
- package/dist/modules/cpq/backend/cpq/quotes/page.meta.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/specifications/[id]/DependsOnRulesEditor.js +214 -0
- package/dist/modules/cpq/backend/cpq/specifications/[id]/DependsOnRulesEditor.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/specifications/[id]/page.js +1399 -0
- package/dist/modules/cpq/backend/cpq/specifications/[id]/page.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/specifications/page.js +148 -0
- package/dist/modules/cpq/backend/cpq/specifications/page.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/specifications/page.meta.js +18 -0
- package/dist/modules/cpq/backend/cpq/specifications/page.meta.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/detail/page.js +204 -0
- package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/detail/page.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/page.js +191 -0
- package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/page.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/wizards/page.js +119 -0
- package/dist/modules/cpq/backend/cpq/wizards/page.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/wizards/page.meta.js +18 -0
- package/dist/modules/cpq/backend/cpq/wizards/page.meta.js.map +7 -0
- package/dist/modules/cpq/ce.js +151 -0
- package/dist/modules/cpq/ce.js.map +7 -0
- package/dist/modules/cpq/cli.js +11 -0
- package/dist/modules/cpq/cli.js.map +7 -0
- package/dist/modules/cpq/components/CpqListView.js +265 -0
- package/dist/modules/cpq/components/CpqListView.js.map +7 -0
- package/dist/modules/cpq/components/NumberInput.js +95 -0
- package/dist/modules/cpq/components/NumberInput.js.map +7 -0
- package/dist/modules/cpq/components/StatusPath.js +60 -0
- package/dist/modules/cpq/components/StatusPath.js.map +7 -0
- package/dist/modules/cpq/components/statusMaps.js +66 -0
- package/dist/modules/cpq/components/statusMaps.js.map +7 -0
- package/dist/modules/cpq/components/useCpqRowActions.js +125 -0
- package/dist/modules/cpq/components/useCpqRowActions.js.map +7 -0
- package/dist/modules/cpq/data/entities.js +1556 -0
- package/dist/modules/cpq/data/entities.js.map +7 -0
- package/dist/modules/cpq/data/validators.js +575 -0
- package/dist/modules/cpq/data/validators.js.map +7 -0
- package/dist/modules/cpq/di.js +57 -0
- package/dist/modules/cpq/di.js.map +7 -0
- package/dist/modules/cpq/events.js +50 -0
- package/dist/modules/cpq/events.js.map +7 -0
- package/dist/modules/cpq/index.js +16 -0
- package/dist/modules/cpq/index.js.map +7 -0
- package/dist/modules/cpq/lib/seeds/api.js +32 -0
- package/dist/modules/cpq/lib/seeds/api.js.map +7 -0
- package/dist/modules/cpq/lib/seeds/tenant-provisioning.js +158 -0
- package/dist/modules/cpq/lib/seeds/tenant-provisioning.js.map +7 -0
- package/dist/modules/cpq/lib/seeds.js +6 -0
- package/dist/modules/cpq/lib/seeds.js.map +7 -0
- package/dist/modules/cpq/migrations/Migration20260220220000_cpq.js +40 -0
- package/dist/modules/cpq/migrations/Migration20260220220000_cpq.js.map +7 -0
- package/dist/modules/cpq/migrations/Migration20260330000000_cpq_product_domain.js +54 -0
- package/dist/modules/cpq/migrations/Migration20260330000000_cpq_product_domain.js.map +7 -0
- package/dist/modules/cpq/migrations/Migration20260331000000_cpq_charge_unique_per_offering.js +15 -0
- package/dist/modules/cpq/migrations/Migration20260331000000_cpq_charge_unique_per_offering.js.map +7 -0
- package/dist/modules/cpq/migrations/Migration20260401000000_cpq_quoting_v2.js +62 -0
- package/dist/modules/cpq/migrations/Migration20260401000000_cpq_quoting_v2.js.map +7 -0
- package/dist/modules/cpq/migrations/Migration20260402000000_cpq_workflows.js +56 -0
- package/dist/modules/cpq/migrations/Migration20260402000000_cpq_workflows.js.map +7 -0
- package/dist/modules/cpq/migrations/Migration20260407000000_cpq_pricing_tables_v2.js +26 -0
- package/dist/modules/cpq/migrations/Migration20260407000000_cpq_pricing_tables_v2.js.map +7 -0
- package/dist/modules/cpq/migrations/Migration20260407100000_cpq_price_rules.js +37 -0
- package/dist/modules/cpq/migrations/Migration20260407100000_cpq_price_rules.js.map +7 -0
- package/dist/modules/cpq/migrations/Migration20260408000000_cpq_price_rules.js +35 -0
- package/dist/modules/cpq/migrations/Migration20260408000000_cpq_price_rules.js.map +7 -0
- package/dist/modules/cpq/migrations/Migration20260410000000_cpq_drop_datacentres_inventory.js +21 -0
- package/dist/modules/cpq/migrations/Migration20260410000000_cpq_drop_datacentres_inventory.js.map +7 -0
- package/dist/modules/cpq/migrations/Migration20260410000000_cpq_wizard_rename.js +46 -0
- package/dist/modules/cpq/migrations/Migration20260410000000_cpq_wizard_rename.js.map +7 -0
- package/dist/modules/cpq/migrations/Migration20260410100000_cpq_inventory.js +118 -0
- package/dist/modules/cpq/migrations/Migration20260410100000_cpq_inventory.js.map +7 -0
- package/dist/modules/cpq/migrations/Migration20260411000000_cpq_orders.js +63 -0
- package/dist/modules/cpq/migrations/Migration20260411000000_cpq_orders.js.map +7 -0
- package/dist/modules/cpq/migrations/Migration20260412000000_cpq_bundled_offerings.js +28 -0
- package/dist/modules/cpq/migrations/Migration20260412000000_cpq_bundled_offerings.js.map +7 -0
- package/dist/modules/cpq/migrations/Migration20260504064621_cpq_arc.js +36 -0
- package/dist/modules/cpq/migrations/Migration20260504064621_cpq_arc.js.map +7 -0
- package/dist/modules/cpq/migrations/Migration20260514000000_cpq_spec_merge_retired_deprecated.js +14 -0
- package/dist/modules/cpq/migrations/Migration20260514000000_cpq_spec_merge_retired_deprecated.js.map +7 -0
- package/dist/modules/cpq/migrations/Migration20260514100000_cpq_offering_merge_retired_deprecated.js +14 -0
- package/dist/modules/cpq/migrations/Migration20260514100000_cpq_offering_merge_retired_deprecated.js.map +7 -0
- package/dist/modules/cpq/migrations/Migration20260514110000_cpq_list_search_indexes.js +58 -0
- package/dist/modules/cpq/migrations/Migration20260514110000_cpq_list_search_indexes.js.map +7 -0
- package/dist/modules/cpq/migrations/Migration20260515000000_cpq_inventory_subscriptions_search_indexes.js +29 -0
- package/dist/modules/cpq/migrations/Migration20260515000000_cpq_inventory_subscriptions_search_indexes.js.map +7 -0
- package/dist/modules/cpq/services/cpqBundleService.js +447 -0
- package/dist/modules/cpq/services/cpqBundleService.js.map +7 -0
- package/dist/modules/cpq/services/cpqInventoryService.js +1371 -0
- package/dist/modules/cpq/services/cpqInventoryService.js.map +7 -0
- package/dist/modules/cpq/services/cpqOrderService.js +901 -0
- package/dist/modules/cpq/services/cpqOrderService.js.map +7 -0
- package/dist/modules/cpq/services/cpqPricingService.js +289 -0
- package/dist/modules/cpq/services/cpqPricingService.js.map +7 -0
- package/dist/modules/cpq/services/cpqProductService.js +204 -0
- package/dist/modules/cpq/services/cpqProductService.js.map +7 -0
- package/dist/modules/cpq/services/cpqQuotingService.js +1867 -0
- package/dist/modules/cpq/services/cpqQuotingService.js.map +7 -0
- package/dist/modules/cpq/services/cpqValidationService.js +234 -0
- package/dist/modules/cpq/services/cpqValidationService.js.map +7 -0
- package/dist/modules/cpq/services/cpqWizardService.js +137 -0
- package/dist/modules/cpq/services/cpqWizardService.js.map +7 -0
- package/dist/modules/cpq/services/types.js +114 -0
- package/dist/modules/cpq/services/types.js.map +7 -0
- package/dist/modules/cpq/setup.js +49 -0
- package/dist/modules/cpq/setup.js.map +7 -0
- package/dist/modules/cpq/subscribers/subscription-amended-log.js +18 -0
- package/dist/modules/cpq/subscribers/subscription-amended-log.js.map +7 -0
- package/dist/modules/cpq/subscribers/subscription-cancelled-log.js +19 -0
- package/dist/modules/cpq/subscribers/subscription-cancelled-log.js.map +7 -0
- package/dist/modules/cpq/subscribers/subscription-merged-log.js +20 -0
- package/dist/modules/cpq/subscribers/subscription-merged-log.js.map +7 -0
- package/dist/modules/cpq/subscribers/subscription-renewed-log.js +18 -0
- package/dist/modules/cpq/subscribers/subscription-renewed-log.js.map +7 -0
- package/dist/modules/cpq/subscribers/subscription-superseded-log.js +18 -0
- package/dist/modules/cpq/subscribers/subscription-superseded-log.js.map +7 -0
- package/dist/modules/cpq/widgets/injection/customer-inventory/widget.client.js +192 -0
- package/dist/modules/cpq/widgets/injection/customer-inventory/widget.client.js.map +7 -0
- package/dist/modules/cpq/widgets/injection/customer-inventory/widget.js +17 -0
- package/dist/modules/cpq/widgets/injection/customer-inventory/widget.js.map +7 -0
- package/dist/modules/cpq/widgets/injection/order-cpq-tab/widget.client.js +79 -0
- package/dist/modules/cpq/widgets/injection/order-cpq-tab/widget.client.js.map +7 -0
- package/dist/modules/cpq/widgets/injection/order-cpq-tab/widget.js +17 -0
- package/dist/modules/cpq/widgets/injection/order-cpq-tab/widget.js.map +7 -0
- package/dist/modules/cpq/widgets/injection/quote-configurator/widget.client.js +181 -0
- package/dist/modules/cpq/widgets/injection/quote-configurator/widget.client.js.map +7 -0
- package/dist/modules/cpq/widgets/injection/quote-configurator/widget.js +17 -0
- package/dist/modules/cpq/widgets/injection/quote-configurator/widget.js.map +7 -0
- package/dist/modules/cpq/widgets/injection-table.js +44 -0
- package/dist/modules/cpq/widgets/injection-table.js.map +7 -0
- package/dist/modules/cpq/workflows/WizardRunner.js +113 -0
- package/dist/modules/cpq/workflows/WizardRunner.js.map +7 -0
- package/dist/modules/cpq/workflows/WizardTrigger.js +116 -0
- package/dist/modules/cpq/workflows/WizardTrigger.js.map +7 -0
- package/dist/modules/cpq/workflows/engine.js +188 -0
- package/dist/modules/cpq/workflows/engine.js.map +7 -0
- package/dist/modules/cpq/workflows/registry.js +16 -0
- package/dist/modules/cpq/workflows/registry.js.map +7 -0
- package/dist/modules/cpq/workflows/steps/CustomerSelectStep.js +119 -0
- package/dist/modules/cpq/workflows/steps/CustomerSelectStep.js.map +7 -0
- package/dist/modules/cpq/workflows/steps/InventorySelectStep.js +24 -0
- package/dist/modules/cpq/workflows/steps/InventorySelectStep.js.map +7 -0
- package/dist/modules/cpq/workflows/steps/ItemListStep.js +115 -0
- package/dist/modules/cpq/workflows/steps/ItemListStep.js.map +7 -0
- package/dist/modules/cpq/workflows/steps/OfferingSelectStep.js +327 -0
- package/dist/modules/cpq/workflows/steps/OfferingSelectStep.js.map +7 -0
- package/dist/modules/cpq/workflows/steps/ProductConfigureStep.js +231 -0
- package/dist/modules/cpq/workflows/steps/ProductConfigureStep.js.map +7 -0
- package/dist/modules/cpq/workflows/steps/ReviewStep.js +152 -0
- package/dist/modules/cpq/workflows/steps/ReviewStep.js.map +7 -0
- package/dist/modules/cpq/workflows/steps/index.js +49 -0
- package/dist/modules/cpq/workflows/steps/index.js.map +7 -0
- package/dist/modules/cpq/workflows/types.js +1 -0
- package/dist/modules/cpq/workflows/types.js.map +7 -0
- package/package.json +150 -0
- package/src/modules/cpq/__integration__/TC-CPQ-001.spec.ts +177 -0
- package/src/modules/cpq/__integration__/TC-CPQ-002.spec.ts +123 -0
- package/src/modules/cpq/__integration__/TC-CPQ-003.spec.ts +115 -0
- package/src/modules/cpq/__integration__/TC-CPQ-004.spec.ts +184 -0
- package/src/modules/cpq/__integration__/TC-CPQ-005.spec.ts +43 -0
- package/src/modules/cpq/__integration__/TC-CPQ-006.spec.ts +87 -0
- package/src/modules/cpq/__integration__/TC-CPQ-007.spec.ts +79 -0
- package/src/modules/cpq/__integration__/TC-CPQ-008.spec.ts +55 -0
- package/src/modules/cpq/__integration__/TC-CPQ-009.spec.ts +45 -0
- package/src/modules/cpq/__integration__/TC-CPQ-010.spec.ts +54 -0
- package/src/modules/cpq/__integration__/TC-CPQ-011.spec.ts +24 -0
- package/src/modules/cpq/__integration__/TC-CPQ-012.spec.ts +62 -0
- package/src/modules/cpq/__integration__/TC-CPQ-ARC-001.spec.ts +52 -0
- package/src/modules/cpq/__integration__/TC-CPQ-ARC-002.spec.ts +65 -0
- package/src/modules/cpq/__integration__/TC-CPQ-ARC-003.spec.ts +107 -0
- package/src/modules/cpq/__integration__/TC-CPQ-ARC-004.spec.ts +74 -0
- package/src/modules/cpq/__integration__/TC-CPQ-ARC-005.spec.ts +86 -0
- package/src/modules/cpq/__integration__/TC-CPQ-ARC-006.spec.ts +79 -0
- package/src/modules/cpq/__integration__/TC-CPQ-ARC-007.spec.ts +63 -0
- package/src/modules/cpq/__integration__/TC-CPQ-ARC-008.spec.ts +62 -0
- package/src/modules/cpq/__integration__/TC-CPQ-ARC-009.spec.ts +62 -0
- package/src/modules/cpq/__integration__/TC-CPQ-ARC-010.spec.ts +59 -0
- package/src/modules/cpq/__integration__/TC-CPQ-ARC-011.spec.ts +128 -0
- package/src/modules/cpq/__integration__/_helpers/cpqArcFixtures.ts +208 -0
- package/src/modules/cpq/__tests__/package-isolation.test.ts +232 -0
- package/src/modules/cpq/acl.ts +26 -0
- package/src/modules/cpq/api/_helpers/__tests__/handleArcError.test.ts +117 -0
- package/src/modules/cpq/api/_helpers/handleArcError.ts +81 -0
- package/src/modules/cpq/api/attribute-options/route.ts +55 -0
- package/src/modules/cpq/api/bundle-slots/route.ts +112 -0
- package/src/modules/cpq/api/bundle-tree/route.ts +31 -0
- package/src/modules/cpq/api/context.ts +39 -0
- package/src/modules/cpq/api/inventory/assets/route.ts +123 -0
- package/src/modules/cpq/api/inventory/assets/status/route.ts +34 -0
- package/src/modules/cpq/api/inventory/customer/[customerId]/parent-items/route.ts +30 -0
- package/src/modules/cpq/api/inventory/customer/[customerId]/route.ts +31 -0
- package/src/modules/cpq/api/inventory/subscription-items/route.ts +107 -0
- package/src/modules/cpq/api/inventory/subscriptions/[subscriptionId]/change-log/route.ts +64 -0
- package/src/modules/cpq/api/inventory/subscriptions/expiring/route.ts +66 -0
- package/src/modules/cpq/api/inventory/subscriptions/route.ts +126 -0
- package/src/modules/cpq/api/inventory/subscriptions/status/route.ts +34 -0
- package/src/modules/cpq/api/offering-components/route.ts +103 -0
- package/src/modules/cpq/api/orders/[orderId]/activate/route.ts +48 -0
- package/src/modules/cpq/api/orders/[orderId]/route.ts +28 -0
- package/src/modules/cpq/api/orders/[orderId]/status/route.ts +38 -0
- package/src/modules/cpq/api/orders/route.ts +77 -0
- package/src/modules/cpq/api/price-rules/route.ts +210 -0
- package/src/modules/cpq/api/pricing-table-entries/route.ts +159 -0
- package/src/modules/cpq/api/pricing-tables/route.ts +202 -0
- package/src/modules/cpq/api/product-attributes/route.ts +175 -0
- package/src/modules/cpq/api/product-charges/route.ts +181 -0
- package/src/modules/cpq/api/product-offerings/route.ts +329 -0
- package/src/modules/cpq/api/product-relationships/route.ts +156 -0
- package/src/modules/cpq/api/product-specifications/route.ts +325 -0
- package/src/modules/cpq/api/quotes/[quoteId]/cancel-meta/route.ts +77 -0
- package/src/modules/cpq/api/quotes/[quoteId]/clone/route.ts +28 -0
- package/src/modules/cpq/api/quotes/[quoteId]/items/[lineId]/route.ts +55 -0
- package/src/modules/cpq/api/quotes/[quoteId]/items/route.ts +26 -0
- package/src/modules/cpq/api/quotes/[quoteId]/merge-meta/route.ts +78 -0
- package/src/modules/cpq/api/quotes/[quoteId]/recalculate/route.ts +34 -0
- package/src/modules/cpq/api/quotes/[quoteId]/route.ts +109 -0
- package/src/modules/cpq/api/quotes/[quoteId]/status/route.ts +26 -0
- package/src/modules/cpq/api/quotes/[quoteId]/target-subscriptions/[targetId]/route.ts +91 -0
- package/src/modules/cpq/api/quotes/[quoteId]/target-subscriptions/route.ts +107 -0
- package/src/modules/cpq/api/quotes/attributes/route.ts +61 -0
- package/src/modules/cpq/api/quotes/from-subscription/route.ts +85 -0
- package/src/modules/cpq/api/quotes/price/route.ts +81 -0
- package/src/modules/cpq/api/quotes/route.ts +114 -0
- package/src/modules/cpq/api/quotes/validate-relationships/route.ts +100 -0
- package/src/modules/cpq/api/resolveQuotingService.ts +11 -0
- package/src/modules/cpq/api/wizards/resolve/route.ts +39 -0
- package/src/modules/cpq/api/wizards/route.ts +127 -0
- package/src/modules/cpq/backend/cpq/inventory/AssetsTable.tsx +166 -0
- package/src/modules/cpq/backend/cpq/inventory/SubscriptionsTable.tsx +251 -0
- package/src/modules/cpq/backend/cpq/inventory/assets/[id]/page.meta.ts +9 -0
- package/src/modules/cpq/backend/cpq/inventory/assets/[id]/page.tsx +440 -0
- package/src/modules/cpq/backend/cpq/inventory/page.meta.ts +16 -0
- package/src/modules/cpq/backend/cpq/inventory/page.tsx +49 -0
- package/src/modules/cpq/backend/cpq/inventory/shared.tsx +32 -0
- package/src/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.meta.ts +9 -0
- package/src/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.tsx +1085 -0
- package/src/modules/cpq/backend/cpq/offerings/[id]/page.tsx +1165 -0
- package/src/modules/cpq/backend/cpq/offerings/page.meta.ts +16 -0
- package/src/modules/cpq/backend/cpq/offerings/page.tsx +468 -0
- package/src/modules/cpq/backend/cpq/orders/[id]/page.tsx +921 -0
- package/src/modules/cpq/backend/cpq/orders/page.meta.ts +16 -0
- package/src/modules/cpq/backend/cpq/orders/page.tsx +182 -0
- package/src/modules/cpq/backend/cpq/price-rules/PriceRuleForm.tsx +310 -0
- package/src/modules/cpq/backend/cpq/price-rules/[id]/page.meta.ts +9 -0
- package/src/modules/cpq/backend/cpq/price-rules/[id]/page.tsx +472 -0
- package/src/modules/cpq/backend/cpq/price-rules/page.meta.ts +16 -0
- package/src/modules/cpq/backend/cpq/price-rules/page.tsx +253 -0
- package/src/modules/cpq/backend/cpq/pricing/[id]/EntriesEditor.tsx +431 -0
- package/src/modules/cpq/backend/cpq/pricing/[id]/ImportPreview.tsx +122 -0
- package/src/modules/cpq/backend/cpq/pricing/[id]/page.tsx +588 -0
- package/src/modules/cpq/backend/cpq/pricing/[id]/xlsxExport.ts +90 -0
- package/src/modules/cpq/backend/cpq/pricing/[id]/xlsxImport.ts +338 -0
- package/src/modules/cpq/backend/cpq/pricing/page.meta.ts +16 -0
- package/src/modules/cpq/backend/cpq/pricing/page.tsx +111 -0
- package/src/modules/cpq/backend/cpq/quotes/[id]/_components/ArcQuoteConfigurator.tsx +737 -0
- package/src/modules/cpq/backend/cpq/quotes/[id]/page.tsx +1721 -0
- package/src/modules/cpq/backend/cpq/quotes/page.meta.ts +16 -0
- package/src/modules/cpq/backend/cpq/quotes/page.tsx +370 -0
- package/src/modules/cpq/backend/cpq/specifications/[id]/DependsOnRulesEditor.tsx +300 -0
- package/src/modules/cpq/backend/cpq/specifications/[id]/page.tsx +1722 -0
- package/src/modules/cpq/backend/cpq/specifications/page.meta.ts +16 -0
- package/src/modules/cpq/backend/cpq/specifications/page.tsx +191 -0
- package/src/modules/cpq/backend/cpq/wizards/[definitionCode]/detail/page.tsx +319 -0
- package/src/modules/cpq/backend/cpq/wizards/[definitionCode]/page.tsx +234 -0
- package/src/modules/cpq/backend/cpq/wizards/page.meta.ts +16 -0
- package/src/modules/cpq/backend/cpq/wizards/page.tsx +141 -0
- package/src/modules/cpq/ce.ts +150 -0
- package/src/modules/cpq/cli.ts +10 -0
- package/src/modules/cpq/components/CpqListView.tsx +431 -0
- package/src/modules/cpq/components/NumberInput.tsx +166 -0
- package/src/modules/cpq/components/StatusPath.tsx +116 -0
- package/src/modules/cpq/components/statusMaps.ts +148 -0
- package/src/modules/cpq/components/useCpqRowActions.tsx +183 -0
- package/src/modules/cpq/data/__tests__/validators.arc.test.ts +271 -0
- package/src/modules/cpq/data/__tests__/validators.test.ts +782 -0
- package/src/modules/cpq/data/entities.ts +1467 -0
- package/src/modules/cpq/data/validators.ts +663 -0
- package/src/modules/cpq/di.ts +70 -0
- package/src/modules/cpq/events.ts +62 -0
- package/src/modules/cpq/index.ts +15 -0
- package/src/modules/cpq/lib/seeds/__tests__/api.test.ts +86 -0
- package/src/modules/cpq/lib/seeds/__tests__/tenant-provisioning.test.ts +349 -0
- package/src/modules/cpq/lib/seeds/api.ts +119 -0
- package/src/modules/cpq/lib/seeds/tenant-provisioning.ts +239 -0
- package/src/modules/cpq/lib/seeds.ts +18 -0
- package/src/modules/cpq/migrations/.snapshot-open-mercato.json +7473 -0
- package/src/modules/cpq/migrations/Migration20260220220000_cpq.ts +51 -0
- package/src/modules/cpq/migrations/Migration20260330000000_cpq_product_domain.ts +70 -0
- package/src/modules/cpq/migrations/Migration20260331000000_cpq_charge_unique_per_offering.ts +15 -0
- package/src/modules/cpq/migrations/Migration20260401000000_cpq_quoting_v2.ts +73 -0
- package/src/modules/cpq/migrations/Migration20260402000000_cpq_workflows.ts +59 -0
- package/src/modules/cpq/migrations/Migration20260407000000_cpq_pricing_tables_v2.ts +30 -0
- package/src/modules/cpq/migrations/Migration20260407100000_cpq_price_rules.ts +36 -0
- package/src/modules/cpq/migrations/Migration20260408000000_cpq_price_rules.ts +33 -0
- package/src/modules/cpq/migrations/Migration20260410000000_cpq_drop_datacentres_inventory.ts +22 -0
- package/src/modules/cpq/migrations/Migration20260410000000_cpq_wizard_rename.ts +56 -0
- package/src/modules/cpq/migrations/Migration20260410100000_cpq_inventory.ts +118 -0
- package/src/modules/cpq/migrations/Migration20260411000000_cpq_orders.ts +62 -0
- package/src/modules/cpq/migrations/Migration20260412000000_cpq_bundled_offerings.ts +33 -0
- package/src/modules/cpq/migrations/Migration20260504064621_cpq_arc.ts +68 -0
- package/src/modules/cpq/migrations/Migration20260514000000_cpq_spec_merge_retired_deprecated.ts +30 -0
- package/src/modules/cpq/migrations/Migration20260514100000_cpq_offering_merge_retired_deprecated.ts +27 -0
- package/src/modules/cpq/migrations/Migration20260514110000_cpq_list_search_indexes.ts +82 -0
- package/src/modules/cpq/migrations/Migration20260515000000_cpq_inventory_subscriptions_search_indexes.ts +52 -0
- package/src/modules/cpq/services/__tests__/_helpers/mockEm.ts +59 -0
- package/src/modules/cpq/services/__tests__/cpqBundleService.test.ts +661 -0
- package/src/modules/cpq/services/__tests__/cpqInventoryService.arc.test.ts +357 -0
- package/src/modules/cpq/services/__tests__/cpqInventoryService.test.ts +718 -0
- package/src/modules/cpq/services/__tests__/cpqOrderService.test.ts +603 -0
- package/src/modules/cpq/services/__tests__/cpqPricingService.test.ts +1012 -0
- package/src/modules/cpq/services/__tests__/cpqProductService.test.ts +603 -0
- package/src/modules/cpq/services/__tests__/cpqQuotingService.arc.test.ts +143 -0
- package/src/modules/cpq/services/__tests__/cpqQuotingService.test.ts +658 -0
- package/src/modules/cpq/services/__tests__/cpqValidationService.test.ts +811 -0
- package/src/modules/cpq/services/__tests__/cpqWizardService.test.ts +389 -0
- package/src/modules/cpq/services/__tests__/types.test.ts +359 -0
- package/src/modules/cpq/services/cpqBundleService.ts +671 -0
- package/src/modules/cpq/services/cpqInventoryService.ts +1929 -0
- package/src/modules/cpq/services/cpqOrderService.ts +1230 -0
- package/src/modules/cpq/services/cpqPricingService.ts +412 -0
- package/src/modules/cpq/services/cpqProductService.ts +311 -0
- package/src/modules/cpq/services/cpqQuotingService.ts +2638 -0
- package/src/modules/cpq/services/cpqValidationService.ts +323 -0
- package/src/modules/cpq/services/cpqWizardService.ts +204 -0
- package/src/modules/cpq/services/types.ts +303 -0
- package/src/modules/cpq/setup.ts +63 -0
- package/src/modules/cpq/subscribers/subscription-amended-log.ts +20 -0
- package/src/modules/cpq/subscribers/subscription-cancelled-log.ts +19 -0
- package/src/modules/cpq/subscribers/subscription-merged-log.ts +22 -0
- package/src/modules/cpq/subscribers/subscription-renewed-log.ts +18 -0
- package/src/modules/cpq/subscribers/subscription-superseded-log.ts +19 -0
- package/src/modules/cpq/widgets/injection/customer-inventory/widget.client.tsx +339 -0
- package/src/modules/cpq/widgets/injection/customer-inventory/widget.ts +16 -0
- package/src/modules/cpq/widgets/injection/order-cpq-tab/widget.client.tsx +96 -0
- package/src/modules/cpq/widgets/injection/order-cpq-tab/widget.ts +16 -0
- package/src/modules/cpq/widgets/injection/quote-configurator/widget.client.tsx +265 -0
- package/src/modules/cpq/widgets/injection/quote-configurator/widget.ts +16 -0
- package/src/modules/cpq/widgets/injection-table.ts +42 -0
- package/src/modules/cpq/workflows/WizardRunner.tsx +158 -0
- package/src/modules/cpq/workflows/WizardTrigger.tsx +142 -0
- package/src/modules/cpq/workflows/engine.tsx +278 -0
- package/src/modules/cpq/workflows/registry.ts +15 -0
- package/src/modules/cpq/workflows/steps/CustomerSelectStep.tsx +136 -0
- package/src/modules/cpq/workflows/steps/InventorySelectStep.tsx +34 -0
- package/src/modules/cpq/workflows/steps/ItemListStep.tsx +146 -0
- package/src/modules/cpq/workflows/steps/OfferingSelectStep.tsx +438 -0
- package/src/modules/cpq/workflows/steps/ProductConfigureStep.tsx +287 -0
- package/src/modules/cpq/workflows/steps/ReviewStep.tsx +219 -0
- package/src/modules/cpq/workflows/steps/index.ts +51 -0
- package/src/modules/cpq/workflows/types.ts +102 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/cpq/services/cpqOrderService.ts"],
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { SalesOrder, SalesOrderLine } from '@open-mercato/core/modules/sales/data/entities'\nimport type { SalesDocumentNumberGenerator } from '@open-mercato/core/modules/sales/services/salesDocumentNumberGenerator'\nimport {\n CpqQuoteConfiguration,\n CpqQuoteLineConfiguration,\n CpqQuoteTargetSubscription,\n CpqInventorySubscription,\n CpqOrderConfiguration,\n CpqOrderLineConfiguration,\n CpqProductOffering,\n CpqProductSpecification,\n CpqInventorySubscriptionItem,\n} from '../data/entities'\nimport type {\n ApplyArcResult,\n ApplyMergeRenewalResult,\n ArcLineChange,\n CreateSubscriptionItemInput,\n DefaultCpqInventoryService,\n} from './cpqInventoryService'\nimport {\n CPQ_ORDER_TRANSITIONS,\n type CpqOrderStatus,\n type TenantScope,\n} from './types'\nimport { emitCpqEvent } from '../events'\n\n// \u2500\u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ninterface OrderListFilters {\n customerId?: string\n sourceQuoteId?: string\n salesOrderId?: string\n cpqStatus?: string | string[]\n currencyCode?: string\n search?: string\n sortField?: 'createdAt' | 'updatedAt' | 'cpqStatus' | 'activatedAt' | 'currencyCode'\n sortDir?: 'asc' | 'desc'\n page?: number\n pageSize?: number\n}\n\ninterface PaginatedResult<T> {\n items: T[]\n total: number\n page: number\n pageSize: number\n totalPages: number\n}\n\ninterface OrderLineResult {\n lineId: string\n offeringId: string | null\n offeringName: string\n offeringType: string | null\n productId: string | null\n specId: string | null\n action: string\n parentLineId: string | null\n quantity: number\n configuration: Record<string, unknown>\n startDate: string | null\n termMonths: number | null\n endDate: string | null\n nrcTotal: number\n mrcTotal: number\n charges: Array<Record<string, unknown>>\n sourceQuoteLineId: string | null\n /** XD-250 ARC: snapshot of the source subscription item's current state.\n * Null for non-ARC lines and for fresh `add` lines on amend quotes. */\n arcSource: {\n subscriptionItemId: string\n name: string\n mrcAmount: number\n nrcAmount: number\n quantity: number\n } | null\n}\n\ninterface OrderResult {\n id: string\n orderId: string\n orderNumber: string\n customerId: string\n cpqStatus: string\n sourceQuoteId: string | null\n /** XD-250 ARC quote type carried over from the source quote \u2014 used by the\n * order detail page to render the AMEND / RENEW / CANCEL badge. */\n quoteType: string\n currencyCode: string\n pricingSummary: {\n nrcTotal: number\n mrcTotal: number\n currencyCode: string\n }\n activatedAt: string | null\n createdAt: string\n lines: OrderLineResult[]\n}\n\ninterface OrderServiceDeps {\n em: EntityManager\n cpqInventoryService: DefaultCpqInventoryService\n salesDocumentNumberGenerator: SalesDocumentNumberGenerator\n}\n\nconst CPQ_TO_SALES_ORDER_STATUS: Record<CpqOrderStatus, string> = {\n draft: 'draft',\n pending_activation: 'pending',\n active: 'active',\n cancelled: 'cancelled',\n fulfilled: 'fulfilled',\n}\n\n// \u2500\u2500\u2500 Service \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class DefaultCpqOrderService {\n private em: EntityManager\n private inventoryService: DefaultCpqInventoryService\n private numberGenerator: SalesDocumentNumberGenerator\n\n constructor(deps: OrderServiceDeps) {\n this.em = deps.em\n this.inventoryService = deps.cpqInventoryService\n this.numberGenerator = deps.salesDocumentNumberGenerator\n }\n\n // \u2500\u2500\u2500 Convert Quote to Order \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async convertQuoteToOrder(quoteId: string, scope: TenantScope): Promise<OrderResult> {\n const em = this.em\n\n const cpqConfig = await em.findOne(CpqQuoteConfiguration, {\n id: quoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!cpqConfig) {\n const byQuoteId = await em.findOne(CpqQuoteConfiguration, {\n quoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!byQuoteId) throw new OrderError(404, 'Quote not found')\n return this.convertFromConfig(byQuoteId, scope)\n }\n return this.convertFromConfig(cpqConfig, scope)\n }\n\n private async convertFromConfig(cpqConfig: CpqQuoteConfiguration, scope: TenantScope): Promise<OrderResult> {\n const em = this.em\n\n const blockedStatuses = ['cancelled', 'rejected']\n if (blockedStatuses.includes(cpqConfig.cpqStatus)) {\n throw new OrderError(409, `Cannot convert a quote in '${cpqConfig.cpqStatus}' status`)\n }\n\n // Idempotency guard: a quote may only convert once. If an order with\n // this quote as its `sourceQuoteId` already exists, the UI should\n // surface \"Go to order\" instead of re-running conversion \u2014 return\n // 409 with the existing id so the caller can redirect.\n const existingOrder = await em.findOne(CpqOrderConfiguration, {\n sourceQuoteId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (existingOrder) {\n throw new OrderError(\n 409,\n `Quote has already been converted to order ${existingOrder.orderId}`,\n )\n }\n\n const quoteLines = await em.find(CpqQuoteLineConfiguration, {\n quoteConfigurationId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n\n if (quoteLines.length === 0) {\n throw new OrderError(422, 'Cannot convert a quote with no line items')\n }\n\n const { number: orderNumber } = await this.numberGenerator.generate({\n kind: 'order',\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n\n const salesOrderId = crypto.randomUUID()\n const pricingSummary = cpqConfig.pricingSummary as Record<string, unknown> | null\n const nrcTotal = Number(pricingSummary?.nrcTotal ?? 0)\n const mrcTotal = Number(pricingSummary?.mrcTotal ?? 0)\n const grandTotal = nrcTotal + mrcTotal\n\n const salesOrder = em.create(SalesOrder, {\n id: salesOrderId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n orderNumber,\n customerEntityId: cpqConfig.customerId,\n currencyCode: cpqConfig.currencyCode,\n status: 'draft',\n subtotalNetAmount: String(grandTotal),\n subtotalGrossAmount: String(grandTotal),\n discountTotalAmount: '0',\n taxTotalAmount: '0',\n shippingNetAmount: '0',\n shippingGrossAmount: '0',\n surchargeTotalAmount: '0',\n paidTotalAmount: '0',\n grandTotalNetAmount: String(grandTotal),\n grandTotalGrossAmount: String(grandTotal),\n lineItemCount: quoteLines.length,\n metadata: { sourceQuoteId: cpqConfig.id },\n createdAt: new Date(),\n updatedAt: new Date(),\n } as never)\n em.persist(salesOrder)\n\n const cpqOrderConfigId = crypto.randomUUID()\n const cpqOrderConfig = em.create(CpqOrderConfiguration, {\n id: cpqOrderConfigId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n orderId: salesOrderId,\n sourceQuoteId: cpqConfig.id,\n customerId: cpqConfig.customerId,\n cpqStatus: 'draft',\n currencyCode: cpqConfig.currencyCode,\n pricingSummary: {\n nrcTotal,\n mrcTotal,\n currencyCode: cpqConfig.currencyCode,\n },\n })\n em.persist(cpqOrderConfig)\n\n const quoteLineIdToOrderLineId = new Map<string, string>()\n\n for (let i = 0; i < quoteLines.length; i++) {\n const ql = quoteLines[i]\n\n const perInstanceNrc = Number(ql.nrcTotal)\n const perInstanceMrc = Number(ql.mrcTotal)\n const unitPriceNet = (perInstanceNrc + perInstanceMrc) / ql.quantity\n const totalNet = perInstanceNrc + perInstanceMrc\n\n const orderLineId = crypto.randomUUID()\n quoteLineIdToOrderLineId.set(ql.quoteLineId, orderLineId)\n\n const offeringName = await this.resolveOfferingName(\n em,\n ql.offeringId,\n scope,\n ql.configuration as Record<string, unknown> | null,\n )\n\n const orderLine = em.create(SalesOrderLine, {\n id: orderLineId,\n order: salesOrder,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n lineNumber: i + 1,\n kind: 'product',\n productId: ql.productId ?? null,\n name: offeringName,\n quantity: String(ql.quantity),\n unitPriceNet: String(unitPriceNet),\n unitPriceGross: String(unitPriceNet),\n totalNetAmount: String(totalNet),\n totalGrossAmount: String(totalNet),\n discountAmount: '0',\n discountPercent: '0',\n taxRate: '0',\n taxAmount: '0',\n currencyCode: cpqConfig.currencyCode,\n configuration: {\n offeringId: ql.offeringId ?? null,\n action: ql.action,\n nrcTotal: perInstanceNrc,\n mrcTotal: perInstanceMrc,\n parentLineId: ql.parentLineId ?? null,\n },\n normalizedQuantity: String(ql.quantity),\n reservedQuantity: '0',\n fulfilledQuantity: '0',\n invoicedQuantity: '0',\n returnedQuantity: '0',\n createdAt: new Date(),\n updatedAt: new Date(),\n } as never)\n em.persist(orderLine)\n const orderLineConfig = em.create(CpqOrderLineConfiguration, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n orderLineId,\n orderConfigurationId: cpqOrderConfig.id,\n offeringId: ql.offeringId ?? null,\n productId: ql.productId ?? null,\n specId: ql.specId ?? null,\n action: ql.action,\n parentLineId: null,\n startDate: ql.startDate,\n termMonths: ql.termMonths ?? null,\n endDate: ql.endDate,\n configuration: { ...ql.configuration, offeringName },\n quantity: ql.quantity,\n charges: ql.charges ? [...ql.charges] : null,\n nrcTotal: ql.nrcTotal,\n mrcTotal: ql.mrcTotal,\n sourceQuoteLineId: ql.quoteLineId,\n })\n em.persist(orderLineConfig)\n }\n\n await em.flush()\n\n // Resolve parent line references using the quote\u2192order line ID map\n const orderLineConfigs = await em.find(CpqOrderLineConfiguration, {\n orderConfigurationId: cpqOrderConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n for (const olc of orderLineConfigs) {\n if (olc.sourceQuoteLineId) {\n const sourceQl = quoteLines.find((ql) => ql.quoteLineId === olc.sourceQuoteLineId)\n if (sourceQl?.parentLineId) {\n const mappedParent = quoteLineIdToOrderLineId.get(sourceQl.parentLineId)\n if (mappedParent) olc.parentLineId = mappedParent\n }\n }\n }\n\n await em.flush()\n\n return this.buildOrderResult(em, cpqOrderConfig, salesOrder, orderLineConfigs, scope)\n }\n\n // \u2500\u2500\u2500 Activate Order \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async activateOrder(orderId: string, scope: TenantScope): Promise<OrderResult> {\n const em = this.em\n\n const orderConfig = await this.loadOrderConfig(em, orderId, scope)\n\n const currentStatus = orderConfig.cpqStatus as CpqOrderStatus\n if (currentStatus !== 'draft' && currentStatus !== 'pending_activation') {\n throw new OrderError(409, `Cannot activate order in '${currentStatus}' status`)\n }\n\n const salesOrder = await this.loadSalesOrder(em, orderConfig.orderId, scope)\n const orderLines = await em.find(CpqOrderLineConfiguration, {\n orderConfigurationId: orderConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n\n // Branch on the source quote's quoteType. ARC quotes mutate existing\n // subscriptions; new-sale quotes materialize a fresh subscription.\n const sourceQuote = orderConfig.sourceQuoteId\n ? await em.findOne(CpqQuoteConfiguration, {\n id: orderConfig.sourceQuoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n : null\n\n const quoteType = sourceQuote?.quoteType ?? 'new'\n const arcEvents: Array<() => Promise<void>> = []\n\n if (quoteType === 'new') {\n await this.createInventoryFromOrder(orderConfig, orderLines, scope)\n } else {\n arcEvents.push(\n ...(await this.applyArcOrder(orderConfig, sourceQuote!, orderLines, scope)),\n )\n }\n\n orderConfig.cpqStatus = 'active'\n orderConfig.activatedAt = new Date()\n salesOrder.status = 'active'\n salesOrder.placedAt = new Date()\n\n await em.flush()\n\n // Emit ARC events AFTER the activation transaction commits.\n for (const fire of arcEvents) {\n try {\n await fire()\n } catch (err) {\n // Don't roll back the activation just because a subscriber blew up \u2014\n // events are best-effort once the DB state is committed.\n console.error('[cpq.arc] event emission failed', err)\n }\n }\n\n return this.buildOrderResult(em, orderConfig, salesOrder, orderLines, scope)\n }\n\n // \u2500\u2500\u2500 ARC activation branch (XD-250) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n //\n // Reads the source quote's targets + lines, then dispatches per target to\n // cpqInventoryService.apply* primitives. Returns the list of post-commit\n // event emissions so the caller can fire them outside the activation TX.\n private async applyArcOrder(\n orderConfig: CpqOrderConfiguration,\n sourceQuote: CpqQuoteConfiguration,\n orderLines: CpqOrderLineConfiguration[],\n scope: TenantScope,\n ): Promise<Array<() => Promise<void>>> {\n const em = this.em\n const quoteType = sourceQuote.quoteType as 'amend' | 'renew' | 'cancel'\n\n // Load attached targets.\n const targets = await em.find(CpqQuoteTargetSubscription, {\n quoteId: sourceQuote.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (targets.length === 0) {\n throw new OrderError(\n 409,\n `ARC quote ${sourceQuote.id} has no target subscriptions to activate`,\n )\n }\n\n const inventory = this.inventoryService\n\n // Group order lines by target_subscription_id \u2014 ARC order lines mirror the\n // quote lines' ARC fields (target_subscription_id is preserved through\n // convertQuoteToOrder via line.configuration when needed).\n // Source quote lines are the source of truth for ARC line data because\n // CpqOrderLineConfiguration doesn't carry target/source-item fields.\n const sourceQuoteLines = await em.find(CpqQuoteLineConfiguration, {\n quoteConfigurationId: sourceQuote.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n const linesByTarget = new Map<string | null, CpqQuoteLineConfiguration[]>()\n for (const line of sourceQuoteLines) {\n const key = line.targetSubscriptionId ?? null\n const list = linesByTarget.get(key) ?? []\n list.push(line)\n linesByTarget.set(key, list)\n }\n\n // Look up specs for `add` lines so we can build itemInput correctly.\n const specIds = [\n ...new Set(sourceQuoteLines.map((l) => l.specId).filter((x): x is string => Boolean(x))),\n ]\n const specs =\n specIds.length > 0\n ? await em.find(CpqProductSpecification, {\n id: { $in: specIds },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n : []\n const specMap = new Map(specs.map((s) => [s.id, s]))\n\n const events: Array<() => Promise<void>> = []\n const eventBaseEnvelope = {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n sourceQuoteId: sourceQuote.id,\n sourceOrderId: orderConfig.id,\n } as const\n\n if (quoteType === 'amend') {\n for (const target of targets) {\n const lines = linesByTarget.get(target.subscriptionId) ?? []\n const result = await inventory.applyAmendment(\n {\n subscriptionId: target.subscriptionId,\n sourceQuoteId: sourceQuote.id,\n sourceOrderId: orderConfig.id,\n performedByUserId: null,\n lineChanges: lines.map((l) => buildArcLineChange(l, specMap)),\n },\n scope,\n )\n events.push(() =>\n emitArcEvent('cpq.subscription.amended', result, eventBaseEnvelope),\n )\n }\n } else if (quoteType === 'cancel') {\n for (const target of targets) {\n const result = await inventory.applyCancel(\n {\n subscriptionId: target.subscriptionId,\n sourceQuoteId: sourceQuote.id,\n sourceOrderId: orderConfig.id,\n performedByUserId: null,\n etfAmount: sourceQuote.arcEtfAmount ?? null,\n etfCurrency: sourceQuote.arcEtfCurrency ?? null,\n reasonCode: sourceQuote.arcReasonCode ?? null,\n reasonText: sourceQuote.arcReasonText ?? null,\n },\n scope,\n )\n events.push(() =>\n emitArcEvent('cpq.subscription.cancelled', result, {\n ...eventBaseEnvelope,\n etfAmount: sourceQuote.arcEtfAmount ?? null,\n etfCurrency: sourceQuote.arcEtfCurrency ?? null,\n reasonCode: sourceQuote.arcReasonCode ?? null,\n reasonText: sourceQuote.arcReasonText ?? null,\n }),\n )\n }\n } else if (quoteType === 'renew') {\n const standalone = targets.filter((t) => t.mergeAction === 'standalone')\n const absorb = targets.filter((t) => t.mergeAction === 'absorb')\n\n if (standalone.length > 0 && absorb.length === 0) {\n for (const target of standalone) {\n if (!target.newTermStart || !target.newTermEnd) {\n throw new OrderError(\n 409,\n `Standalone renew target ${target.id} missing newTermStart/newTermEnd`,\n )\n }\n const lines = linesByTarget.get(target.subscriptionId) ?? []\n const result = await inventory.applyRenewal(\n {\n subscriptionId: target.subscriptionId,\n sourceQuoteId: sourceQuote.id,\n sourceOrderId: orderConfig.id,\n performedByUserId: null,\n term: {\n newTermStart: target.newTermStart,\n newTermEnd: target.newTermEnd,\n newTermMonths: target.newTermMonths ?? null,\n },\n lineChanges: lines.map((l) => buildArcLineChange(l, specMap)),\n },\n scope,\n )\n events.push(() =>\n emitArcEvent('cpq.subscription.renewed', result, {\n ...eventBaseEnvelope,\n term: {\n newTermStart: target.newTermStart!.toISOString(),\n newTermEnd: target.newTermEnd!.toISOString(),\n },\n }),\n )\n }\n } else if (absorb.length >= 2 && standalone.length === 0) {\n if (!sourceQuote.arcMergeNewTermStart || !sourceQuote.arcMergeNewTermEnd) {\n throw new OrderError(\n 409,\n `Merge renew quote ${sourceQuote.id} missing arc_merge_new_term_*`,\n )\n }\n // Lines targeting null are operator-edits on the new merge sub M.\n const mergeLines = linesByTarget.get(null) ?? []\n const merge = await inventory.applyMergeRenewal(\n {\n sourceIds: absorb.map((t) => t.subscriptionId),\n sourceQuoteId: sourceQuote.id,\n sourceOrderId: orderConfig.id,\n performedByUserId: null,\n term: {\n newTermStart: sourceQuote.arcMergeNewTermStart,\n newTermEnd: sourceQuote.arcMergeNewTermEnd,\n newTermMonths: sourceQuote.arcMergeNewTermMonths ?? null,\n },\n mergeMeta: {\n newSubCode: sourceQuote.arcMergeNewSubCode ?? null,\n newSubName: sourceQuote.arcMergeNewSubName ?? null,\n },\n lineChanges: mergeLines.map((l) => buildArcLineChange(l, specMap)),\n },\n scope,\n )\n\n // One event per source (`superseded`) + one for M (`merged`).\n const mergedFromSubscriptionIds = absorb.map((t) => t.subscriptionId)\n events.push(() =>\n emitMergedEvent(merge, eventBaseEnvelope, mergedFromSubscriptionIds),\n )\n for (const sourceLog of merge.sourceChangeLogs) {\n events.push(() =>\n emitSupersededEvent(sourceLog, merge.mergedSubscription.id, eventBaseEnvelope),\n )\n }\n } else {\n throw new OrderError(\n 409,\n `Inconsistent renew targets \u2014 must be either single standalone or \u22652 absorb`,\n )\n }\n } else {\n throw new OrderError(500, `Unknown quote_type '${quoteType}' for ARC activation`)\n }\n\n return events\n }\n\n // \u2500\u2500\u2500 Inventory Creation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private async createInventoryFromOrder(\n orderConfig: CpqOrderConfiguration,\n orderLines: CpqOrderLineConfiguration[],\n scope: TenantScope,\n ): Promise<void> {\n if (orderLines.length === 0) return\n\n const specIds = [...new Set(orderLines.map((l) => l.specId).filter(Boolean))] as string[]\n const specs = specIds.length > 0\n ? await this.em.find(CpqProductSpecification, {\n id: { $in: specIds },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n : []\n const specMap = new Map(specs.map((s) => [s.id, s]))\n\n const subscriptionLines = orderLines.filter((l) => {\n const spec = l.specId ? specMap.get(l.specId) : null\n return !spec?.isAssetizable\n })\n const assetLines = orderLines.filter((l) => {\n const spec = l.specId ? specMap.get(l.specId) : null\n return spec?.isAssetizable === true\n })\n\n const hasSubscriptionContent = subscriptionLines.some(\n (l) => Number(l.mrcTotal) > 0 || Number(l.nrcTotal) > 0,\n )\n if (!hasSubscriptionContent && assetLines.length === 0) return\n\n const subscriptionName = await this.buildSubscriptionName(orderConfig, orderLines, scope)\n\n const lineWithDates = orderLines.find((l) => l.startDate != null) ?? orderLines[0]\n const lineWithTerm = orderLines.find((l) => l.termMonths != null) ?? orderLines[0]\n const subscriptionItems = subscriptionLines.map((line) => ({\n productId: line.productId ?? undefined,\n offeringId: line.offeringId ?? undefined,\n specId: line.specId ?? undefined,\n name: this.getLineName(line),\n configuration: line.configuration ?? {},\n charges: (line.charges ?? []) as Array<Record<string, unknown>>,\n mrcAmount: Number(line.mrcTotal),\n nrcAmount: Number(line.nrcTotal),\n currencyCode: orderConfig.currencyCode,\n quantity: line.quantity,\n sourceQuoteLineId: line.sourceQuoteLineId ?? undefined,\n sortOrder: orderLines.indexOf(line),\n }))\n\n const subscription = await this.inventoryService.createSubscription(\n {\n customerId: orderConfig.customerId,\n name: subscriptionName,\n billingCycle: 'monthly',\n currencyCode: orderConfig.currencyCode,\n startDate: lineWithDates?.startDate?.toISOString?.() ?? undefined,\n termMonths: lineWithTerm?.termMonths ?? undefined,\n sourceQuoteId: orderConfig.sourceQuoteId ?? undefined,\n sourceOrderId: orderConfig.id,\n items: subscriptionItems.length > 0\n ? subscriptionItems\n : [{ name: subscriptionName, mrcAmount: 0, nrcAmount: 0 }],\n },\n scope,\n )\n\n const orderLineToSubItem = new Map<string, string>()\n const allSubItems = await this.em.find(CpqInventorySubscriptionItem, {\n subscriptionId: subscription.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, { orderBy: { sortOrder: 'asc' } })\n\n for (let i = 0; i < subscriptionLines.length && i < allSubItems.length; i++) {\n orderLineToSubItem.set(subscriptionLines[i].orderLineId, allSubItems[i].id)\n }\n\n for (let i = 0; i < subscriptionLines.length && i < allSubItems.length; i++) {\n const orderLine = subscriptionLines[i]\n if (orderLine.parentLineId) {\n const parentSubItemId = orderLineToSubItem.get(orderLine.parentLineId)\n if (parentSubItemId) {\n allSubItems[i].parentItemId = parentSubItemId\n }\n }\n }\n await this.em.flush()\n\n for (const line of assetLines) {\n let subscriptionItemId: string | undefined\n if (line.parentLineId) {\n subscriptionItemId = orderLineToSubItem.get(line.parentLineId) ?? undefined\n }\n\n await this.inventoryService.createAsset(\n {\n customerId: orderConfig.customerId,\n subscriptionId: subscription.id,\n subscriptionItemId,\n productId: line.productId ?? undefined,\n offeringId: line.offeringId ?? undefined,\n specId: line.specId ?? undefined,\n name: this.getLineName(line),\n assetType: 'one_time',\n currencyCode: orderConfig.currencyCode,\n purchasePrice: Number(line.nrcTotal),\n quantity: line.quantity,\n purchaseDate: new Date().toISOString().split('T')[0],\n configuration: line.configuration ?? {},\n charges: (line.charges ?? []) as Array<Record<string, unknown>>,\n sourceOrderId: orderConfig.id,\n sourceQuoteLineId: line.sourceQuoteLineId ?? undefined,\n },\n scope,\n )\n }\n }\n\n // \u2500\u2500\u2500 Get / List \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async getOrder(orderId: string, scope: TenantScope): Promise<OrderResult> {\n const em = this.em\n const orderConfig = await this.loadOrderConfig(em, orderId, scope)\n const salesOrder = await this.loadSalesOrder(em, orderConfig.orderId, scope)\n const lines = await em.find(CpqOrderLineConfiguration, {\n orderConfigurationId: orderConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n return this.buildOrderResult(em, orderConfig, salesOrder, lines, scope)\n }\n\n async listOrders(filters: OrderListFilters, scope: TenantScope) {\n const page = Math.max(1, filters.page ?? 1)\n const pageSize = Math.min(100, Math.max(1, filters.pageSize ?? 50))\n const offset = (page - 1) * pageSize\n\n const where: Record<string, unknown> = {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }\n\n if (filters.customerId) where.customerId = filters.customerId\n if (filters.sourceQuoteId) where.sourceQuoteId = filters.sourceQuoteId\n if (filters.salesOrderId) where.orderId = filters.salesOrderId\n if (filters.currencyCode) where.currencyCode = filters.currencyCode\n if (filters.cpqStatus) {\n where.cpqStatus = Array.isArray(filters.cpqStatus)\n ? { $in: filters.cpqStatus }\n : filters.cpqStatus\n }\n\n const search = filters.search?.trim()\n if (search) {\n where.$or = [\n { orderId: { $ilike: `%${search}%` } },\n { customerId: { $ilike: `%${search}%` } },\n ]\n }\n\n const sortField = filters.sortField ?? 'createdAt'\n const sortDir = filters.sortDir === 'asc' ? 'asc' : 'desc'\n\n const [configs, total] = await this.em.findAndCount(\n CpqOrderConfiguration,\n where,\n { limit: pageSize, offset, orderBy: { [sortField]: sortDir } },\n )\n\n const orderIds = configs.map((c) => c.orderId)\n const salesOrders = orderIds.length > 0\n ? await this.em.find(SalesOrder, { id: { $in: orderIds } })\n : []\n const salesOrderMap = new Map(salesOrders.map((o) => [o.id, o]))\n\n const items = configs.map((c) => ({\n ...c,\n orderNumber: salesOrderMap.get(c.orderId)?.orderNumber ?? null,\n }))\n\n return { items, total, page, pageSize, totalPages: Math.ceil(total / pageSize) }\n }\n\n // \u2500\u2500\u2500 Status Transition \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async transitionOrderStatus(orderId: string, targetStatus: string, scope: TenantScope): Promise<OrderResult> {\n const em = this.em\n const orderConfig = await this.loadOrderConfig(em, orderId, scope)\n const salesOrder = await this.loadSalesOrder(em, orderConfig.orderId, scope)\n\n const currentStatus = orderConfig.cpqStatus as CpqOrderStatus\n const allowed = CPQ_ORDER_TRANSITIONS[currentStatus] ?? []\n\n if (!allowed.includes(targetStatus as CpqOrderStatus)) {\n throw new OrderError(409, `Cannot transition from '${currentStatus}' to '${targetStatus}'`)\n }\n\n if (targetStatus === 'active') {\n return this.activateOrder(orderId, scope)\n }\n\n orderConfig.cpqStatus = targetStatus\n salesOrder.status = CPQ_TO_SALES_ORDER_STATUS[targetStatus as CpqOrderStatus] ?? targetStatus\n\n await em.flush()\n\n const lines = await em.find(CpqOrderLineConfiguration, {\n orderConfigurationId: orderConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n return this.buildOrderResult(em, orderConfig, salesOrder, lines, scope)\n }\n\n // \u2500\u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private async loadOrderConfig(em: EntityManager, orderId: string, scope: TenantScope): Promise<CpqOrderConfiguration> {\n let config = await em.findOne(CpqOrderConfiguration, {\n id: orderId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!config) {\n config = await em.findOne(CpqOrderConfiguration, {\n orderId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n }\n if (!config) throw new OrderError(404, 'Order not found')\n return config\n }\n\n private async loadSalesOrder(em: EntityManager, orderId: string, scope: TenantScope): Promise<SalesOrder> {\n const order = await em.findOne(SalesOrder, {\n id: orderId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n if (!order) throw new OrderError(404, 'Sales order not found')\n return order\n }\n\n private async resolveOfferingInfo(\n em: EntityManager,\n offeringId: string | null | undefined,\n scope: TenantScope,\n fallbackConfig?: Record<string, unknown> | null,\n ): Promise<{ name: string; type: string | null }> {\n if (offeringId) {\n const offering = await em.findOne(CpqProductOffering, {\n id: offeringId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (offering) return { name: offering.name, type: offering.offeringType ?? 'simple' }\n }\n const cfg = fallbackConfig ?? null\n const fallbackName =\n (cfg?._arcMirroredName as string | undefined) ??\n (cfg?.offeringName as string | undefined) ??\n 'Configured Item'\n return { name: fallbackName, type: null }\n }\n\n private async resolveOfferingName(\n em: EntityManager,\n offeringId: string | null | undefined,\n scope: TenantScope,\n fallbackConfig?: Record<string, unknown> | null,\n ): Promise<string> {\n const info = await this.resolveOfferingInfo(em, offeringId, scope, fallbackConfig)\n return info.name\n }\n\n private getLineName(line: CpqOrderLineConfiguration): string {\n const config = line.configuration as Record<string, unknown> | null\n return (\n (config?._arcMirroredName as string | undefined) ??\n (config?.offeringName as string | undefined) ??\n (config?.name as string | undefined) ??\n 'Configured Item'\n )\n }\n\n private async buildSubscriptionName(\n orderConfig: CpqOrderConfiguration,\n orderLines: CpqOrderLineConfiguration[],\n scope: TenantScope,\n ): Promise<string> {\n if (orderLines.length === 1 && orderLines[0].offeringId) {\n return this.resolveOfferingName(this.em, orderLines[0].offeringId, scope)\n }\n const names: string[] = []\n for (const line of orderLines.slice(0, 3)) {\n if (line.offeringId) {\n names.push(await this.resolveOfferingName(this.em, line.offeringId, scope))\n }\n }\n if (names.length > 0) {\n const suffix = orderLines.length > 3 ? ` (+${orderLines.length - 3} more)` : ''\n return names.join(', ') + suffix\n }\n return `Order ${orderConfig.orderId.slice(0, 8)}`\n }\n\n private async buildOrderResult(\n em: EntityManager,\n orderConfig: CpqOrderConfiguration,\n salesOrder: SalesOrder,\n lineConfigs: CpqOrderLineConfiguration[],\n scope: TenantScope,\n ): Promise<OrderResult> {\n const lines: OrderLineResult[] = []\n\n // XD-250 ARC: batch-load source subscription items so we can render the\n // before/after diff per line on the order detail page.\n const arcItemIds = new Set<string>()\n for (const lc of lineConfigs) {\n const m = (lc.configuration as Record<string, unknown> | null)?._arcMirroredFromItemId\n if (typeof m === 'string') arcItemIds.add(m)\n }\n const arcItemMap = new Map<string, CpqInventorySubscriptionItem>()\n if (arcItemIds.size > 0) {\n const items = await em.find(CpqInventorySubscriptionItem, {\n id: { $in: Array.from(arcItemIds) },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n for (const it of items) arcItemMap.set(it.id, it)\n }\n\n for (const lc of lineConfigs) {\n const offeringInfo = await this.resolveOfferingInfo(\n em,\n lc.offeringId,\n scope,\n lc.configuration as Record<string, unknown> | null,\n )\n const arcSource = pickArcSourceFromConfig(lc.configuration as Record<string, unknown> | null, arcItemMap)\n lines.push({\n lineId: lc.orderLineId,\n offeringId: lc.offeringId ?? null,\n offeringName: offeringInfo.name,\n offeringType: offeringInfo.type,\n productId: lc.productId ?? null,\n specId: lc.specId ?? null,\n action: lc.action,\n parentLineId: lc.parentLineId ?? null,\n quantity: lc.quantity,\n configuration: lc.configuration ?? {},\n startDate: lc.startDate?.toISOString() ?? null,\n termMonths: lc.termMonths ?? null,\n endDate: lc.endDate?.toISOString() ?? null,\n nrcTotal: Number(lc.nrcTotal),\n mrcTotal: Number(lc.mrcTotal),\n charges: (lc.charges ?? []) as Array<Record<string, unknown>>,\n sourceQuoteLineId: lc.sourceQuoteLineId ?? null,\n arcSource,\n })\n }\n\n // Source quote's quoteType \u2014 surfaced to the order header so the UI can\n // render an AMEND / RENEW / CANCEL badge alongside the order number.\n // CpqOrderConfiguration.sourceQuoteId stores CpqQuoteConfiguration.id\n // (see convertFromConfig \u2014 sourceQuoteId: cpqConfig.id), NOT the\n // SalesQuote.id, so we look it up by `id` rather than by `quoteId`.\n let quoteType = 'new'\n if (orderConfig.sourceQuoteId) {\n const sourceCfg = await em.findOne(CpqQuoteConfiguration, {\n id: orderConfig.sourceQuoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n if (sourceCfg?.quoteType) quoteType = sourceCfg.quoteType\n }\n\n const pricing = orderConfig.pricingSummary ?? {}\n\n return {\n id: orderConfig.id,\n orderId: orderConfig.orderId,\n orderNumber: salesOrder.orderNumber ?? '',\n customerId: orderConfig.customerId,\n cpqStatus: orderConfig.cpqStatus,\n sourceQuoteId: orderConfig.sourceQuoteId ?? null,\n quoteType,\n currencyCode: orderConfig.currencyCode,\n pricingSummary: {\n nrcTotal: Number((pricing as Record<string, unknown>).nrcTotal ?? 0),\n mrcTotal: Number((pricing as Record<string, unknown>).mrcTotal ?? 0),\n currencyCode: orderConfig.currencyCode,\n },\n activatedAt: orderConfig.activatedAt?.toISOString() ?? null,\n createdAt: orderConfig.createdAt.toISOString(),\n lines,\n }\n }\n}\n\nfunction pickArcSourceFromConfig(\n cfg: Record<string, unknown> | null,\n map: Map<string, CpqInventorySubscriptionItem>,\n): OrderLineResult['arcSource'] {\n const m = cfg?._arcMirroredFromItemId\n if (typeof m !== 'string') return null\n const item = map.get(m)\n if (!item) return null\n return {\n subscriptionItemId: item.id,\n name: item.name,\n mrcAmount: Number(item.mrcAmount),\n nrcAmount: Number(item.nrcAmount),\n quantity: item.quantity,\n }\n}\n\n// \u2500\u2500\u2500 Error class \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class OrderError extends Error {\n constructor(\n public status: number,\n message: string,\n ) {\n super(message)\n this.name = 'OrderError'\n }\n}\n\n// \u2500\u2500\u2500 ARC helpers (XD-250) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Build a service-layer ArcLineChange from a CpqQuoteLineConfiguration.\n * For 'add' actions, materializes the itemInput from line + spec data.\n */\nfunction buildArcLineChange(\n line: CpqQuoteLineConfiguration,\n specMap: Map<string, CpqProductSpecification>,\n): ArcLineChange {\n const action = line.action as 'add' | 'modify' | 'cancel'\n if (action === 'add') {\n const itemInput: Omit<CreateSubscriptionItemInput, 'name'> & { name: string } = {\n productId: line.productId ?? undefined,\n offeringId: line.offeringId ?? undefined,\n specId: line.specId ?? undefined,\n name: resolveLineName(line, specMap),\n configuration: line.configuration ?? {},\n charges: (line.charges ?? null) as Array<Record<string, unknown>> | undefined,\n mrcAmount: Number(line.mrcTotal),\n nrcAmount: Number(line.nrcTotal),\n quantity: line.quantity,\n sourceQuoteLineId: line.quoteLineId,\n }\n return {\n quoteLineId: line.quoteLineId,\n action,\n itemInput,\n parentQuoteLineId: line.parentLineId ?? null,\n }\n }\n if (action === 'cancel') {\n return {\n quoteLineId: line.quoteLineId,\n action,\n sourceSubscriptionItemId: line.sourceSubscriptionItemId ?? null,\n }\n }\n // modify\n return {\n quoteLineId: line.quoteLineId,\n action,\n sourceSubscriptionItemId: line.sourceSubscriptionItemId ?? null,\n modifyPatch: {\n configuration: line.configuration ?? undefined,\n charges: (line.charges ?? undefined) as Array<Record<string, unknown>> | undefined,\n mrcAmount: Number(line.mrcTotal),\n nrcAmount: Number(line.nrcTotal),\n quantity: line.quantity,\n },\n }\n}\n\nfunction resolveLineName(\n line: CpqQuoteLineConfiguration,\n specMap: Map<string, CpqProductSpecification>,\n): string {\n const cfg = line.configuration as Record<string, unknown> | null\n const cfgName = (cfg?._arcMirroredName as string | undefined) ?? null\n if (cfgName) return cfgName\n if (line.specId) {\n const spec = specMap.get(line.specId)\n if (spec?.name) return spec.name\n }\n return 'Configured Item'\n}\n\ninterface ArcEventEnvelope {\n organizationId: string\n tenantId: string\n sourceQuoteId: string\n sourceOrderId: string\n}\n\nasync function emitArcEvent(\n eventId:\n | 'cpq.subscription.amended'\n | 'cpq.subscription.renewed'\n | 'cpq.subscription.cancelled',\n result: ApplyArcResult,\n envelope: ArcEventEnvelope & {\n term?: { newTermStart: string; newTermEnd: string }\n etfAmount?: string | null\n etfCurrency?: string | null\n reasonCode?: string | null\n reasonText?: string | null\n },\n): Promise<void> {\n const sub = result.subscription\n await emitCpqEvent(eventId as never, {\n subscriptionId: sub.id,\n customerId: sub.customerId,\n organizationId: envelope.organizationId,\n tenantId: envelope.tenantId,\n timestamp: new Date().toISOString(),\n sourceQuoteId: envelope.sourceQuoteId,\n sourceOrderId: envelope.sourceOrderId,\n performedByUserId: null,\n changeLogId: result.changeLog.id,\n proration: buildProrationPayload(sub, result.changeLog.beforeSnapshot ?? null),\n ...(envelope.term ? { term: envelope.term } : {}),\n ...(envelope.etfAmount !== undefined ? { etfAmount: envelope.etfAmount } : {}),\n ...(envelope.etfCurrency !== undefined ? { etfCurrency: envelope.etfCurrency } : {}),\n ...(envelope.reasonCode !== undefined ? { reasonCode: envelope.reasonCode } : {}),\n ...(envelope.reasonText !== undefined ? { reasonText: envelope.reasonText } : {}),\n } as never)\n}\n\nasync function emitMergedEvent(\n merge: ApplyMergeRenewalResult,\n envelope: ArcEventEnvelope,\n mergedFromSubscriptionIds: string[],\n): Promise<void> {\n const m = merge.mergedSubscription\n await emitCpqEvent('cpq.subscription.merged' as never, {\n subscriptionId: m.id,\n customerId: m.customerId,\n organizationId: envelope.organizationId,\n tenantId: envelope.tenantId,\n timestamp: new Date().toISOString(),\n sourceQuoteId: envelope.sourceQuoteId,\n sourceOrderId: envelope.sourceOrderId,\n performedByUserId: null,\n changeLogId: merge.mergeResultChangeLog.id,\n mergedFromSubscriptionIds,\n term: {\n newTermStart: m.currentTermStart?.toISOString() ?? null,\n newTermEnd: m.currentTermEnd?.toISOString() ?? null,\n newTermMonths: m.termMonths ?? null,\n },\n proration: buildProrationPayload(m, null),\n } as never)\n}\n\nasync function emitSupersededEvent(\n sourceLog: { id: string; subscriptionId: string },\n newMergeSubId: string,\n envelope: ArcEventEnvelope,\n): Promise<void> {\n await emitCpqEvent('cpq.subscription.superseded' as never, {\n subscriptionId: sourceLog.subscriptionId,\n organizationId: envelope.organizationId,\n tenantId: envelope.tenantId,\n timestamp: new Date().toISOString(),\n sourceQuoteId: envelope.sourceQuoteId,\n sourceOrderId: envelope.sourceOrderId,\n performedByUserId: null,\n changeLogId: sourceLog.id,\n mergedIntoSubscriptionId: newMergeSubId,\n } as never)\n}\n\n/**\n * Compute proration payload sent on every ARC subscription event.\n *\n * Currently a placeholder. Proration math against the live billing cycle\n * lives in the billing module \u2014 CPQ's contract is to surface the *inputs*\n * (old/new MRC, cycle bounds) on the event payload so billing can compute\n * the delta. Until billing integration exists, we expose the essentials and\n * leave precise cycle math to follow-up work.\n */\nfunction buildProrationPayload(\n sub: CpqInventorySubscription,\n beforeSnapshot: Record<string, unknown> | null,\n): Record<string, unknown> {\n const oldMrc = beforeSnapshot\n ? Number((beforeSnapshot.mrcAmount as string | undefined) ?? 0)\n : 0\n return {\n oldMrcAmount: oldMrc,\n newMrcAmount: Number(sub.mrcAmount),\n currency: sub.currencyCode,\n billingCycleStart: null,\n billingCycleEnd: null,\n daysElapsedInCycle: null,\n daysRemainingInCycle: null,\n }\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,YAAY,sBAAsB;AAE3C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAQP;AAAA,EACE;AAAA,OAGK;AACP,SAAS,oBAAoB;AAiF7B,MAAM,4BAA4D;AAAA,EAChE,OAAO;AAAA,EACP,oBAAoB;AAAA,EACpB,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,WAAW;AACb;AAIO,MAAM,uBAAuB;AAAA,EAKlC,YAAY,MAAwB;AAClC,SAAK,KAAK,KAAK;AACf,SAAK,mBAAmB,KAAK;AAC7B,SAAK,kBAAkB,KAAK;AAAA,EAC9B;AAAA;AAAA,EAIA,MAAM,oBAAoB,SAAiB,OAA0C;AACnF,UAAM,KAAK,KAAK;AAEhB,UAAM,YAAY,MAAM,GAAG,QAAQ,uBAAuB;AAAA,MACxD,IAAI;AAAA,MACJ,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,MAChB,WAAW;AAAA,IACb,CAAC;AACD,QAAI,CAAC,WAAW;AACd,YAAM,YAAY,MAAM,GAAG,QAAQ,uBAAuB;AAAA,QACxD;AAAA,QACA,gBAAgB,MAAM;AAAA,QACtB,UAAU,MAAM;AAAA,QAChB,WAAW;AAAA,MACb,CAAC;AACD,UAAI,CAAC,UAAW,OAAM,IAAI,WAAW,KAAK,iBAAiB;AAC3D,aAAO,KAAK,kBAAkB,WAAW,KAAK;AAAA,IAChD;AACA,WAAO,KAAK,kBAAkB,WAAW,KAAK;AAAA,EAChD;AAAA,EAEA,MAAc,kBAAkB,WAAkC,OAA0C;AAC1G,UAAM,KAAK,KAAK;AAEhB,UAAM,kBAAkB,CAAC,aAAa,UAAU;AAChD,QAAI,gBAAgB,SAAS,UAAU,SAAS,GAAG;AACjD,YAAM,IAAI,WAAW,KAAK,8BAA8B,UAAU,SAAS,UAAU;AAAA,IACvF;AAMA,UAAM,gBAAgB,MAAM,GAAG,QAAQ,uBAAuB;AAAA,MAC5D,eAAe,UAAU;AAAA,MACzB,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,MAChB,WAAW;AAAA,IACb,CAAC;AACD,QAAI,eAAe;AACjB,YAAM,IAAI;AAAA,QACR;AAAA,QACA,6CAA6C,cAAc,OAAO;AAAA,MACpE;AAAA,IACF;AAEA,UAAM,aAAa,MAAM,GAAG,KAAK,2BAA2B;AAAA,MAC1D,sBAAsB,UAAU;AAAA,MAChC,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,MAChB,WAAW;AAAA,IACb,CAAC;AAED,QAAI,WAAW,WAAW,GAAG;AAC3B,YAAM,IAAI,WAAW,KAAK,2CAA2C;AAAA,IACvE;AAEA,UAAM,EAAE,QAAQ,YAAY,IAAI,MAAM,KAAK,gBAAgB,SAAS;AAAA,MAClE,MAAM;AAAA,MACN,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,IAClB,CAAC;AAED,UAAM,eAAe,OAAO,WAAW;AACvC,UAAM,iBAAiB,UAAU;AACjC,UAAM,WAAW,OAAO,gBAAgB,YAAY,CAAC;AACrD,UAAM,WAAW,OAAO,gBAAgB,YAAY,CAAC;AACrD,UAAM,aAAa,WAAW;AAE9B,UAAM,aAAa,GAAG,OAAO,YAAY;AAAA,MACvC,IAAI;AAAA,MACJ,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,MAChB;AAAA,MACA,kBAAkB,UAAU;AAAA,MAC5B,cAAc,UAAU;AAAA,MACxB,QAAQ;AAAA,MACR,mBAAmB,OAAO,UAAU;AAAA,MACpC,qBAAqB,OAAO,UAAU;AAAA,MACtC,qBAAqB;AAAA,MACrB,gBAAgB;AAAA,MAChB,mBAAmB;AAAA,MACnB,qBAAqB;AAAA,MACrB,sBAAsB;AAAA,MACtB,iBAAiB;AAAA,MACjB,qBAAqB,OAAO,UAAU;AAAA,MACtC,uBAAuB,OAAO,UAAU;AAAA,MACxC,eAAe,WAAW;AAAA,MAC1B,UAAU,EAAE,eAAe,UAAU,GAAG;AAAA,MACxC,WAAW,oBAAI,KAAK;AAAA,MACpB,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAU;AACV,OAAG,QAAQ,UAAU;AAErB,UAAM,mBAAmB,OAAO,WAAW;AAC3C,UAAM,iBAAiB,GAAG,OAAO,uBAAuB;AAAA,MACtD,IAAI;AAAA,MACJ,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,MAChB,SAAS;AAAA,MACT,eAAe,UAAU;AAAA,MACzB,YAAY,UAAU;AAAA,MACtB,WAAW;AAAA,MACX,cAAc,UAAU;AAAA,MACxB,gBAAgB;AAAA,QACd;AAAA,QACA;AAAA,QACA,cAAc,UAAU;AAAA,MAC1B;AAAA,IACF,CAAC;AACD,OAAG,QAAQ,cAAc;AAEzB,UAAM,2BAA2B,oBAAI,IAAoB;AAEzD,aAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK;AAC1C,YAAM,KAAK,WAAW,CAAC;AAEvB,YAAM,iBAAiB,OAAO,GAAG,QAAQ;AACzC,YAAM,iBAAiB,OAAO,GAAG,QAAQ;AACzC,YAAM,gBAAgB,iBAAiB,kBAAkB,GAAG;AAC5D,YAAM,WAAW,iBAAiB;AAElC,YAAM,cAAc,OAAO,WAAW;AACtC,+BAAyB,IAAI,GAAG,aAAa,WAAW;AAExD,YAAM,eAAe,MAAM,KAAK;AAAA,QAC9B;AAAA,QACA,GAAG;AAAA,QACH;AAAA,QACA,GAAG;AAAA,MACL;AAEA,YAAM,YAAY,GAAG,OAAO,gBAAgB;AAAA,QAC1C,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,gBAAgB,MAAM;AAAA,QACtB,UAAU,MAAM;AAAA,QAChB,YAAY,IAAI;AAAA,QAChB,MAAM;AAAA,QACN,WAAW,GAAG,aAAa;AAAA,QAC3B,MAAM;AAAA,QACN,UAAU,OAAO,GAAG,QAAQ;AAAA,QAC5B,cAAc,OAAO,YAAY;AAAA,QACjC,gBAAgB,OAAO,YAAY;AAAA,QACnC,gBAAgB,OAAO,QAAQ;AAAA,QAC/B,kBAAkB,OAAO,QAAQ;AAAA,QACjC,gBAAgB;AAAA,QAChB,iBAAiB;AAAA,QACjB,SAAS;AAAA,QACT,WAAW;AAAA,QACX,cAAc,UAAU;AAAA,QACxB,eAAe;AAAA,UACb,YAAY,GAAG,cAAc;AAAA,UAC7B,QAAQ,GAAG;AAAA,UACX,UAAU;AAAA,UACV,UAAU;AAAA,UACV,cAAc,GAAG,gBAAgB;AAAA,QACnC;AAAA,QACA,oBAAoB,OAAO,GAAG,QAAQ;AAAA,QACtC,kBAAkB;AAAA,QAClB,mBAAmB;AAAA,QACnB,kBAAkB;AAAA,QAClB,kBAAkB;AAAA,QAClB,WAAW,oBAAI,KAAK;AAAA,QACpB,WAAW,oBAAI,KAAK;AAAA,MACtB,CAAU;AACV,SAAG,QAAQ,SAAS;AACpB,YAAM,kBAAkB,GAAG,OAAO,2BAA2B;AAAA,QAC3D,gBAAgB,MAAM;AAAA,QACtB,UAAU,MAAM;AAAA,QAChB;AAAA,QACA,sBAAsB,eAAe;AAAA,QACrC,YAAY,GAAG,cAAc;AAAA,QAC7B,WAAW,GAAG,aAAa;AAAA,QAC3B,QAAQ,GAAG,UAAU;AAAA,QACrB,QAAQ,GAAG;AAAA,QACX,cAAc;AAAA,QACd,WAAW,GAAG;AAAA,QACd,YAAY,GAAG,cAAc;AAAA,QAC7B,SAAS,GAAG;AAAA,QACZ,eAAe,EAAE,GAAG,GAAG,eAAe,aAAa;AAAA,QACnD,UAAU,GAAG;AAAA,QACb,SAAS,GAAG,UAAU,CAAC,GAAG,GAAG,OAAO,IAAI;AAAA,QACxC,UAAU,GAAG;AAAA,QACb,UAAU,GAAG;AAAA,QACb,mBAAmB,GAAG;AAAA,MACxB,CAAC;AACD,SAAG,QAAQ,eAAe;AAAA,IAC5B;AAEA,UAAM,GAAG,MAAM;AAGf,UAAM,mBAAmB,MAAM,GAAG,KAAK,2BAA2B;AAAA,MAChE,sBAAsB,eAAe;AAAA,MACrC,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,IAClB,CAAC;AACD,eAAW,OAAO,kBAAkB;AAClC,UAAI,IAAI,mBAAmB;AACzB,cAAM,WAAW,WAAW,KAAK,CAAC,OAAO,GAAG,gBAAgB,IAAI,iBAAiB;AACjF,YAAI,UAAU,cAAc;AAC1B,gBAAM,eAAe,yBAAyB,IAAI,SAAS,YAAY;AACvE,cAAI,aAAc,KAAI,eAAe;AAAA,QACvC;AAAA,MACF;AAAA,IACF;AAEA,UAAM,GAAG,MAAM;AAEf,WAAO,KAAK,iBAAiB,IAAI,gBAAgB,YAAY,kBAAkB,KAAK;AAAA,EACtF;AAAA;AAAA,EAIA,MAAM,cAAc,SAAiB,OAA0C;AAC7E,UAAM,KAAK,KAAK;AAEhB,UAAM,cAAc,MAAM,KAAK,gBAAgB,IAAI,SAAS,KAAK;AAEjE,UAAM,gBAAgB,YAAY;AAClC,QAAI,kBAAkB,WAAW,kBAAkB,sBAAsB;AACvE,YAAM,IAAI,WAAW,KAAK,6BAA6B,aAAa,UAAU;AAAA,IAChF;AAEA,UAAM,aAAa,MAAM,KAAK,eAAe,IAAI,YAAY,SAAS,KAAK;AAC3E,UAAM,aAAa,MAAM,GAAG,KAAK,2BAA2B;AAAA,MAC1D,sBAAsB,YAAY;AAAA,MAClC,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,MAChB,WAAW;AAAA,IACb,CAAC;AAID,UAAM,cAAc,YAAY,gBAC5B,MAAM,GAAG,QAAQ,uBAAuB;AAAA,MACtC,IAAI,YAAY;AAAA,MAChB,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,MAChB,WAAW;AAAA,IACb,CAAC,IACD;AAEJ,UAAM,YAAY,aAAa,aAAa;AAC5C,UAAM,YAAwC,CAAC;AAE/C,QAAI,cAAc,OAAO;AACvB,YAAM,KAAK,yBAAyB,aAAa,YAAY,KAAK;AAAA,IACpE,OAAO;AACL,gBAAU;AAAA,QACR,GAAI,MAAM,KAAK,cAAc,aAAa,aAAc,YAAY,KAAK;AAAA,MAC3E;AAAA,IACF;AAEA,gBAAY,YAAY;AACxB,gBAAY,cAAc,oBAAI,KAAK;AACnC,eAAW,SAAS;AACpB,eAAW,WAAW,oBAAI,KAAK;AAE/B,UAAM,GAAG,MAAM;AAGf,eAAW,QAAQ,WAAW;AAC5B,UAAI;AACF,cAAM,KAAK;AAAA,MACb,SAAS,KAAK;AAGZ,gBAAQ,MAAM,mCAAmC,GAAG;AAAA,MACtD;AAAA,IACF;AAEA,WAAO,KAAK,iBAAiB,IAAI,aAAa,YAAY,YAAY,KAAK;AAAA,EAC7E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,cACZ,aACA,aACA,YACA,OACqC;AACrC,UAAM,KAAK,KAAK;AAChB,UAAM,YAAY,YAAY;AAG9B,UAAM,UAAU,MAAM,GAAG,KAAK,4BAA4B;AAAA,MACxD,SAAS,YAAY;AAAA,MACrB,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,MAChB,WAAW;AAAA,IACb,CAAC;AACD,QAAI,QAAQ,WAAW,GAAG;AACxB,YAAM,IAAI;AAAA,QACR;AAAA,QACA,aAAa,YAAY,EAAE;AAAA,MAC7B;AAAA,IACF;AAEA,UAAM,YAAY,KAAK;AAOvB,UAAM,mBAAmB,MAAM,GAAG,KAAK,2BAA2B;AAAA,MAChE,sBAAsB,YAAY;AAAA,MAClC,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,MAChB,WAAW;AAAA,IACb,CAAC;AACD,UAAM,gBAAgB,oBAAI,IAAgD;AAC1E,eAAW,QAAQ,kBAAkB;AACnC,YAAM,MAAM,KAAK,wBAAwB;AACzC,YAAM,OAAO,cAAc,IAAI,GAAG,KAAK,CAAC;AACxC,WAAK,KAAK,IAAI;AACd,oBAAc,IAAI,KAAK,IAAI;AAAA,IAC7B;AAGA,UAAM,UAAU;AAAA,MACd,GAAG,IAAI,IAAI,iBAAiB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,MAAmB,QAAQ,CAAC,CAAC,CAAC;AAAA,IACzF;AACA,UAAM,QACJ,QAAQ,SAAS,IACb,MAAM,GAAG,KAAK,yBAAyB;AAAA,MACrC,IAAI,EAAE,KAAK,QAAQ;AAAA,MACnB,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,MAChB,WAAW;AAAA,IACb,CAAC,IACD,CAAC;AACP,UAAM,UAAU,IAAI,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAEnD,UAAM,SAAqC,CAAC;AAC5C,UAAM,oBAAoB;AAAA,MACxB,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,MAChB,eAAe,YAAY;AAAA,MAC3B,eAAe,YAAY;AAAA,IAC7B;AAEA,QAAI,cAAc,SAAS;AACzB,iBAAW,UAAU,SAAS;AAC5B,cAAM,QAAQ,cAAc,IAAI,OAAO,cAAc,KAAK,CAAC;AAC3D,cAAM,SAAS,MAAM,UAAU;AAAA,UAC7B;AAAA,YACE,gBAAgB,OAAO;AAAA,YACvB,eAAe,YAAY;AAAA,YAC3B,eAAe,YAAY;AAAA,YAC3B,mBAAmB;AAAA,YACnB,aAAa,MAAM,IAAI,CAAC,MAAM,mBAAmB,GAAG,OAAO,CAAC;AAAA,UAC9D;AAAA,UACA;AAAA,QACF;AACA,eAAO;AAAA,UAAK,MACV,aAAa,4BAA4B,QAAQ,iBAAiB;AAAA,QACpE;AAAA,MACF;AAAA,IACF,WAAW,cAAc,UAAU;AACjC,iBAAW,UAAU,SAAS;AAC5B,cAAM,SAAS,MAAM,UAAU;AAAA,UAC7B;AAAA,YACE,gBAAgB,OAAO;AAAA,YACvB,eAAe,YAAY;AAAA,YAC3B,eAAe,YAAY;AAAA,YAC3B,mBAAmB;AAAA,YACnB,WAAW,YAAY,gBAAgB;AAAA,YACvC,aAAa,YAAY,kBAAkB;AAAA,YAC3C,YAAY,YAAY,iBAAiB;AAAA,YACzC,YAAY,YAAY,iBAAiB;AAAA,UAC3C;AAAA,UACA;AAAA,QACF;AACA,eAAO;AAAA,UAAK,MACV,aAAa,8BAA8B,QAAQ;AAAA,YACjD,GAAG;AAAA,YACH,WAAW,YAAY,gBAAgB;AAAA,YACvC,aAAa,YAAY,kBAAkB;AAAA,YAC3C,YAAY,YAAY,iBAAiB;AAAA,YACzC,YAAY,YAAY,iBAAiB;AAAA,UAC3C,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF,WAAW,cAAc,SAAS;AAChC,YAAM,aAAa,QAAQ,OAAO,CAAC,MAAM,EAAE,gBAAgB,YAAY;AACvE,YAAM,SAAS,QAAQ,OAAO,CAAC,MAAM,EAAE,gBAAgB,QAAQ;AAE/D,UAAI,WAAW,SAAS,KAAK,OAAO,WAAW,GAAG;AAChD,mBAAW,UAAU,YAAY;AAC/B,cAAI,CAAC,OAAO,gBAAgB,CAAC,OAAO,YAAY;AAC9C,kBAAM,IAAI;AAAA,cACR;AAAA,cACA,2BAA2B,OAAO,EAAE;AAAA,YACtC;AAAA,UACF;AACA,gBAAM,QAAQ,cAAc,IAAI,OAAO,cAAc,KAAK,CAAC;AAC3D,gBAAM,SAAS,MAAM,UAAU;AAAA,YAC7B;AAAA,cACE,gBAAgB,OAAO;AAAA,cACvB,eAAe,YAAY;AAAA,cAC3B,eAAe,YAAY;AAAA,cAC3B,mBAAmB;AAAA,cACnB,MAAM;AAAA,gBACJ,cAAc,OAAO;AAAA,gBACrB,YAAY,OAAO;AAAA,gBACnB,eAAe,OAAO,iBAAiB;AAAA,cACzC;AAAA,cACA,aAAa,MAAM,IAAI,CAAC,MAAM,mBAAmB,GAAG,OAAO,CAAC;AAAA,YAC9D;AAAA,YACA;AAAA,UACF;AACA,iBAAO;AAAA,YAAK,MACV,aAAa,4BAA4B,QAAQ;AAAA,cAC/C,GAAG;AAAA,cACH,MAAM;AAAA,gBACJ,cAAc,OAAO,aAAc,YAAY;AAAA,gBAC/C,YAAY,OAAO,WAAY,YAAY;AAAA,cAC7C;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF,WAAW,OAAO,UAAU,KAAK,WAAW,WAAW,GAAG;AACxD,YAAI,CAAC,YAAY,wBAAwB,CAAC,YAAY,oBAAoB;AACxE,gBAAM,IAAI;AAAA,YACR;AAAA,YACA,qBAAqB,YAAY,EAAE;AAAA,UACrC;AAAA,QACF;AAEA,cAAM,aAAa,cAAc,IAAI,IAAI,KAAK,CAAC;AAC/C,cAAM,QAAQ,MAAM,UAAU;AAAA,UAC5B;AAAA,YACE,WAAW,OAAO,IAAI,CAAC,MAAM,EAAE,cAAc;AAAA,YAC7C,eAAe,YAAY;AAAA,YAC3B,eAAe,YAAY;AAAA,YAC3B,mBAAmB;AAAA,YACnB,MAAM;AAAA,cACJ,cAAc,YAAY;AAAA,cAC1B,YAAY,YAAY;AAAA,cACxB,eAAe,YAAY,yBAAyB;AAAA,YACtD;AAAA,YACA,WAAW;AAAA,cACT,YAAY,YAAY,sBAAsB;AAAA,cAC9C,YAAY,YAAY,sBAAsB;AAAA,YAChD;AAAA,YACA,aAAa,WAAW,IAAI,CAAC,MAAM,mBAAmB,GAAG,OAAO,CAAC;AAAA,UACnE;AAAA,UACA;AAAA,QACF;AAGA,cAAM,4BAA4B,OAAO,IAAI,CAAC,MAAM,EAAE,cAAc;AACpE,eAAO;AAAA,UAAK,MACV,gBAAgB,OAAO,mBAAmB,yBAAyB;AAAA,QACrE;AACA,mBAAW,aAAa,MAAM,kBAAkB;AAC9C,iBAAO;AAAA,YAAK,MACV,oBAAoB,WAAW,MAAM,mBAAmB,IAAI,iBAAiB;AAAA,UAC/E;AAAA,QACF;AAAA,MACF,OAAO;AACL,cAAM,IAAI;AAAA,UACR;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,IACF,OAAO;AACL,YAAM,IAAI,WAAW,KAAK,uBAAuB,SAAS,sBAAsB;AAAA,IAClF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA,EAIA,MAAc,yBACZ,aACA,YACA,OACe;AACf,QAAI,WAAW,WAAW,EAAG;AAE7B,UAAM,UAAU,CAAC,GAAG,IAAI,IAAI,WAAW,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,OAAO,CAAC,CAAC;AAC5E,UAAM,QAAQ,QAAQ,SAAS,IAC3B,MAAM,KAAK,GAAG,KAAK,yBAAyB;AAAA,MAC1C,IAAI,EAAE,KAAK,QAAQ;AAAA,MACnB,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,MAChB,WAAW;AAAA,IACb,CAAC,IACD,CAAC;AACL,UAAM,UAAU,IAAI,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAEnD,UAAM,oBAAoB,WAAW,OAAO,CAAC,MAAM;AACjD,YAAM,OAAO,EAAE,SAAS,QAAQ,IAAI,EAAE,MAAM,IAAI;AAChD,aAAO,CAAC,MAAM;AAAA,IAChB,CAAC;AACD,UAAM,aAAa,WAAW,OAAO,CAAC,MAAM;AAC1C,YAAM,OAAO,EAAE,SAAS,QAAQ,IAAI,EAAE,MAAM,IAAI;AAChD,aAAO,MAAM,kBAAkB;AAAA,IACjC,CAAC;AAED,UAAM,yBAAyB,kBAAkB;AAAA,MAC/C,CAAC,MAAM,OAAO,EAAE,QAAQ,IAAI,KAAK,OAAO,EAAE,QAAQ,IAAI;AAAA,IACxD;AACA,QAAI,CAAC,0BAA0B,WAAW,WAAW,EAAG;AAExD,UAAM,mBAAmB,MAAM,KAAK,sBAAsB,aAAa,YAAY,KAAK;AAExF,UAAM,gBAAgB,WAAW,KAAK,CAAC,MAAM,EAAE,aAAa,IAAI,KAAK,WAAW,CAAC;AACjF,UAAM,eAAe,WAAW,KAAK,CAAC,MAAM,EAAE,cAAc,IAAI,KAAK,WAAW,CAAC;AACjF,UAAM,oBAAoB,kBAAkB,IAAI,CAAC,UAAU;AAAA,MACzD,WAAW,KAAK,aAAa;AAAA,MAC7B,YAAY,KAAK,cAAc;AAAA,MAC/B,QAAQ,KAAK,UAAU;AAAA,MACvB,MAAM,KAAK,YAAY,IAAI;AAAA,MAC3B,eAAe,KAAK,iBAAiB,CAAC;AAAA,MACtC,SAAU,KAAK,WAAW,CAAC;AAAA,MAC3B,WAAW,OAAO,KAAK,QAAQ;AAAA,MAC/B,WAAW,OAAO,KAAK,QAAQ;AAAA,MAC/B,cAAc,YAAY;AAAA,MAC1B,UAAU,KAAK;AAAA,MACf,mBAAmB,KAAK,qBAAqB;AAAA,MAC7C,WAAW,WAAW,QAAQ,IAAI;AAAA,IACpC,EAAE;AAEF,UAAM,eAAe,MAAM,KAAK,iBAAiB;AAAA,MAC/C;AAAA,QACE,YAAY,YAAY;AAAA,QACxB,MAAM;AAAA,QACN,cAAc;AAAA,QACd,cAAc,YAAY;AAAA,QAC1B,WAAW,eAAe,WAAW,cAAc,KAAK;AAAA,QACxD,YAAY,cAAc,cAAc;AAAA,QACxC,eAAe,YAAY,iBAAiB;AAAA,QAC5C,eAAe,YAAY;AAAA,QAC3B,OAAO,kBAAkB,SAAS,IAC9B,oBACA,CAAC,EAAE,MAAM,kBAAkB,WAAW,GAAG,WAAW,EAAE,CAAC;AAAA,MAC7D;AAAA,MACA;AAAA,IACF;AAEA,UAAM,qBAAqB,oBAAI,IAAoB;AACnD,UAAM,cAAc,MAAM,KAAK,GAAG,KAAK,8BAA8B;AAAA,MACnE,gBAAgB,aAAa;AAAA,MAC7B,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,MAChB,WAAW;AAAA,IACb,GAAG,EAAE,SAAS,EAAE,WAAW,MAAM,EAAE,CAAC;AAEpC,aAAS,IAAI,GAAG,IAAI,kBAAkB,UAAU,IAAI,YAAY,QAAQ,KAAK;AAC3E,yBAAmB,IAAI,kBAAkB,CAAC,EAAE,aAAa,YAAY,CAAC,EAAE,EAAE;AAAA,IAC5E;AAEA,aAAS,IAAI,GAAG,IAAI,kBAAkB,UAAU,IAAI,YAAY,QAAQ,KAAK;AAC3E,YAAM,YAAY,kBAAkB,CAAC;AACrC,UAAI,UAAU,cAAc;AAC1B,cAAM,kBAAkB,mBAAmB,IAAI,UAAU,YAAY;AACrE,YAAI,iBAAiB;AACnB,sBAAY,CAAC,EAAE,eAAe;AAAA,QAChC;AAAA,MACF;AAAA,IACF;AACA,UAAM,KAAK,GAAG,MAAM;AAEpB,eAAW,QAAQ,YAAY;AAC7B,UAAI;AACJ,UAAI,KAAK,cAAc;AACrB,6BAAqB,mBAAmB,IAAI,KAAK,YAAY,KAAK;AAAA,MACpE;AAEA,YAAM,KAAK,iBAAiB;AAAA,QAC1B;AAAA,UACE,YAAY,YAAY;AAAA,UACxB,gBAAgB,aAAa;AAAA,UAC7B;AAAA,UACA,WAAW,KAAK,aAAa;AAAA,UAC7B,YAAY,KAAK,cAAc;AAAA,UAC/B,QAAQ,KAAK,UAAU;AAAA,UACvB,MAAM,KAAK,YAAY,IAAI;AAAA,UAC3B,WAAW;AAAA,UACX,cAAc,YAAY;AAAA,UAC1B,eAAe,OAAO,KAAK,QAAQ;AAAA,UACnC,UAAU,KAAK;AAAA,UACf,eAAc,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,UACnD,eAAe,KAAK,iBAAiB,CAAC;AAAA,UACtC,SAAU,KAAK,WAAW,CAAC;AAAA,UAC3B,eAAe,YAAY;AAAA,UAC3B,mBAAmB,KAAK,qBAAqB;AAAA,QAC/C;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAIA,MAAM,SAAS,SAAiB,OAA0C;AACxE,UAAM,KAAK,KAAK;AAChB,UAAM,cAAc,MAAM,KAAK,gBAAgB,IAAI,SAAS,KAAK;AACjE,UAAM,aAAa,MAAM,KAAK,eAAe,IAAI,YAAY,SAAS,KAAK;AAC3E,UAAM,QAAQ,MAAM,GAAG,KAAK,2BAA2B;AAAA,MACrD,sBAAsB,YAAY;AAAA,MAClC,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,MAChB,WAAW;AAAA,IACb,CAAC;AACD,WAAO,KAAK,iBAAiB,IAAI,aAAa,YAAY,OAAO,KAAK;AAAA,EACxE;AAAA,EAEA,MAAM,WAAW,SAA2B,OAAoB;AAC9D,UAAM,OAAO,KAAK,IAAI,GAAG,QAAQ,QAAQ,CAAC;AAC1C,UAAM,WAAW,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,QAAQ,YAAY,EAAE,CAAC;AAClE,UAAM,UAAU,OAAO,KAAK;AAE5B,UAAM,QAAiC;AAAA,MACrC,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,MAChB,WAAW;AAAA,IACb;AAEA,QAAI,QAAQ,WAAY,OAAM,aAAa,QAAQ;AACnD,QAAI,QAAQ,cAAe,OAAM,gBAAgB,QAAQ;AACzD,QAAI,QAAQ,aAAc,OAAM,UAAU,QAAQ;AAClD,QAAI,QAAQ,aAAc,OAAM,eAAe,QAAQ;AACvD,QAAI,QAAQ,WAAW;AACrB,YAAM,YAAY,MAAM,QAAQ,QAAQ,SAAS,IAC7C,EAAE,KAAK,QAAQ,UAAU,IACzB,QAAQ;AAAA,IACd;AAEA,UAAM,SAAS,QAAQ,QAAQ,KAAK;AACpC,QAAI,QAAQ;AACV,YAAM,MAAM;AAAA,QACV,EAAE,SAAS,EAAE,QAAQ,IAAI,MAAM,IAAI,EAAE;AAAA,QACrC,EAAE,YAAY,EAAE,QAAQ,IAAI,MAAM,IAAI,EAAE;AAAA,MAC1C;AAAA,IACF;AAEA,UAAM,YAAY,QAAQ,aAAa;AACvC,UAAM,UAAU,QAAQ,YAAY,QAAQ,QAAQ;AAEpD,UAAM,CAAC,SAAS,KAAK,IAAI,MAAM,KAAK,GAAG;AAAA,MACrC;AAAA,MACA;AAAA,MACA,EAAE,OAAO,UAAU,QAAQ,SAAS,EAAE,CAAC,SAAS,GAAG,QAAQ,EAAE;AAAA,IAC/D;AAEA,UAAM,WAAW,QAAQ,IAAI,CAAC,MAAM,EAAE,OAAO;AAC7C,UAAM,cAAc,SAAS,SAAS,IAClC,MAAM,KAAK,GAAG,KAAK,YAAY,EAAE,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC,IACxD,CAAC;AACL,UAAM,gBAAgB,IAAI,IAAI,YAAY,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAE/D,UAAM,QAAQ,QAAQ,IAAI,CAAC,OAAO;AAAA,MAChC,GAAG;AAAA,MACH,aAAa,cAAc,IAAI,EAAE,OAAO,GAAG,eAAe;AAAA,IAC5D,EAAE;AAEF,WAAO,EAAE,OAAO,OAAO,MAAM,UAAU,YAAY,KAAK,KAAK,QAAQ,QAAQ,EAAE;AAAA,EACjF;AAAA;AAAA,EAIA,MAAM,sBAAsB,SAAiB,cAAsB,OAA0C;AAC3G,UAAM,KAAK,KAAK;AAChB,UAAM,cAAc,MAAM,KAAK,gBAAgB,IAAI,SAAS,KAAK;AACjE,UAAM,aAAa,MAAM,KAAK,eAAe,IAAI,YAAY,SAAS,KAAK;AAE3E,UAAM,gBAAgB,YAAY;AAClC,UAAM,UAAU,sBAAsB,aAAa,KAAK,CAAC;AAEzD,QAAI,CAAC,QAAQ,SAAS,YAA8B,GAAG;AACrD,YAAM,IAAI,WAAW,KAAK,2BAA2B,aAAa,SAAS,YAAY,GAAG;AAAA,IAC5F;AAEA,QAAI,iBAAiB,UAAU;AAC7B,aAAO,KAAK,cAAc,SAAS,KAAK;AAAA,IAC1C;AAEA,gBAAY,YAAY;AACxB,eAAW,SAAS,0BAA0B,YAA8B,KAAK;AAEjF,UAAM,GAAG,MAAM;AAEf,UAAM,QAAQ,MAAM,GAAG,KAAK,2BAA2B;AAAA,MACrD,sBAAsB,YAAY;AAAA,MAClC,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,MAChB,WAAW;AAAA,IACb,CAAC;AACD,WAAO,KAAK,iBAAiB,IAAI,aAAa,YAAY,OAAO,KAAK;AAAA,EACxE;AAAA;AAAA,EAIA,MAAc,gBAAgB,IAAmB,SAAiB,OAAoD;AACpH,QAAI,SAAS,MAAM,GAAG,QAAQ,uBAAuB;AAAA,MACnD,IAAI;AAAA,MACJ,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,MAChB,WAAW;AAAA,IACb,CAAC;AACD,QAAI,CAAC,QAAQ;AACX,eAAS,MAAM,GAAG,QAAQ,uBAAuB;AAAA,QAC/C;AAAA,QACA,gBAAgB,MAAM;AAAA,QACtB,UAAU,MAAM;AAAA,QAChB,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AACA,QAAI,CAAC,OAAQ,OAAM,IAAI,WAAW,KAAK,iBAAiB;AACxD,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,eAAe,IAAmB,SAAiB,OAAyC;AACxG,UAAM,QAAQ,MAAM,GAAG,QAAQ,YAAY;AAAA,MACzC,IAAI;AAAA,MACJ,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,IAClB,CAAC;AACD,QAAI,CAAC,MAAO,OAAM,IAAI,WAAW,KAAK,uBAAuB;AAC7D,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,oBACZ,IACA,YACA,OACA,gBACgD;AAChD,QAAI,YAAY;AACd,YAAM,WAAW,MAAM,GAAG,QAAQ,oBAAoB;AAAA,QACpD,IAAI;AAAA,QACJ,gBAAgB,MAAM;AAAA,QACtB,UAAU,MAAM;AAAA,QAChB,WAAW;AAAA,MACb,CAAC;AACD,UAAI,SAAU,QAAO,EAAE,MAAM,SAAS,MAAM,MAAM,SAAS,gBAAgB,SAAS;AAAA,IACtF;AACA,UAAM,MAAM,kBAAkB;AAC9B,UAAM,eACH,KAAK,oBACL,KAAK,gBACN;AACF,WAAO,EAAE,MAAM,cAAc,MAAM,KAAK;AAAA,EAC1C;AAAA,EAEA,MAAc,oBACZ,IACA,YACA,OACA,gBACiB;AACjB,UAAM,OAAO,MAAM,KAAK,oBAAoB,IAAI,YAAY,OAAO,cAAc;AACjF,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,YAAY,MAAyC;AAC3D,UAAM,SAAS,KAAK;AACpB,WACG,QAAQ,oBACR,QAAQ,gBACR,QAAQ,QACT;AAAA,EAEJ;AAAA,EAEA,MAAc,sBACZ,aACA,YACA,OACiB;AACjB,QAAI,WAAW,WAAW,KAAK,WAAW,CAAC,EAAE,YAAY;AACvD,aAAO,KAAK,oBAAoB,KAAK,IAAI,WAAW,CAAC,EAAE,YAAY,KAAK;AAAA,IAC1E;AACA,UAAM,QAAkB,CAAC;AACzB,eAAW,QAAQ,WAAW,MAAM,GAAG,CAAC,GAAG;AACzC,UAAI,KAAK,YAAY;AACnB,cAAM,KAAK,MAAM,KAAK,oBAAoB,KAAK,IAAI,KAAK,YAAY,KAAK,CAAC;AAAA,MAC5E;AAAA,IACF;AACA,QAAI,MAAM,SAAS,GAAG;AACpB,YAAM,SAAS,WAAW,SAAS,IAAI,MAAM,WAAW,SAAS,CAAC,WAAW;AAC7E,aAAO,MAAM,KAAK,IAAI,IAAI;AAAA,IAC5B;AACA,WAAO,SAAS,YAAY,QAAQ,MAAM,GAAG,CAAC,CAAC;AAAA,EACjD;AAAA,EAEA,MAAc,iBACZ,IACA,aACA,YACA,aACA,OACsB;AACtB,UAAM,QAA2B,CAAC;AAIlC,UAAM,aAAa,oBAAI,IAAY;AACnC,eAAW,MAAM,aAAa;AAC5B,YAAM,IAAK,GAAG,eAAkD;AAChE,UAAI,OAAO,MAAM,SAAU,YAAW,IAAI,CAAC;AAAA,IAC7C;AACA,UAAM,aAAa,oBAAI,IAA0C;AACjE,QAAI,WAAW,OAAO,GAAG;AACvB,YAAM,QAAQ,MAAM,GAAG,KAAK,8BAA8B;AAAA,QACxD,IAAI,EAAE,KAAK,MAAM,KAAK,UAAU,EAAE;AAAA,QAClC,gBAAgB,MAAM;AAAA,QACtB,UAAU,MAAM;AAAA,QAChB,WAAW;AAAA,MACb,CAAC;AACD,iBAAW,MAAM,MAAO,YAAW,IAAI,GAAG,IAAI,EAAE;AAAA,IAClD;AAEA,eAAW,MAAM,aAAa;AAC5B,YAAM,eAAe,MAAM,KAAK;AAAA,QAC9B;AAAA,QACA,GAAG;AAAA,QACH;AAAA,QACA,GAAG;AAAA,MACL;AACA,YAAM,YAAY,wBAAwB,GAAG,eAAiD,UAAU;AACxG,YAAM,KAAK;AAAA,QACT,QAAQ,GAAG;AAAA,QACX,YAAY,GAAG,cAAc;AAAA,QAC7B,cAAc,aAAa;AAAA,QAC3B,cAAc,aAAa;AAAA,QAC3B,WAAW,GAAG,aAAa;AAAA,QAC3B,QAAQ,GAAG,UAAU;AAAA,QACrB,QAAQ,GAAG;AAAA,QACX,cAAc,GAAG,gBAAgB;AAAA,QACjC,UAAU,GAAG;AAAA,QACb,eAAe,GAAG,iBAAiB,CAAC;AAAA,QACpC,WAAW,GAAG,WAAW,YAAY,KAAK;AAAA,QAC1C,YAAY,GAAG,cAAc;AAAA,QAC7B,SAAS,GAAG,SAAS,YAAY,KAAK;AAAA,QACtC,UAAU,OAAO,GAAG,QAAQ;AAAA,QAC5B,UAAU,OAAO,GAAG,QAAQ;AAAA,QAC5B,SAAU,GAAG,WAAW,CAAC;AAAA,QACzB,mBAAmB,GAAG,qBAAqB;AAAA,QAC3C;AAAA,MACF,CAAC;AAAA,IACH;AAOA,QAAI,YAAY;AAChB,QAAI,YAAY,eAAe;AAC7B,YAAM,YAAY,MAAM,GAAG,QAAQ,uBAAuB;AAAA,QACxD,IAAI,YAAY;AAAA,QAChB,gBAAgB,MAAM;AAAA,QACtB,UAAU,MAAM;AAAA,MAClB,CAAC;AACD,UAAI,WAAW,UAAW,aAAY,UAAU;AAAA,IAClD;AAEA,UAAM,UAAU,YAAY,kBAAkB,CAAC;AAE/C,WAAO;AAAA,MACL,IAAI,YAAY;AAAA,MAChB,SAAS,YAAY;AAAA,MACrB,aAAa,WAAW,eAAe;AAAA,MACvC,YAAY,YAAY;AAAA,MACxB,WAAW,YAAY;AAAA,MACvB,eAAe,YAAY,iBAAiB;AAAA,MAC5C;AAAA,MACA,cAAc,YAAY;AAAA,MAC1B,gBAAgB;AAAA,QACd,UAAU,OAAQ,QAAoC,YAAY,CAAC;AAAA,QACnE,UAAU,OAAQ,QAAoC,YAAY,CAAC;AAAA,QACnE,cAAc,YAAY;AAAA,MAC5B;AAAA,MACA,aAAa,YAAY,aAAa,YAAY,KAAK;AAAA,MACvD,WAAW,YAAY,UAAU,YAAY;AAAA,MAC7C;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,wBACP,KACA,KAC8B;AAC9B,QAAM,IAAI,KAAK;AACf,MAAI,OAAO,MAAM,SAAU,QAAO;AAClC,QAAM,OAAO,IAAI,IAAI,CAAC;AACtB,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO;AAAA,IACL,oBAAoB,KAAK;AAAA,IACzB,MAAM,KAAK;AAAA,IACX,WAAW,OAAO,KAAK,SAAS;AAAA,IAChC,WAAW,OAAO,KAAK,SAAS;AAAA,IAChC,UAAU,KAAK;AAAA,EACjB;AACF;AAIO,MAAM,mBAAmB,MAAM;AAAA,EACpC,YACS,QACP,SACA;AACA,UAAM,OAAO;AAHN;AAIP,SAAK,OAAO;AAAA,EACd;AACF;AAQA,SAAS,mBACP,MACA,SACe;AACf,QAAM,SAAS,KAAK;AACpB,MAAI,WAAW,OAAO;AACpB,UAAM,YAA0E;AAAA,MAC9E,WAAW,KAAK,aAAa;AAAA,MAC7B,YAAY,KAAK,cAAc;AAAA,MAC/B,QAAQ,KAAK,UAAU;AAAA,MACvB,MAAM,gBAAgB,MAAM,OAAO;AAAA,MACnC,eAAe,KAAK,iBAAiB,CAAC;AAAA,MACtC,SAAU,KAAK,WAAW;AAAA,MAC1B,WAAW,OAAO,KAAK,QAAQ;AAAA,MAC/B,WAAW,OAAO,KAAK,QAAQ;AAAA,MAC/B,UAAU,KAAK;AAAA,MACf,mBAAmB,KAAK;AAAA,IAC1B;AACA,WAAO;AAAA,MACL,aAAa,KAAK;AAAA,MAClB;AAAA,MACA;AAAA,MACA,mBAAmB,KAAK,gBAAgB;AAAA,IAC1C;AAAA,EACF;AACA,MAAI,WAAW,UAAU;AACvB,WAAO;AAAA,MACL,aAAa,KAAK;AAAA,MAClB;AAAA,MACA,0BAA0B,KAAK,4BAA4B;AAAA,IAC7D;AAAA,EACF;AAEA,SAAO;AAAA,IACL,aAAa,KAAK;AAAA,IAClB;AAAA,IACA,0BAA0B,KAAK,4BAA4B;AAAA,IAC3D,aAAa;AAAA,MACX,eAAe,KAAK,iBAAiB;AAAA,MACrC,SAAU,KAAK,WAAW;AAAA,MAC1B,WAAW,OAAO,KAAK,QAAQ;AAAA,MAC/B,WAAW,OAAO,KAAK,QAAQ;AAAA,MAC/B,UAAU,KAAK;AAAA,IACjB;AAAA,EACF;AACF;AAEA,SAAS,gBACP,MACA,SACQ;AACR,QAAM,MAAM,KAAK;AACjB,QAAM,UAAW,KAAK,oBAA2C;AACjE,MAAI,QAAS,QAAO;AACpB,MAAI,KAAK,QAAQ;AACf,UAAM,OAAO,QAAQ,IAAI,KAAK,MAAM;AACpC,QAAI,MAAM,KAAM,QAAO,KAAK;AAAA,EAC9B;AACA,SAAO;AACT;AASA,eAAe,aACb,SAIA,QACA,UAOe;AACf,QAAM,MAAM,OAAO;AACnB,QAAM,aAAa,SAAkB;AAAA,IACnC,gBAAgB,IAAI;AAAA,IACpB,YAAY,IAAI;AAAA,IAChB,gBAAgB,SAAS;AAAA,IACzB,UAAU,SAAS;AAAA,IACnB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,eAAe,SAAS;AAAA,IACxB,eAAe,SAAS;AAAA,IACxB,mBAAmB;AAAA,IACnB,aAAa,OAAO,UAAU;AAAA,IAC9B,WAAW,sBAAsB,KAAK,OAAO,UAAU,kBAAkB,IAAI;AAAA,IAC7E,GAAI,SAAS,OAAO,EAAE,MAAM,SAAS,KAAK,IAAI,CAAC;AAAA,IAC/C,GAAI,SAAS,cAAc,SAAY,EAAE,WAAW,SAAS,UAAU,IAAI,CAAC;AAAA,IAC5E,GAAI,SAAS,gBAAgB,SAAY,EAAE,aAAa,SAAS,YAAY,IAAI,CAAC;AAAA,IAClF,GAAI,SAAS,eAAe,SAAY,EAAE,YAAY,SAAS,WAAW,IAAI,CAAC;AAAA,IAC/E,GAAI,SAAS,eAAe,SAAY,EAAE,YAAY,SAAS,WAAW,IAAI,CAAC;AAAA,EACjF,CAAU;AACZ;AAEA,eAAe,gBACb,OACA,UACA,2BACe;AACf,QAAM,IAAI,MAAM;AAChB,QAAM,aAAa,2BAAoC;AAAA,IACrD,gBAAgB,EAAE;AAAA,IAClB,YAAY,EAAE;AAAA,IACd,gBAAgB,SAAS;AAAA,IACzB,UAAU,SAAS;AAAA,IACnB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,eAAe,SAAS;AAAA,IACxB,eAAe,SAAS;AAAA,IACxB,mBAAmB;AAAA,IACnB,aAAa,MAAM,qBAAqB;AAAA,IACxC;AAAA,IACA,MAAM;AAAA,MACJ,cAAc,EAAE,kBAAkB,YAAY,KAAK;AAAA,MACnD,YAAY,EAAE,gBAAgB,YAAY,KAAK;AAAA,MAC/C,eAAe,EAAE,cAAc;AAAA,IACjC;AAAA,IACA,WAAW,sBAAsB,GAAG,IAAI;AAAA,EAC1C,CAAU;AACZ;AAEA,eAAe,oBACb,WACA,eACA,UACe;AACf,QAAM,aAAa,+BAAwC;AAAA,IACzD,gBAAgB,UAAU;AAAA,IAC1B,gBAAgB,SAAS;AAAA,IACzB,UAAU,SAAS;AAAA,IACnB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,eAAe,SAAS;AAAA,IACxB,eAAe,SAAS;AAAA,IACxB,mBAAmB;AAAA,IACnB,aAAa,UAAU;AAAA,IACvB,0BAA0B;AAAA,EAC5B,CAAU;AACZ;AAWA,SAAS,sBACP,KACA,gBACyB;AACzB,QAAM,SAAS,iBACX,OAAQ,eAAe,aAAoC,CAAC,IAC5D;AACJ,SAAO;AAAA,IACL,cAAc;AAAA,IACd,cAAc,OAAO,IAAI,SAAS;AAAA,IAClC,UAAU,IAAI;AAAA,IACd,mBAAmB;AAAA,IACnB,iBAAiB;AAAA,IACjB,oBAAoB;AAAA,IACpB,sBAAsB;AAAA,EACxB;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { CpqProductCharge, CpqPricingTable, CpqPricingTableEntry, CpqPriceRule } from "../data/entities.js";
|
|
2
|
+
import { getBaseCurrencyCode } from "./types.js";
|
|
3
|
+
function evaluateApplicability(condition, configuration) {
|
|
4
|
+
if (!condition) return true;
|
|
5
|
+
const cond = condition;
|
|
6
|
+
if (!cond.attribute || !cond.operator) return true;
|
|
7
|
+
const configValue = String(configuration[cond.attribute] ?? "");
|
|
8
|
+
const conditionValue = String(cond.value ?? "");
|
|
9
|
+
if (cond.operator === "eq") return configValue === conditionValue;
|
|
10
|
+
if (cond.operator === "neq") return configValue !== conditionValue;
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
function matchEntry(entries, dimensions, configuration) {
|
|
14
|
+
return entries.find(
|
|
15
|
+
(entry) => dimensions.every((dim) => {
|
|
16
|
+
const configVal = String(configuration[dim.key] ?? "");
|
|
17
|
+
const entryVal = String(entry.dimensionValues[dim.key] ?? "");
|
|
18
|
+
return configVal.toLowerCase() === entryVal.toLowerCase();
|
|
19
|
+
})
|
|
20
|
+
) ?? null;
|
|
21
|
+
}
|
|
22
|
+
class DefaultCpqPricingService {
|
|
23
|
+
constructor(em) {
|
|
24
|
+
this.em = em;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Resolve charges for an offering (v2) or product (v1 fallback).
|
|
28
|
+
* When offeringId is provided, charges are loaded by offeringId.
|
|
29
|
+
* When only productId is provided, falls back to loading by productId.
|
|
30
|
+
*/
|
|
31
|
+
async resolveProductCharges(params) {
|
|
32
|
+
const { offeringId, productId, configuration, tenantId, organizationId, currencyCode } = params;
|
|
33
|
+
const chargeFilter = {
|
|
34
|
+
tenantId,
|
|
35
|
+
organizationId,
|
|
36
|
+
isActive: true,
|
|
37
|
+
deletedAt: null
|
|
38
|
+
};
|
|
39
|
+
if (offeringId) {
|
|
40
|
+
chargeFilter.offeringId = offeringId;
|
|
41
|
+
} else if (productId) {
|
|
42
|
+
chargeFilter.productId = productId;
|
|
43
|
+
} else {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
const charges = await this.em.find(CpqProductCharge, chargeFilter, {
|
|
47
|
+
orderBy: { sortOrder: "asc" }
|
|
48
|
+
});
|
|
49
|
+
const applicableCharges = charges.filter(
|
|
50
|
+
(charge) => evaluateApplicability(charge.applicabilityCondition, configuration)
|
|
51
|
+
);
|
|
52
|
+
const results = [];
|
|
53
|
+
for (const charge of applicableCharges) {
|
|
54
|
+
const resolved = await this.calculateCharge({
|
|
55
|
+
charge,
|
|
56
|
+
configuration,
|
|
57
|
+
tenantId,
|
|
58
|
+
organizationId,
|
|
59
|
+
currencyCode
|
|
60
|
+
});
|
|
61
|
+
if (currencyCode) {
|
|
62
|
+
resolved.currencyCode = currencyCode;
|
|
63
|
+
}
|
|
64
|
+
resolved.adjustments = [];
|
|
65
|
+
results.push(resolved);
|
|
66
|
+
}
|
|
67
|
+
const rules = await this.loadPriceRules({
|
|
68
|
+
offeringId: offeringId ?? null,
|
|
69
|
+
tenantId,
|
|
70
|
+
organizationId
|
|
71
|
+
});
|
|
72
|
+
if (rules.length > 0) {
|
|
73
|
+
this.applyPriceRules(results, rules, configuration);
|
|
74
|
+
}
|
|
75
|
+
return results;
|
|
76
|
+
}
|
|
77
|
+
async loadPriceRules(params) {
|
|
78
|
+
const { offeringId, tenantId, organizationId } = params;
|
|
79
|
+
const rules = await this.em.find(
|
|
80
|
+
CpqPriceRule,
|
|
81
|
+
{
|
|
82
|
+
tenantId,
|
|
83
|
+
organizationId,
|
|
84
|
+
isActive: true,
|
|
85
|
+
deletedAt: null,
|
|
86
|
+
$or: [
|
|
87
|
+
{ productOfferingId: null },
|
|
88
|
+
...offeringId ? [{ productOfferingId: offeringId }] : []
|
|
89
|
+
]
|
|
90
|
+
},
|
|
91
|
+
{ orderBy: { sortOrder: "asc" } }
|
|
92
|
+
);
|
|
93
|
+
return rules;
|
|
94
|
+
}
|
|
95
|
+
applyPriceRules(charges, rules, configuration) {
|
|
96
|
+
for (const rule of rules) {
|
|
97
|
+
if (!evaluateApplicability(rule.applicabilityCondition, configuration)) continue;
|
|
98
|
+
for (const charge of charges) {
|
|
99
|
+
if (rule.chargeCodeFilter && rule.chargeCodeFilter !== charge.chargeCode) continue;
|
|
100
|
+
if (rule.chargeTypeFilter && rule.chargeTypeFilter !== charge.chargeType) continue;
|
|
101
|
+
const unitPriceBefore = charge.unitPrice;
|
|
102
|
+
const ruleValue = Number(rule.value);
|
|
103
|
+
let unitPriceAfter;
|
|
104
|
+
let totalPriceOverride;
|
|
105
|
+
switch (rule.ruleType) {
|
|
106
|
+
case "discount_percent":
|
|
107
|
+
unitPriceAfter = Math.max(0, unitPriceBefore * (1 - ruleValue / 100));
|
|
108
|
+
break;
|
|
109
|
+
case "discount_absolute": {
|
|
110
|
+
const currentTotal = charge.totalPrice ?? unitPriceBefore;
|
|
111
|
+
totalPriceOverride = Math.max(0, currentTotal - ruleValue);
|
|
112
|
+
const qty = charge.quantity && charge.quantity > 0 ? charge.quantity : 1;
|
|
113
|
+
unitPriceAfter = totalPriceOverride / qty;
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
case "surcharge_percent":
|
|
117
|
+
unitPriceAfter = unitPriceBefore * (1 + ruleValue / 100);
|
|
118
|
+
break;
|
|
119
|
+
case "surcharge_absolute": {
|
|
120
|
+
const currentTotal = charge.totalPrice ?? unitPriceBefore;
|
|
121
|
+
totalPriceOverride = currentTotal + ruleValue;
|
|
122
|
+
const qty = charge.quantity && charge.quantity > 0 ? charge.quantity : 1;
|
|
123
|
+
unitPriceAfter = totalPriceOverride / qty;
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
case "price_override":
|
|
127
|
+
unitPriceAfter = ruleValue;
|
|
128
|
+
break;
|
|
129
|
+
default:
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
charge.unitPrice = unitPriceAfter;
|
|
133
|
+
if (charge.chargeType === "usage") {
|
|
134
|
+
} else if (totalPriceOverride !== void 0) {
|
|
135
|
+
charge.totalPrice = totalPriceOverride;
|
|
136
|
+
} else if (charge.quantity !== null) {
|
|
137
|
+
charge.totalPrice = unitPriceAfter * charge.quantity;
|
|
138
|
+
} else {
|
|
139
|
+
charge.totalPrice = unitPriceAfter;
|
|
140
|
+
}
|
|
141
|
+
const adjustment = {
|
|
142
|
+
ruleCode: rule.code,
|
|
143
|
+
ruleName: rule.name,
|
|
144
|
+
ruleType: rule.ruleType,
|
|
145
|
+
value: ruleValue,
|
|
146
|
+
unitPriceBefore,
|
|
147
|
+
unitPriceAfter,
|
|
148
|
+
delta: unitPriceAfter - unitPriceBefore
|
|
149
|
+
};
|
|
150
|
+
if (!charge.adjustments) {
|
|
151
|
+
charge.adjustments = [adjustment];
|
|
152
|
+
} else {
|
|
153
|
+
charge.adjustments.push(adjustment);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
async calculateCharge(params) {
|
|
159
|
+
const { charge, configuration, tenantId, organizationId, currencyCode } = params;
|
|
160
|
+
const method = charge.pricingMethod === "fixed" ? "flat" : charge.pricingMethod;
|
|
161
|
+
if (charge.fixedPrice && !charge.pricingTableId) {
|
|
162
|
+
const unitPrice = Number(charge.fixedPrice);
|
|
163
|
+
return {
|
|
164
|
+
chargeCode: charge.code,
|
|
165
|
+
chargeName: charge.name,
|
|
166
|
+
chargeType: charge.chargeType,
|
|
167
|
+
pricingMethod: method,
|
|
168
|
+
unitPrice,
|
|
169
|
+
quantity: 1,
|
|
170
|
+
totalPrice: unitPrice,
|
|
171
|
+
currencyCode: charge.currencyCode ?? await getBaseCurrencyCode(this.em, { tenantId, organizationId })
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
const fallbackCurrency = currencyCode ?? charge.currencyCode ?? await getBaseCurrencyCode(this.em, { tenantId, organizationId });
|
|
175
|
+
const base = {
|
|
176
|
+
chargeCode: charge.code,
|
|
177
|
+
chargeName: charge.name,
|
|
178
|
+
chargeType: charge.chargeType,
|
|
179
|
+
pricingMethod: method,
|
|
180
|
+
unitPrice: 0,
|
|
181
|
+
quantity: 1,
|
|
182
|
+
totalPrice: 0,
|
|
183
|
+
currencyCode: fallbackCurrency
|
|
184
|
+
};
|
|
185
|
+
if (!charge.pricingTableId) return base;
|
|
186
|
+
const table = await this.em.findOne(CpqPricingTable, {
|
|
187
|
+
id: charge.pricingTableId,
|
|
188
|
+
tenantId,
|
|
189
|
+
organizationId
|
|
190
|
+
});
|
|
191
|
+
if (!table) return base;
|
|
192
|
+
const entryFilters = {
|
|
193
|
+
pricingTableId: table.id,
|
|
194
|
+
tenantId,
|
|
195
|
+
organizationId,
|
|
196
|
+
isActive: true,
|
|
197
|
+
deletedAt: null
|
|
198
|
+
};
|
|
199
|
+
if (currencyCode) {
|
|
200
|
+
entryFilters.currencyCode = currencyCode;
|
|
201
|
+
}
|
|
202
|
+
const entries = await this.em.find(CpqPricingTableEntry, entryFilters);
|
|
203
|
+
const priceKey = charge.priceColumnKey ?? "";
|
|
204
|
+
if (method === "flat") {
|
|
205
|
+
return this.calculateFlat(base, charge, entries, table.dimensions, configuration, priceKey);
|
|
206
|
+
}
|
|
207
|
+
if (method === "per_unit") {
|
|
208
|
+
return this.calculatePerUnit(base, charge, entries, table.dimensions, configuration, priceKey);
|
|
209
|
+
}
|
|
210
|
+
if (method === "tiered") {
|
|
211
|
+
return this.calculateTiered(base, charge, entries, configuration, priceKey);
|
|
212
|
+
}
|
|
213
|
+
return base;
|
|
214
|
+
}
|
|
215
|
+
calculateFlat(base, charge, entries, dimensions, configuration, priceKey) {
|
|
216
|
+
const entry = matchEntry(entries, dimensions, configuration);
|
|
217
|
+
if (!entry) return base;
|
|
218
|
+
const unitPrice = entry.prices[priceKey] ?? 0;
|
|
219
|
+
if (charge.chargeType === "usage") {
|
|
220
|
+
return {
|
|
221
|
+
...base,
|
|
222
|
+
unitPrice,
|
|
223
|
+
quantity: null,
|
|
224
|
+
totalPrice: null,
|
|
225
|
+
currencyCode: entry.currencyCode,
|
|
226
|
+
note: charge.description ?? "Usage-based charge \u2014 billed on actual consumption."
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
return { ...base, unitPrice, quantity: 1, totalPrice: unitPrice, currencyCode: entry.currencyCode };
|
|
230
|
+
}
|
|
231
|
+
calculatePerUnit(base, charge, entries, dimensions, configuration, priceKey) {
|
|
232
|
+
const entry = matchEntry(entries, dimensions, configuration);
|
|
233
|
+
if (!entry) return base;
|
|
234
|
+
const unitPrice = entry.prices[priceKey] ?? 0;
|
|
235
|
+
const entryCurrency = entry.currencyCode;
|
|
236
|
+
if (charge.chargeType === "usage") {
|
|
237
|
+
return {
|
|
238
|
+
...base,
|
|
239
|
+
unitPrice,
|
|
240
|
+
quantity: null,
|
|
241
|
+
totalPrice: null,
|
|
242
|
+
currencyCode: entryCurrency,
|
|
243
|
+
note: charge.description ?? "Usage-based charge \u2014 billed on actual consumption."
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
const quantity = Number(configuration[charge.quantityAttributeCode ?? ""] ?? 0);
|
|
247
|
+
return { ...base, unitPrice, quantity, totalPrice: unitPrice * quantity, currencyCode: entryCurrency };
|
|
248
|
+
}
|
|
249
|
+
calculateTiered(base, charge, entries, configuration, priceKey) {
|
|
250
|
+
const quantity = Number(configuration[charge.quantityAttributeCode ?? ""] ?? 0);
|
|
251
|
+
if (quantity <= 0) return { ...base, quantity: 0, totalPrice: 0 };
|
|
252
|
+
const sorted = [...entries].sort((a, b) => (a.tierNumber ?? 0) - (b.tierNumber ?? 0));
|
|
253
|
+
let allocated = 0;
|
|
254
|
+
let total = 0;
|
|
255
|
+
const tiers = [];
|
|
256
|
+
let entryCurrency = base.currencyCode;
|
|
257
|
+
for (const entry of sorted) {
|
|
258
|
+
if (allocated >= quantity) break;
|
|
259
|
+
const to = entry.rangeTo ? Number(entry.rangeTo) : Infinity;
|
|
260
|
+
const tierCeil = to === Infinity ? quantity : Math.min(to, quantity);
|
|
261
|
+
const qty = tierCeil - allocated;
|
|
262
|
+
if (qty <= 0) continue;
|
|
263
|
+
const price = entry.prices[priceKey] ?? 0;
|
|
264
|
+
entryCurrency = entry.currencyCode;
|
|
265
|
+
tiers.push({
|
|
266
|
+
tier: entry.tierNumber ?? 0,
|
|
267
|
+
from: allocated + 1,
|
|
268
|
+
to: allocated + qty,
|
|
269
|
+
pricePerUnit: price,
|
|
270
|
+
quantity: qty,
|
|
271
|
+
subtotal: qty * price
|
|
272
|
+
});
|
|
273
|
+
total += qty * price;
|
|
274
|
+
allocated += qty;
|
|
275
|
+
}
|
|
276
|
+
return {
|
|
277
|
+
...base,
|
|
278
|
+
unitPrice: quantity > 0 ? total / quantity : 0,
|
|
279
|
+
quantity,
|
|
280
|
+
totalPrice: total,
|
|
281
|
+
breakdown: { tiers },
|
|
282
|
+
currencyCode: entryCurrency
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
export {
|
|
287
|
+
DefaultCpqPricingService
|
|
288
|
+
};
|
|
289
|
+
//# sourceMappingURL=cpqPricingService.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/cpq/services/cpqPricingService.ts"],
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { CpqProductCharge, CpqPricingTable, CpqPricingTableEntry, CpqPriceRule } from '../data/entities'\nimport type { ResolvedCharge, RuleAdjustment, TierBreakdown } from './types'\nimport { getBaseCurrencyCode } from './types'\n\nexport type { ResolvedCharge, RuleAdjustment, TierBreakdown }\n\nexport interface QuotePricingSummary {\n lines: Array<{\n lineId: string\n productId: string\n charges: ResolvedCharge[]\n }>\n totals: {\n nrcTotal: number\n mrcTotal: number\n usageCharges: Array<{ chargeCode: string; unitPrice: number; note: string }>\n }\n currencyCode: string\n}\n\ninterface ApplicabilityCondition {\n attribute: string\n operator: 'eq' | 'neq'\n value: string\n}\n\nfunction evaluateApplicability(\n condition: Record<string, unknown> | null | undefined,\n configuration: Record<string, unknown>,\n): boolean {\n if (!condition) return true\n const cond = condition as unknown as ApplicabilityCondition\n if (!cond.attribute || !cond.operator) return true\n const configValue = String(configuration[cond.attribute] ?? '')\n const conditionValue = String(cond.value ?? '')\n if (cond.operator === 'eq') return configValue === conditionValue\n if (cond.operator === 'neq') return configValue !== conditionValue\n return true\n}\n\nfunction matchEntry(\n entries: CpqPricingTableEntry[],\n dimensions: Array<{ key: string }>,\n configuration: Record<string, unknown>,\n): CpqPricingTableEntry | null {\n return (\n entries.find((entry) =>\n dimensions.every((dim) => {\n const configVal = String(configuration[dim.key] ?? '')\n const entryVal = String(entry.dimensionValues[dim.key] ?? '')\n return configVal.toLowerCase() === entryVal.toLowerCase()\n }),\n ) ?? null\n )\n}\n\nexport class DefaultCpqPricingService {\n private em: EntityManager\n\n constructor(em: EntityManager) {\n this.em = em\n }\n\n /**\n * Resolve charges for an offering (v2) or product (v1 fallback).\n * When offeringId is provided, charges are loaded by offeringId.\n * When only productId is provided, falls back to loading by productId.\n */\n async resolveProductCharges(params: {\n offeringId?: string | null\n productId?: string | null\n configuration: Record<string, unknown>\n currencyCode?: string\n tenantId: string\n organizationId: string\n }): Promise<ResolvedCharge[]> {\n const { offeringId, productId, configuration, tenantId, organizationId, currencyCode } = params\n\n const chargeFilter: Record<string, unknown> = {\n tenantId,\n organizationId,\n isActive: true,\n deletedAt: null,\n }\n\n if (offeringId) {\n chargeFilter.offeringId = offeringId\n } else if (productId) {\n chargeFilter.productId = productId\n } else {\n return []\n }\n\n const charges = await this.em.find(CpqProductCharge, chargeFilter, {\n orderBy: { sortOrder: 'asc' },\n })\n\n const applicableCharges = charges.filter((charge) =>\n evaluateApplicability(charge.applicabilityCondition, configuration),\n )\n\n const results: ResolvedCharge[] = []\n for (const charge of applicableCharges) {\n const resolved = await this.calculateCharge({\n charge,\n configuration,\n tenantId,\n organizationId,\n currencyCode,\n })\n // R-CPRICE-8: quote-level currency overrides entry-level currency for consistency.\n // Entry filtering by currencyCode (line 274) ensures price values already match.\n if (currencyCode) {\n resolved.currencyCode = currencyCode\n }\n resolved.adjustments = []\n results.push(resolved)\n }\n\n const rules = await this.loadPriceRules({\n offeringId: offeringId ?? null,\n tenantId,\n organizationId,\n })\n\n if (rules.length > 0) {\n this.applyPriceRules(results, rules, configuration)\n }\n\n return results\n }\n\n private async loadPriceRules(params: {\n offeringId: string | null | undefined\n tenantId: string\n organizationId: string\n }): Promise<CpqPriceRule[]> {\n const { offeringId, tenantId, organizationId } = params\n\n const rules = await this.em.find(\n CpqPriceRule,\n {\n tenantId,\n organizationId,\n isActive: true,\n deletedAt: null,\n $or: [\n { productOfferingId: null },\n ...(offeringId ? [{ productOfferingId: offeringId }] : []),\n ],\n },\n { orderBy: { sortOrder: 'asc' } },\n )\n\n return rules\n }\n\n private applyPriceRules(\n charges: ResolvedCharge[],\n rules: CpqPriceRule[],\n configuration: Record<string, unknown>,\n ): void {\n for (const rule of rules) {\n if (!evaluateApplicability(rule.applicabilityCondition, configuration)) continue\n\n for (const charge of charges) {\n if (rule.chargeCodeFilter && rule.chargeCodeFilter !== charge.chargeCode) continue\n if (rule.chargeTypeFilter && rule.chargeTypeFilter !== charge.chargeType) continue\n\n const unitPriceBefore = charge.unitPrice\n const ruleValue = Number(rule.value)\n let unitPriceAfter: number\n let totalPriceOverride: number | undefined\n\n switch (rule.ruleType) {\n case 'discount_percent':\n unitPriceAfter = Math.max(0, unitPriceBefore * (1 - ruleValue / 100))\n break\n case 'discount_absolute': {\n const currentTotal = charge.totalPrice ?? unitPriceBefore\n totalPriceOverride = Math.max(0, currentTotal - ruleValue)\n const qty = charge.quantity && charge.quantity > 0 ? charge.quantity : 1\n unitPriceAfter = totalPriceOverride / qty\n break\n }\n case 'surcharge_percent':\n unitPriceAfter = unitPriceBefore * (1 + ruleValue / 100)\n break\n case 'surcharge_absolute': {\n const currentTotal = charge.totalPrice ?? unitPriceBefore\n totalPriceOverride = currentTotal + ruleValue\n const qty = charge.quantity && charge.quantity > 0 ? charge.quantity : 1\n unitPriceAfter = totalPriceOverride / qty\n break\n }\n case 'price_override':\n unitPriceAfter = ruleValue\n break\n default:\n continue\n }\n\n charge.unitPrice = unitPriceAfter\n\n if (charge.chargeType === 'usage') {\n // totalPrice stays null for usage charges\n } else if (totalPriceOverride !== undefined) {\n charge.totalPrice = totalPriceOverride\n } else if (charge.quantity !== null) {\n charge.totalPrice = unitPriceAfter * charge.quantity\n } else {\n charge.totalPrice = unitPriceAfter\n }\n\n const adjustment: RuleAdjustment = {\n ruleCode: rule.code,\n ruleName: rule.name,\n ruleType: rule.ruleType,\n value: ruleValue,\n unitPriceBefore,\n unitPriceAfter,\n delta: unitPriceAfter - unitPriceBefore,\n }\n\n if (!charge.adjustments) {\n charge.adjustments = [adjustment]\n } else {\n charge.adjustments.push(adjustment)\n }\n }\n }\n }\n\n async calculateCharge(params: {\n charge: CpqProductCharge\n configuration: Record<string, unknown>\n tenantId: string\n organizationId: string\n currencyCode?: string\n }): Promise<ResolvedCharge> {\n const { charge, configuration, tenantId, organizationId, currencyCode } = params\n\n // `fixed` is a legacy alias for `flat` \u2014 older seeds emit it directly\n // and ~30+ rows in prod still carry it. Treat them identically.\n const method = charge.pricingMethod === 'fixed' ? 'flat' : charge.pricingMethod\n\n // If charge has a fixed price and no pricing table, use fixed price directly\n if (charge.fixedPrice && !charge.pricingTableId) {\n const unitPrice = Number(charge.fixedPrice)\n return {\n chargeCode: charge.code,\n chargeName: charge.name,\n chargeType: charge.chargeType as ResolvedCharge['chargeType'],\n pricingMethod: method as ResolvedCharge['pricingMethod'],\n unitPrice,\n quantity: 1,\n totalPrice: unitPrice,\n currencyCode: charge.currencyCode ?? await getBaseCurrencyCode(this.em, { tenantId, organizationId }),\n }\n }\n\n const fallbackCurrency = currencyCode ?? charge.currencyCode ?? await getBaseCurrencyCode(this.em, { tenantId, organizationId })\n const base: ResolvedCharge = {\n chargeCode: charge.code,\n chargeName: charge.name,\n chargeType: charge.chargeType as ResolvedCharge['chargeType'],\n pricingMethod: method as ResolvedCharge['pricingMethod'],\n unitPrice: 0,\n quantity: 1,\n totalPrice: 0,\n currencyCode: fallbackCurrency,\n }\n\n if (!charge.pricingTableId) return base\n\n const table = await this.em.findOne(CpqPricingTable, {\n id: charge.pricingTableId,\n tenantId,\n organizationId,\n })\n if (!table) return base\n\n const entryFilters: Record<string, unknown> = {\n pricingTableId: table.id,\n tenantId,\n organizationId,\n isActive: true,\n deletedAt: null,\n }\n if (currencyCode) {\n entryFilters.currencyCode = currencyCode\n }\n\n const entries = await this.em.find(CpqPricingTableEntry, entryFilters)\n\n const priceKey = charge.priceColumnKey ?? ''\n\n if (method === 'flat') {\n return this.calculateFlat(base, charge, entries, table.dimensions, configuration, priceKey)\n }\n if (method === 'per_unit') {\n return this.calculatePerUnit(base, charge, entries, table.dimensions, configuration, priceKey)\n }\n if (method === 'tiered') {\n return this.calculateTiered(base, charge, entries, configuration, priceKey)\n }\n\n return base\n }\n\n private calculateFlat(\n base: ResolvedCharge,\n charge: CpqProductCharge,\n entries: CpqPricingTableEntry[],\n dimensions: Array<{ key: string }>,\n configuration: Record<string, unknown>,\n priceKey: string,\n ): ResolvedCharge {\n const entry = matchEntry(entries, dimensions, configuration)\n if (!entry) return base\n const unitPrice = entry.prices[priceKey] ?? 0\n\n if (charge.chargeType === 'usage') {\n return {\n ...base,\n unitPrice,\n quantity: null,\n totalPrice: null,\n currencyCode: entry.currencyCode,\n note: charge.description ?? 'Usage-based charge \u2014 billed on actual consumption.',\n }\n }\n\n return { ...base, unitPrice, quantity: 1, totalPrice: unitPrice, currencyCode: entry.currencyCode }\n }\n\n private calculatePerUnit(\n base: ResolvedCharge,\n charge: CpqProductCharge,\n entries: CpqPricingTableEntry[],\n dimensions: Array<{ key: string }>,\n configuration: Record<string, unknown>,\n priceKey: string,\n ): ResolvedCharge {\n const entry = matchEntry(entries, dimensions, configuration)\n if (!entry) return base\n const unitPrice = entry.prices[priceKey] ?? 0\n const entryCurrency = entry.currencyCode\n\n if (charge.chargeType === 'usage') {\n return {\n ...base,\n unitPrice,\n quantity: null,\n totalPrice: null,\n currencyCode: entryCurrency,\n note: charge.description ?? 'Usage-based charge \u2014 billed on actual consumption.',\n }\n }\n\n const quantity = Number(configuration[charge.quantityAttributeCode ?? ''] ?? 0)\n return { ...base, unitPrice, quantity, totalPrice: unitPrice * quantity, currencyCode: entryCurrency }\n }\n\n private calculateTiered(\n base: ResolvedCharge,\n charge: CpqProductCharge,\n entries: CpqPricingTableEntry[],\n configuration: Record<string, unknown>,\n priceKey: string,\n ): ResolvedCharge {\n const quantity = Number(configuration[charge.quantityAttributeCode ?? ''] ?? 0)\n if (quantity <= 0) return { ...base, quantity: 0, totalPrice: 0 }\n\n const sorted = [...entries].sort((a, b) => (a.tierNumber ?? 0) - (b.tierNumber ?? 0))\n\n let allocated = 0\n let total = 0\n const tiers: TierBreakdown['tiers'] = []\n let entryCurrency = base.currencyCode\n\n for (const entry of sorted) {\n if (allocated >= quantity) break\n const to = entry.rangeTo ? Number(entry.rangeTo) : Infinity\n const tierCeil = to === Infinity ? quantity : Math.min(to, quantity)\n const qty = tierCeil - allocated\n if (qty <= 0) continue\n const price = entry.prices[priceKey] ?? 0\n entryCurrency = entry.currencyCode\n tiers.push({\n tier: entry.tierNumber ?? 0,\n from: allocated + 1,\n to: allocated + qty,\n pricePerUnit: price,\n quantity: qty,\n subtotal: qty * price,\n })\n total += qty * price\n allocated += qty\n }\n\n return {\n ...base,\n unitPrice: quantity > 0 ? total / quantity : 0,\n quantity,\n totalPrice: total,\n breakdown: { tiers },\n currencyCode: entryCurrency,\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|