@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/backend/cpq/offerings/%5Bid%5D/page.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useParams, useRouter } from 'next/navigation'\nimport { Alert } from '@open-mercato/ui/primitives/alert'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport { NumberInput } from '../../../../components/NumberInput'\nimport {\n chargeTypeMap,\n formatStatusLabel,\n lifecycleStatusMap,\n type ChargeType,\n type LifecycleStatus,\n} from '../../../../components/statusMaps'\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\ntype OfferingComponent = {\n id: string\n slotId: string\n slot: { id: string; componentGroup: string; name: string; cardinalityMin: number; cardinalityMax: number | null } | null\n childOfferingId: string\n childOffering: { id: string; code: string; name: string; offeringType: string; specId: string } | null\n isDefault: boolean\n sortOrder: number\n isActive: boolean\n}\n\ntype BundleSlot = {\n id: string\n componentGroup: string\n name: string\n targetSpecId: string\n targetSpec: { id: string; code: string; name: string; specType: string } | null\n cardinalityMin: number\n cardinalityMax: number | null\n sortOrder: number\n}\n\ntype Offering = {\n id: string\n specId: string\n catalogOfferId: string | null\n code: string\n name: string\n description: string | null\n offeringType: string\n designTimeValues: Record<string, unknown>\n lifecycleStatus: string\n effectiveFrom: string | null\n effectiveTo: string | null\n metadata: Record<string, unknown> | null\n isActive: boolean\n specification: { id: string; code: string; name: string; productId: string; specType?: string } | null\n charges: Charge[]\n components?: OfferingComponent[]\n}\n\ntype Charge = {\n id: string\n code: string\n name: string\n description: string | null\n chargeType: string\n pricingMethod: string\n pricingTableId: string | null\n priceColumnKey: string | null\n fixedPrice: string | null\n currencyCode: string | null\n quantityAttributeCode: string | null\n applicabilityCondition: Record<string, unknown> | null\n sortOrder: number\n isActive: boolean\n}\n\ntype Attribute = {\n id: string\n code: string\n name: string\n attributeType: string\n resolutionTime: string\n options: Array<{ value: string; label: string }> | null\n constraints: Record<string, unknown> | null\n defaultValue: unknown | null\n helpText: string | null\n sortOrder: number\n isRequired: boolean\n isActive: boolean\n}\n\ntype Specification = {\n id: string\n code: string\n name: string\n productId: string\n}\n\ntype PricingTableRef = { id: string; code: string; name: string; dimensions: Array<{ key: string; label: string }>; priceColumns: Array<{ key: string; label: string }> }\n\ntype EditingCharge = Omit<Charge, 'id'> & { id?: string }\n\n// \u2500\u2500\u2500 Defaults \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\nconst EMPTY_FORM = {\n code: '',\n name: '',\n description: '',\n offeringType: 'simple' as string,\n lifecycleStatus: 'draft',\n effectiveFrom: null as string | null,\n effectiveTo: null as string | null,\n isActive: true,\n specId: '',\n}\n\nconst EMPTY_CHARGE: EditingCharge = {\n code: '',\n name: '',\n description: null,\n chargeType: 'mrc',\n pricingMethod: 'flat',\n pricingTableId: null,\n priceColumnKey: null,\n fixedPrice: null,\n currencyCode: 'USD',\n quantityAttributeCode: null,\n applicabilityCondition: null,\n sortOrder: 0,\n isActive: true,\n}\n\n\nconst PRICING_METHOD_LABELS: Record<string, string> = {\n flat: 'flat price',\n fixed: 'flat price', // legacy alias \u2014 see validators.ts\n per_unit: 'per unit',\n tiered: 'tiered',\n}\n\n// V-CHG-1 in `validators.ts`: per_unit/tiered need table + column + qty\n// attribute; flat needs fixedPrice + currencyCode. Mirror it in the UI so\n// users see what's missing without round-tripping to the server.\ntype ChargeShape = {\n pricingMethod: string\n pricingTableId: string | null\n priceColumnKey: string | null\n fixedPrice: string | null\n currencyCode: string | null\n quantityAttributeCode: string | null\n}\n\nfunction isChargeComplete(charge: ChargeShape): boolean {\n return chargeMissingFields(charge).length === 0\n}\n\nfunction chargeMissingFields(charge: ChargeShape): string[] {\n const method = charge.pricingMethod === 'fixed' ? 'flat' : charge.pricingMethod\n const missing: string[] = []\n if (method === 'flat') {\n if (!charge.fixedPrice) missing.push('Fixed Price')\n if (!charge.currencyCode) missing.push('Currency')\n } else if (method === 'per_unit' || method === 'tiered') {\n if (!charge.pricingTableId) missing.push('Pricing Table')\n if (!charge.priceColumnKey) missing.push('Price Column')\n if (!charge.quantityAttributeCode) missing.push('Quantity Attribute')\n }\n return missing\n}\n\n// \u2500\u2500\u2500 Component \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 default function OfferingDetailPage(props: { params?: { id?: string } }) {\n const t = useT()\n const router = useRouter()\n const urlParams = useParams()\n const offeringId = (props.params?.id ?? urlParams?.id) as string\n const isNew = offeringId === 'new'\n\n // \u2500\u2500\u2500 State \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\n const [tab, setTab] = React.useState<'general' | 'charges' | 'components'>('general')\n const [form, setForm] = React.useState(EMPTY_FORM)\n const [designTimeValues, setDesignTimeValues] = React.useState<Record<string, unknown>>({})\n const [charges, setCharges] = React.useState<Charge[]>([])\n const [attributes, setAttributes] = React.useState<Attribute[]>([])\n const [specs, setSpecs] = React.useState<Specification[]>([])\n const [specDetail, setSpecDetail] = React.useState<{ id: string; code: string; name: string; specType?: string } | null>(null)\n const [pricingTables, setPricingTables] = React.useState<PricingTableRef[]>([])\n const [components, setComponents] = React.useState<OfferingComponent[]>([])\n const [bundleSlots, setBundleSlots] = React.useState<BundleSlot[]>([])\n const [addingComponent, setAddingComponent] = React.useState<{ slotId: string; childOfferingId: string; isDefault: boolean } | null>(null)\n const [slotOfferings, setSlotOfferings] = React.useState<Record<string, Array<{ id: string; code: string; name: string; offeringType: string }>>>({})\n\n const [loading, setLoading] = React.useState(!isNew)\n const [saving, setSaving] = React.useState(false)\n const [error, setError] = React.useState<string | null>(null)\n\n const [editingCharge, setEditingCharge] = React.useState<EditingCharge | null>(null)\n\n // OM-standard detail page: existing offerings open read-only and require\n // an explicit Edit click to allow changes. New offerings skip view mode.\n const [generalMode, setGeneralMode] = React.useState<'view' | 'edit'>(isNew ? 'edit' : 'view')\n const [formSnapshot, setFormSnapshot] = React.useState<typeof EMPTY_FORM | null>(null)\n const [designTimeSnapshot, setDesignTimeSnapshot] = React.useState<Record<string, unknown> | null>(null)\n\n // \u2500\u2500\u2500 Load data \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 React.useEffect(() => {\n let cancelled = false\n\n async function load() {\n try {\n // Load specs for dropdown (needed for new + showing spec name)\n const specsRes = await fetch('/api/cpq/product-specifications?pageSize=200')\n if (specsRes.ok) {\n const d = await specsRes.json()\n if (!cancelled) setSpecs(d.items ?? [])\n }\n\n if (isNew) return\n\n // Load offering detail\n const res = await fetch(`/api/cpq/product-offerings?id=${encodeURIComponent(offeringId)}`)\n if (!res.ok) {\n if (!cancelled) setError('Failed to load offering')\n return\n }\n\n const data: Offering = await res.json()\n if (!cancelled) {\n setForm({\n code: data.code,\n name: data.name,\n description: data.description ?? '',\n offeringType: data.offeringType ?? 'simple',\n lifecycleStatus: data.lifecycleStatus,\n effectiveFrom: data.effectiveFrom,\n effectiveTo: data.effectiveTo,\n isActive: data.isActive,\n specId: data.specId,\n })\n setDesignTimeValues(data.designTimeValues ?? {})\n setCharges(data.charges ?? [])\n setSpecDetail(data.specification ?? null)\n setComponents(data.components ?? [])\n\n // Load attributes for the spec\n if (data.specId) {\n const attrRes = await fetch(`/api/cpq/product-attributes?specId=${encodeURIComponent(data.specId)}&pageSize=200`)\n if (attrRes.ok) {\n const attrData = await attrRes.json()\n if (!cancelled) setAttributes(attrData.items ?? [])\n }\n }\n\n // Load bundle slots if this is a bundle offering\n if (data.offeringType === 'bundle' && data.specId) {\n const slotsRes = await fetch(`/api/cpq/bundle-slots?specId=${encodeURIComponent(data.specId)}`)\n if (slotsRes.ok) {\n const slotsData = await slotsRes.json()\n if (!cancelled) setBundleSlots(slotsData.items ?? [])\n }\n }\n }\n } catch (err) {\n console.error('Failed to load', err)\n if (!cancelled) setError('Failed to load')\n } finally {\n if (!cancelled) setLoading(false)\n }\n }\n\n load()\n return () => { cancelled = true }\n }, [offeringId, isNew])\n\n // Load attributes when spec changes (for new offering)\n const loadSpecAttributes = async (specId: string) => {\n if (!specId) { setAttributes([]); return }\n try {\n const res = await fetch(`/api/cpq/product-attributes?specId=${encodeURIComponent(specId)}&pageSize=200`)\n if (res.ok) {\n const data = await res.json()\n setAttributes(data.items ?? [])\n }\n } catch {\n console.error('Failed to load spec attributes')\n }\n }\n\n // \u2500\u2500\u2500 Save offering \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 const saveOffering = async () => {\n setSaving(true)\n setError(null)\n try {\n const payload = isNew\n ? { ...form, description: form.description || null, designTimeValues, specId: form.specId }\n : { id: offeringId, ...form, description: form.description || null, designTimeValues }\n\n const res = await fetch('/api/cpq/product-offerings', {\n method: isNew ? 'POST' : 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n\n if (!res.ok) {\n const d = await res.json()\n setError(d.error ?? 'Failed to save')\n return\n }\n\n const saved = await res.json()\n if (isNew) {\n router.push(`/backend/cpq/offerings/${saved.id}`)\n } else {\n setForm({\n code: saved.code,\n name: saved.name,\n description: saved.description ?? '',\n offeringType: saved.offeringType ?? form.offeringType,\n lifecycleStatus: saved.lifecycleStatus,\n effectiveFrom: saved.effectiveFrom,\n effectiveTo: saved.effectiveTo,\n isActive: saved.isActive,\n specId: saved.specId,\n })\n setDesignTimeValues(saved.designTimeValues ?? {})\n // Save succeeded \u2014 drop snapshots and flip back to read-only.\n setFormSnapshot(null)\n setDesignTimeSnapshot(null)\n setGeneralMode('view')\n }\n } catch {\n setError('Failed to save')\n } finally {\n setSaving(false)\n }\n }\n\n const deleteOffering = async () => {\n if (!confirm(t('cpq.offerings.confirmDelete', 'Delete this offering and all its charges?'))) return\n try {\n const res = await fetch('/api/cpq/product-offerings', {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: offeringId }),\n })\n if (res.ok) {\n router.push('/backend/cpq/offerings')\n } else {\n const d = await res.json()\n setError(d.error ?? 'Failed to delete')\n }\n } catch {\n setError('Failed to delete')\n }\n }\n\n // \u2500\u2500\u2500 Charge CRUD \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 const loadPricingTables = async () => {\n if (pricingTables.length > 0) return\n const res = await fetch('/api/cpq/pricing-tables?pageSize=200')\n if (res.ok) {\n const data = await res.json()\n setPricingTables(data.items ?? [])\n }\n }\n\n const startEditCharge = (charge?: Charge) => {\n const editing = charge ? { ...charge } : { ...EMPTY_CHARGE }\n setEditingCharge(editing)\n loadPricingTables()\n }\n\n const saveCharge = async () => {\n if (!editingCharge) return\n setSaving(true)\n setError(null)\n try {\n const isEdit = !!editingCharge.id\n const payload = {\n ...editingCharge,\n offeringId,\n }\n const res = await fetch('/api/cpq/product-charges', {\n method: isEdit ? 'PUT' : 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n if (!res.ok) {\n const d = await res.json()\n setError(d.error ?? 'Failed to save charge')\n return\n }\n // Reload offering to get updated charges\n const offeringRes = await fetch(`/api/cpq/product-offerings?id=${encodeURIComponent(offeringId)}`)\n if (offeringRes.ok) {\n const data = await offeringRes.json()\n setCharges(data.charges ?? [])\n }\n setEditingCharge(null)\n } catch {\n setError('Failed to save charge')\n } finally {\n setSaving(false)\n }\n }\n\n const deleteCharge = async (chargeId: string) => {\n if (!confirm('Delete this charge?')) return\n try {\n const res = await fetch('/api/cpq/product-charges', {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: chargeId }),\n })\n if (res.ok) setCharges((prev) => prev.filter((c) => c.id !== chargeId))\n } catch {\n setError('Failed to delete charge')\n }\n }\n\n const selectedPricingTable = editingCharge?.pricingTableId\n ? pricingTables.find((pt) => pt.id === editingCharge.pricingTableId)\n : null\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 const designTimeAttrs = attributes.filter((a) => a.resolutionTime === 'design_time')\n\n // \u2500\u2500\u2500 Render \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\n if (loading) {\n return <div className=\"text-sm text-muted-foreground\">{t('common.loading', 'Loading...')}</div>\n }\n\n return (\n <div className=\"space-y-6\">\n {/* Header */}\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <button\n onClick={() => router.push('/backend/cpq/offerings')}\n className=\"text-sm text-muted-foreground hover:text-foreground\"\n >\n \u2190 {t('common.back', 'Back')}\n </button>\n <h1 className=\"text-2xl font-bold\">\n {isNew ? t('cpq.offerings.new', 'New Offering') : form.name}\n </h1>\n {!isNew && (\n <Tag variant={lifecycleStatusMap[form.lifecycleStatus as LifecycleStatus] ?? 'neutral'} dot>\n {formatStatusLabel(form.lifecycleStatus)}\n </Tag>\n )}\n {specDetail && (\n <span className=\"text-sm text-muted-foreground\">\n Spec: <button onClick={() => router.push(`/backend/cpq/specifications/${specDetail.id}`)} className=\"text-primary hover:underline\">{specDetail.name}</button>\n </span>\n )}\n </div>\n {!isNew && (\n <div className=\"flex items-center gap-2\">\n {generalMode === 'view' && tab === 'general' && (\n <Button\n type=\"button\"\n onClick={() => {\n setFormSnapshot(form)\n setDesignTimeSnapshot(designTimeValues)\n setGeneralMode('edit')\n }}\n >\n {t('common.edit', 'Edit')}\n </Button>\n )}\n <Button type=\"button\" variant=\"destructive\" onClick={deleteOffering}>\n {t('common.delete', 'Delete')}\n </Button>\n </div>\n )}\n </div>\n\n {error && (\n <Alert variant=\"destructive\">{error}</Alert>\n )}\n\n {/* Tabs */}\n {!isNew && (\n <div className=\"flex gap-1 border-b\">\n {([\n 'general',\n 'charges',\n ...(form.offeringType === 'bundle' ? ['components' as const] : []),\n ] as const).map((t_) => (\n <button\n key={t_}\n onClick={() => setTab(t_ as typeof tab)}\n className={`px-4 py-2 text-sm font-medium border-b-2 transition-colors ${\n tab === t_ ? 'border-primary text-primary' : 'border-transparent text-muted-foreground hover:text-foreground'\n }`}\n >\n {t_ === 'general' && 'General'}\n {t_ === 'charges' && `Charges (${charges.length})`}\n {t_ === 'components' && `Components (${components.length})`}\n </button>\n ))}\n </div>\n )}\n\n {/* \u2500\u2500\u2500 General Tab / New Form \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 {(isNew || tab === 'general') && (\n <div className=\"rounded-lg border bg-card p-6 space-y-4\">\n {isNew && (\n <div>\n <label className=\"block text-sm font-medium mb-1\">Specification</label>\n <select\n value={form.specId}\n onChange={(e) => {\n setForm({ ...form, specId: e.target.value })\n loadSpecAttributes(e.target.value)\n setDesignTimeValues({})\n }}\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n >\n <option value=\"\">Select a specification...</option>\n {specs.map((s) => (\n <option key={s.id} value={s.id}>{s.name} ({s.code})</option>\n ))}\n </select>\n </div>\n )}\n\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"block text-sm font-medium mb-1\">{t('cpq.offerings.code', 'Code')}</label>\n {generalMode === 'view' && !isNew ? (\n <p className=\"text-sm font-mono py-2\">{form.code || '\u2014'}</p>\n ) : (\n <input\n type=\"text\"\n value={form.code}\n onChange={(e) => setForm({ ...form, code: e.target.value })}\n placeholder=\"e.g. gix-cloud-connect-aws\"\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n />\n )}\n </div>\n <div>\n <label className=\"block text-sm font-medium mb-1\">{t('cpq.offerings.name', 'Name')}</label>\n {generalMode === 'view' && !isNew ? (\n <p className=\"text-sm py-2\">{form.name || '\u2014'}</p>\n ) : (\n <input\n type=\"text\"\n value={form.name}\n onChange={(e) => setForm({ ...form, name: e.target.value })}\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n />\n )}\n </div>\n <div>\n <label className=\"block text-sm font-medium mb-1\">{t('cpq.offerings.lifecycleStatus', 'Lifecycle Status')}</label>\n {generalMode === 'view' && !isNew ? (\n <div className=\"py-2\">\n <Tag variant={lifecycleStatusMap[form.lifecycleStatus as LifecycleStatus] ?? 'neutral'} dot>\n {formatStatusLabel(form.lifecycleStatus)}\n </Tag>\n </div>\n ) : (\n <select\n value={form.lifecycleStatus}\n onChange={(e) => setForm({ ...form, lifecycleStatus: e.target.value })}\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n >\n <option value=\"draft\">Draft</option>\n <option value=\"active\">Active</option>\n <option value=\"deprecated\">Deprecated</option>\n </select>\n )}\n </div>\n <div>\n <label className=\"block text-sm font-medium mb-1\">{t('cpq.offerings.isActive', 'Is Active?')}</label>\n <div className=\"flex items-center h-[38px]\">\n {generalMode === 'view' && !isNew ? (\n <Tag variant={form.isActive ? 'success' : 'neutral'} dot>\n {form.isActive ? t('common.yes', 'Yes') : t('common.no', 'No')}\n </Tag>\n ) : (\n <input\n type=\"checkbox\"\n checked={form.isActive}\n onChange={(e) => setForm({ ...form, isActive: e.target.checked })}\n className=\"rounded border\"\n />\n )}\n </div>\n </div>\n </div>\n <div>\n <label className=\"block text-sm font-medium mb-1\">{t('cpq.offerings.description', 'Description')}</label>\n {generalMode === 'view' && !isNew ? (\n <p className=\"text-sm text-muted-foreground py-2 whitespace-pre-wrap\">{form.description || '\u2014'}</p>\n ) : (\n <textarea\n value={form.description ?? ''}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n rows={3}\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n />\n )}\n </div>\n\n {/* Design-time values */}\n {designTimeAttrs.length > 0 && (\n <div className=\"space-y-3\">\n <label className=\"block text-sm font-medium\">Design-Time Values</label>\n <div className=\"grid grid-cols-2 gap-3\">\n {designTimeAttrs.map((attr) => {\n const value = designTimeValues[attr.code]\n const isViewing = generalMode === 'view' && !isNew\n // Lookup the human label for select-type values so the\n // read-only view doesn't show raw codes.\n const optionLabel =\n (attr.attributeType === 'select' || attr.attributeType === 'enum') && attr.options\n ? attr.options.find((o) => o.value === value)?.label\n : undefined\n return (\n <div key={attr.code}>\n <label className=\"block text-xs font-medium mb-1\">\n {attr.name}\n {attr.isRequired && <span className=\"text-destructive ml-0.5\">*</span>}\n </label>\n {isViewing ? (\n <p className=\"text-sm py-2\">\n {value == null || value === '' ? (\n <span className=\"text-muted-foreground\">\u2014</span>\n ) : attr.attributeType === 'boolean' ? (\n <Tag variant={value ? 'success' : 'neutral'} dot>\n {value ? t('common.yes', 'Yes') : t('common.no', 'No')}\n </Tag>\n ) : (\n optionLabel ?? String(value)\n )}\n </p>\n ) : (attr.attributeType === 'select' || attr.attributeType === 'enum') && attr.options ? (\n <select\n value={String(value ?? '')}\n onChange={(e) => setDesignTimeValues({ ...designTimeValues, [attr.code]: e.target.value || null })}\n className=\"w-full rounded-md border px-2 py-1.5 text-sm\"\n >\n <option value=\"\">Select {attr.name}...</option>\n {attr.options.map((opt) => (\n <option key={opt.value} value={opt.value}>{opt.label}</option>\n ))}\n </select>\n ) : attr.attributeType === 'number' ? (\n <NumberInput\n value={typeof value === 'number' ? (value as number) : null}\n onChange={(n) => setDesignTimeValues({ ...designTimeValues, [attr.code]: n })}\n />\n ) : attr.attributeType === 'boolean' ? (\n <div className=\"pt-1\">\n <label className=\"flex items-center gap-1.5 text-sm\">\n <input\n type=\"checkbox\"\n checked={!!value}\n onChange={(e) => setDesignTimeValues({ ...designTimeValues, [attr.code]: e.target.checked })}\n className=\"rounded border\"\n />\n {attr.name}\n </label>\n </div>\n ) : (\n <input\n type=\"text\"\n value={String(value ?? '')}\n onChange={(e) => setDesignTimeValues({ ...designTimeValues, [attr.code]: e.target.value || null })}\n className=\"w-full rounded-md border px-2 py-1.5 text-sm\"\n placeholder={attr.helpText ?? undefined}\n />\n )}\n {attr.helpText && <p className=\"text-xs text-muted-foreground mt-0.5\">{attr.helpText}</p>}\n </div>\n )\n })}\n </div>\n </div>\n )}\n\n {/* In view mode the Edit button lives in the page header next to\n Delete (OM standard). Here we only render the Save/Cancel\n pair when actually editing. */}\n {!(generalMode === 'view' && !isNew) && (\n <div className=\"flex gap-3\">\n <Button\n type=\"button\"\n onClick={saveOffering}\n disabled={saving || !form.code || !form.name || (isNew && !form.specId)}\n >\n {saving ? t('common.saving', 'Saving...') : t('common.save', 'Save')}\n </Button>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => {\n if (isNew) {\n router.push('/backend/cpq/offerings')\n return\n }\n if (formSnapshot) setForm(formSnapshot)\n if (designTimeSnapshot) setDesignTimeValues(designTimeSnapshot)\n setFormSnapshot(null)\n setDesignTimeSnapshot(null)\n setGeneralMode('view')\n }}\n >\n {t('common.cancel', 'Cancel')}\n </Button>\n </div>\n )}\n </div>\n )}\n\n {/* \u2500\u2500\u2500 Charges Tab \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 {tab === 'charges' && !isNew && (\n <div className=\"space-y-4\">\n <div className=\"flex justify-end\">\n <button\n onClick={() => startEditCharge()}\n className=\"inline-flex items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90\"\n >\n {t('cpq.offerings.addCharge', 'Add Charge')}\n </button>\n </div>\n\n {/* Charge edit form */}\n {editingCharge && (\n <div className=\"rounded-lg border bg-card p-4 space-y-3\">\n <h3 className=\"font-medium text-sm\">\n {editingCharge.id ? 'Edit Charge' : 'New Charge'}\n </h3>\n <div className=\"grid grid-cols-3 gap-3\">\n <div>\n <label className=\"block text-xs font-medium mb-1\">Code</label>\n <input type=\"text\" value={editingCharge.code} onChange={(e) => setEditingCharge({ ...editingCharge, code: e.target.value })} placeholder=\"e.g. mrc-monthly\" className=\"w-full rounded-md border px-2 py-1.5 text-sm\" />\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Name</label>\n <input type=\"text\" value={editingCharge.name} onChange={(e) => setEditingCharge({ ...editingCharge, name: e.target.value })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\" />\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Charge Type</label>\n <select value={editingCharge.chargeType} onChange={(e) => setEditingCharge({ ...editingCharge, chargeType: e.target.value })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\">\n <option value=\"mrc\">MRC (Monthly Recurring)</option>\n <option value=\"nrc\">NRC (Non-Recurring)</option>\n <option value=\"usage\">Usage</option>\n </select>\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Pricing Method</label>\n <select value={editingCharge.pricingMethod} onChange={(e) => {\n const method = e.target.value\n if (method === 'flat') {\n setEditingCharge({ ...editingCharge, pricingMethod: method, pricingTableId: null, priceColumnKey: null, quantityAttributeCode: null })\n } else {\n setEditingCharge({ ...editingCharge, pricingMethod: method, fixedPrice: null })\n }\n }} className=\"w-full rounded-md border px-2 py-1.5 text-sm\">\n <option value=\"flat\">Flat Price</option>\n <option value=\"per_unit\">Per Unit (table lookup)</option>\n <option value=\"tiered\">Tiered (table lookup)</option>\n </select>\n </div>\n {(editingCharge.pricingMethod === 'flat' || editingCharge.pricingMethod === 'fixed') ? (\n <>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Fixed Price <span className=\"text-destructive\">*</span></label>\n <input type=\"text\" value={editingCharge.fixedPrice ?? ''} onChange={(e) => setEditingCharge({ ...editingCharge, fixedPrice: e.target.value || null })} placeholder=\"0.00\" className=\"w-full rounded-md border px-2 py-1.5 text-sm\" />\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Currency <span className=\"text-destructive\">*</span></label>\n <input type=\"text\" value={editingCharge.currencyCode ?? 'USD'} onChange={(e) => setEditingCharge({ ...editingCharge, currencyCode: e.target.value || null })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\" />\n </div>\n </>\n ) : (\n <>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Pricing Table <span className=\"text-destructive\">*</span></label>\n <select value={editingCharge.pricingTableId ?? ''} onChange={(e) => setEditingCharge({ ...editingCharge, pricingTableId: e.target.value || null, priceColumnKey: null })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\">\n <option value=\"\">Select table...</option>\n {pricingTables.map((pt) => (\n <option key={pt.id} value={pt.id}>{pt.name} ({pt.code})</option>\n ))}\n </select>\n {pricingTables.length === 0 && (\n <p className=\"text-xs text-warning mt-0.5\">\n No pricing tables yet \u2014{' '}\n <a href=\"/backend/cpq/pricing-tables\" className=\"text-primary hover:underline\">create one</a>{' '}\n before using {editingCharge.pricingMethod} pricing.\n </p>\n )}\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Price Column <span className=\"text-destructive\">*</span></label>\n <select value={editingCharge.priceColumnKey ?? ''} onChange={(e) => setEditingCharge({ ...editingCharge, priceColumnKey: e.target.value || null })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\" disabled={!selectedPricingTable}>\n <option value=\"\">Select column...</option>\n {selectedPricingTable?.priceColumns.map((col) => (\n <option key={col.key} value={col.key}>{col.label}</option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Quantity Attribute <span className=\"text-destructive\">*</span></label>\n <select value={editingCharge.quantityAttributeCode ?? ''} onChange={(e) => setEditingCharge({ ...editingCharge, quantityAttributeCode: e.target.value || null })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\">\n <option value=\"\">Select attribute...</option>\n {attributes.filter((a) => a.attributeType === 'number').map((a) => (\n <option key={a.code} value={a.code}>{a.name} ({a.code})</option>\n ))}\n </select>\n <p className=\"text-xs text-muted-foreground mt-0.5\">Attribute whose value drives the quantity for pricing</p>\n {attributes.filter((a) => a.attributeType === 'number').length === 0 && form.specId && (\n <p className=\"text-xs text-warning mt-0.5\">\n Spec has no number attributes \u2014{' '}\n <a href={`/backend/cpq/specifications/${form.specId}`} className=\"text-primary hover:underline\">\n add one to the spec\n </a>{' '}\n first.\n </p>\n )}\n </div>\n </>\n )}\n <div>\n <label className=\"block text-xs font-medium mb-1\">Sort Order</label>\n <NumberInput\n integer\n value={editingCharge.sortOrder}\n onChange={(n) => setEditingCharge({ ...editingCharge, sortOrder: n ?? 0 })}\n />\n </div>\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Description</label>\n <input type=\"text\" value={editingCharge.description ?? ''} onChange={(e) => setEditingCharge({ ...editingCharge, description: e.target.value || null })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\" />\n </div>\n <div className=\"flex items-end gap-4\">\n <label className=\"flex items-center gap-1.5 text-sm\">\n <input type=\"checkbox\" checked={editingCharge.isActive} onChange={(e) => setEditingCharge({ ...editingCharge, isActive: e.target.checked })} className=\"rounded border\" />\n Active\n </label>\n </div>\n {(() => {\n const missing = chargeMissingFields(editingCharge)\n const blocked = saving || !editingCharge.code || !editingCharge.name || missing.length > 0\n return (\n <>\n {missing.length > 0 && (\n <Alert variant=\"destructive\">\n Missing required field{missing.length > 1 ? 's' : ''} for {editingCharge.pricingMethod} pricing: {missing.join(', ')}\n </Alert>\n )}\n <div className=\"flex gap-2\">\n <button onClick={saveCharge} disabled={blocked} className=\"inline-flex items-center rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed\">\n {saving ? 'Saving...' : 'Save'}\n </button>\n <button onClick={() => setEditingCharge(null)} className=\"inline-flex items-center rounded-md border px-3 py-1.5 text-sm font-medium hover:bg-muted\">Cancel</button>\n </div>\n </>\n )\n })()}\n </div>\n )}\n\n {/* Charges table */}\n {charges.length === 0 ? (\n <div className=\"rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground\">\n No charges defined. Add recurring, non-recurring, or usage charges to this offering.\n </div>\n ) : (\n <div className=\"rounded-lg border\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b bg-muted/50\">\n <th className=\"px-4 py-3 text-left font-medium\">Code</th>\n <th className=\"px-4 py-3 text-left font-medium\">Name</th>\n <th className=\"px-4 py-3 text-left font-medium\">Type</th>\n <th className=\"px-4 py-3 text-left font-medium\">Pricing</th>\n <th className=\"px-4 py-3 text-left font-medium\">Price</th>\n <th className=\"px-4 py-3 text-left font-medium\">Active</th>\n <th className=\"px-4 py-3 text-right font-medium\">Actions</th>\n </tr>\n </thead>\n <tbody>\n {charges.map((charge) => {\n const incomplete = !isChargeComplete(charge)\n const tableRef = charge.pricingTableId\n ? pricingTables.find((pt) => pt.id === charge.pricingTableId)\n : null\n const qtyAttr = charge.quantityAttributeCode\n ? attributes.find((a) => a.code === charge.quantityAttributeCode)\n : null\n const isFlat = charge.pricingMethod === 'flat' || charge.pricingMethod === 'fixed'\n return (\n <tr key={charge.id} className=\"border-b\">\n <td className=\"px-4 py-3 font-mono text-xs\">{charge.code}</td>\n <td className=\"px-4 py-3\">\n {charge.name}\n {incomplete && (\n <Tag variant=\"error\" className=\"ml-2 px-2 text-[10px]\" dot>Incomplete</Tag>\n )}\n </td>\n <td className=\"px-4 py-3\">\n <Tag variant={chargeTypeMap[charge.chargeType as ChargeType] ?? 'neutral'} className=\"px-2 text-xs\">\n {charge.chargeType.toUpperCase()}\n </Tag>\n </td>\n <td className=\"px-4 py-3 text-xs\">{PRICING_METHOD_LABELS[charge.pricingMethod] ?? charge.pricingMethod}</td>\n <td className=\"px-4 py-3 text-xs\">\n {isFlat ? (\n charge.fixedPrice != null\n ? `${charge.currencyCode ?? 'USD'} ${charge.fixedPrice}`\n : <span className=\"text-muted-foreground\">\u2014</span>\n ) : (\n <div className=\"flex flex-col gap-0.5\">\n <span>\n <span className=\"text-muted-foreground\">Table:</span>{' '}\n {tableRef ? `${tableRef.name} \u2192 ${charge.priceColumnKey ?? '?'}` : <span className=\"text-destructive\">missing</span>}\n </span>\n <span>\n <span className=\"text-muted-foreground\">\u00D7 Qty:</span>{' '}\n {qtyAttr ? `${qtyAttr.name} (${qtyAttr.code})` : <span className=\"text-destructive\">missing</span>}\n </span>\n </div>\n )}\n </td>\n <td className=\"px-4 py-3\">{charge.isActive ? 'Yes' : 'No'}</td>\n <td className=\"px-4 py-3 text-right\">\n <button onClick={() => startEditCharge(charge)} className=\"text-xs text-primary hover:underline mr-2\">Edit</button>\n <button onClick={() => deleteCharge(charge.id)} className=\"text-xs text-destructive hover:underline\">Delete</button>\n </td>\n </tr>\n )\n })}\n </tbody>\n </table>\n </div>\n )}\n </div>\n )}\n\n {/* \u2500\u2500\u2500 Components Tab (bundle offerings) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */}\n {tab === 'components' && !isNew && form.offeringType === 'bundle' && (\n <div className=\"space-y-4\">\n {bundleSlots.length === 0 ? (\n <div className=\"rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground\">\n No bundle slots defined on this specification. Add slots on the specification first.\n </div>\n ) : (\n <>\n {/* Group components by slot */}\n {bundleSlots.map((slot) => {\n const slotComponents = components.filter((c) => c.slotId === slot.id)\n return (\n <div key={slot.id} className=\"rounded-lg border bg-card overflow-hidden\">\n <div className=\"bg-muted/50 px-4 py-3 border-b flex items-center justify-between\">\n <div>\n <span className=\"font-medium text-sm\">{slot.name}</span>\n <Tag variant=\"info\" className=\"ml-2 px-2 text-[10px]\">\n {slot.componentGroup}\n </Tag>\n <span className=\"ml-2 text-xs text-muted-foreground\">\n {slot.cardinalityMin}..{slot.cardinalityMax ?? '\u221E'}\n </span>\n {slot.targetSpec && (\n <span className=\"ml-2 text-xs text-muted-foreground\">\u2192 {slot.targetSpec.name}</span>\n )}\n </div>\n <button\n onClick={async () => {\n setAddingComponent({ slotId: slot.id, childOfferingId: '', isDefault: false })\n if (!slotOfferings[slot.targetSpecId]) {\n const res = await fetch(`/api/cpq/product-offerings?specId=${encodeURIComponent(slot.targetSpecId)}&pageSize=100`)\n if (res.ok) {\n const d = await res.json()\n setSlotOfferings((prev) => ({ ...prev, [slot.targetSpecId]: d.items ?? [] }))\n }\n }\n }}\n className=\"inline-flex items-center justify-center rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90\"\n >\n + Add Component\n </button>\n </div>\n\n {addingComponent?.slotId === slot.id && (\n <div className=\"p-4 border-b bg-muted/20 space-y-3\">\n <div className=\"grid grid-cols-3 gap-3\">\n <div className=\"col-span-2\">\n <label className=\"block text-xs font-medium mb-1\">Component Offering</label>\n <select\n value={addingComponent.childOfferingId}\n onChange={(e) => setAddingComponent({ ...addingComponent, childOfferingId: e.target.value })}\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n >\n <option value=\"\">\u2014 Select offering \u2014</option>\n {(slotOfferings[slot.targetSpecId] ?? []).map((o) => (\n <option key={o.id} value={o.id}>{o.name} ({o.code}){o.offeringType === 'bundle' ? ' [bundle]' : ''}</option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Default?</label>\n <div className=\"flex items-center h-[38px]\">\n <input\n type=\"checkbox\"\n checked={addingComponent.isDefault}\n onChange={(e) => setAddingComponent({ ...addingComponent, isDefault: e.target.checked })}\n className=\"rounded border\"\n />\n <span className=\"ml-2 text-xs text-muted-foreground\">Pre-selected in quote</span>\n </div>\n </div>\n </div>\n <div className=\"flex gap-2\">\n <button\n disabled={saving || !addingComponent.childOfferingId}\n onClick={async () => {\n setSaving(true)\n setError(null)\n try {\n const res = await fetch('/api/cpq/offering-components', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n offeringId,\n slotId: addingComponent.slotId,\n childOfferingId: addingComponent.childOfferingId,\n isDefault: addingComponent.isDefault,\n }),\n })\n if (!res.ok) {\n const d = await res.json()\n setError(d.error ?? 'Failed to add component')\n return\n }\n setAddingComponent(null)\n const compRes = await fetch(`/api/cpq/offering-components?offeringId=${offeringId}`)\n if (compRes.ok) {\n const d = await compRes.json()\n setComponents(d.items ?? [])\n }\n } catch {\n setError('Failed to add component')\n } finally {\n setSaving(false)\n }\n }}\n className=\"inline-flex items-center justify-center rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50\"\n >\n {saving ? 'Adding...' : 'Add'}\n </button>\n <button\n onClick={() => setAddingComponent(null)}\n className=\"inline-flex items-center justify-center rounded-md border px-3 py-1.5 text-xs font-medium hover:bg-muted\"\n >\n Cancel\n </button>\n </div>\n </div>\n )}\n\n {slotComponents.length === 0 ? (\n <div className=\"p-4 text-center text-xs text-muted-foreground\">\n No components assigned to this slot\n {slot.cardinalityMin > 0 && (\n <span className=\"ml-1 text-status-warning-text font-medium\">(required: min {slot.cardinalityMin})</span>\n )}\n </div>\n ) : (\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b bg-muted/30\">\n <th className=\"px-4 py-2 text-left text-xs font-medium\">Offering</th>\n <th className=\"px-4 py-2 text-left text-xs font-medium\">Code</th>\n <th className=\"px-4 py-2 text-left text-xs font-medium\">Type</th>\n <th className=\"px-4 py-2 text-left text-xs font-medium\">Default</th>\n <th className=\"px-4 py-2 text-right text-xs font-medium\">Actions</th>\n </tr>\n </thead>\n <tbody>\n {slotComponents.map((comp) => (\n <tr key={comp.id} className=\"border-b last:border-0\">\n <td className=\"px-4 py-2.5 font-medium\">{comp.childOffering?.name ?? 'Unknown'}</td>\n <td className=\"px-4 py-2.5 text-muted-foreground text-xs\">{comp.childOffering?.code ?? '\u2014'}</td>\n <td className=\"px-4 py-2.5\">\n {comp.childOffering?.offeringType === 'bundle' ? (\n <Tag variant=\"brand\" className=\"px-2 text-[10px]\">bundle</Tag>\n ) : (\n <Tag variant=\"neutral\" className=\"px-2 text-[10px]\">simple</Tag>\n )}\n </td>\n <td className=\"px-4 py-2.5\">\n <button\n onClick={async () => {\n try {\n const res = await fetch('/api/cpq/offering-components', {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: comp.id, isDefault: !comp.isDefault }),\n })\n if (res.ok) {\n setComponents((prev) => prev.map((c) => c.id === comp.id ? { ...c, isDefault: !c.isDefault } : c))\n }\n } catch { /* ignore */ }\n }}\n className=\"cursor-pointer\"\n >\n <Tag variant={comp.isDefault ? 'success' : 'neutral'} className=\"px-2 text-[10px]\">\n {comp.isDefault ? 'Yes' : 'No'}\n </Tag>\n </button>\n </td>\n <td className=\"px-4 py-2.5 text-right\">\n <button\n onClick={async () => {\n if (!confirm('Remove this component from the bundle?')) return\n try {\n const res = await fetch('/api/cpq/offering-components', {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: comp.id }),\n })\n if (res.ok) {\n setComponents((prev) => prev.filter((c) => c.id !== comp.id))\n } else {\n const d = await res.json()\n setError(d.error ?? 'Failed to remove')\n }\n } catch {\n setError('Failed to remove component')\n }\n }}\n className=\"text-xs text-destructive hover:underline\"\n >\n Remove\n </button>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n )}\n </div>\n )\n })}\n </>\n )}\n </div>\n )}\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
5
|
+
import { useRouter } from "next/navigation";
|
|
6
|
+
import { Button } from "@open-mercato/ui/primitives/button";
|
|
7
|
+
import { Checkbox } from "@open-mercato/ui/primitives/checkbox";
|
|
8
|
+
import { Input } from "@open-mercato/ui/primitives/input";
|
|
9
|
+
import {
|
|
10
|
+
Select,
|
|
11
|
+
SelectContent,
|
|
12
|
+
SelectItem,
|
|
13
|
+
SelectTrigger,
|
|
14
|
+
SelectValue
|
|
15
|
+
} from "@open-mercato/ui/primitives/select";
|
|
16
|
+
import { flash } from "@open-mercato/ui/backend/FlashMessages";
|
|
17
|
+
import { Alert } from "@open-mercato/ui/primitives/alert";
|
|
18
|
+
import { Tag } from "@open-mercato/ui/primitives/tag";
|
|
19
|
+
import { CpqListView, useCpqListData } from "../../../components/CpqListView.js";
|
|
20
|
+
import { NumberInput } from "../../../components/NumberInput.js";
|
|
21
|
+
import {
|
|
22
|
+
chargeTypeMap,
|
|
23
|
+
formatStatusLabel,
|
|
24
|
+
lifecycleStatusMap
|
|
25
|
+
} from "../../../components/statusMaps.js";
|
|
26
|
+
const PAGE_SIZE = 50;
|
|
27
|
+
function ChargePopover({ charge }) {
|
|
28
|
+
const [open, setOpen] = React.useState(false);
|
|
29
|
+
const variant = chargeTypeMap[charge.chargeType] ?? "neutral";
|
|
30
|
+
return /* @__PURE__ */ jsxs(
|
|
31
|
+
"span",
|
|
32
|
+
{
|
|
33
|
+
className: "relative inline-flex",
|
|
34
|
+
onMouseEnter: () => setOpen(true),
|
|
35
|
+
onMouseLeave: () => setOpen(false),
|
|
36
|
+
children: [
|
|
37
|
+
/* @__PURE__ */ jsx(Tag, { variant, className: "cursor-default px-2 text-[10px]", children: charge.chargeType.toUpperCase() }),
|
|
38
|
+
open && /* @__PURE__ */ jsxs("div", { className: "absolute bottom-full left-1/2 -translate-x-1/2 mb-2 z-50 w-56 rounded-lg border bg-popover p-3 shadow-md text-popover-foreground text-xs space-y-1.5", children: [
|
|
39
|
+
/* @__PURE__ */ jsx("div", { className: "font-medium text-sm", children: charge.name }),
|
|
40
|
+
/* @__PURE__ */ jsx("div", { className: "text-muted-foreground font-mono", children: charge.code }),
|
|
41
|
+
charge.description && /* @__PURE__ */ jsx("div", { className: "text-muted-foreground", children: charge.description }),
|
|
42
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between pt-1 border-t", children: [
|
|
43
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
44
|
+
"Pricing: ",
|
|
45
|
+
charge.pricingMethod
|
|
46
|
+
] }),
|
|
47
|
+
charge.fixedPrice != null && /* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
|
|
48
|
+
charge.currencyCode ?? "USD",
|
|
49
|
+
" ",
|
|
50
|
+
charge.fixedPrice
|
|
51
|
+
] })
|
|
52
|
+
] }),
|
|
53
|
+
!charge.isActive && /* @__PURE__ */ jsx(Tag, { variant: "warning", dot: true, children: "Inactive" }),
|
|
54
|
+
/* @__PURE__ */ jsx("div", { className: "absolute left-1/2 -translate-x-1/2 top-full w-2 h-2 bg-popover border-b border-r rotate-45 -mt-1" })
|
|
55
|
+
] })
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
function buildFilterParams(values, params) {
|
|
61
|
+
if (typeof values.lifecycleStatus === "string" && values.lifecycleStatus) {
|
|
62
|
+
params.set("lifecycleStatus", values.lifecycleStatus);
|
|
63
|
+
}
|
|
64
|
+
if (typeof values.offeringType === "string" && values.offeringType) {
|
|
65
|
+
params.set("offeringType", values.offeringType);
|
|
66
|
+
}
|
|
67
|
+
if (values.isActive === true) params.set("isActive", "true");
|
|
68
|
+
if (values.isActive === false) params.set("isActive", "false");
|
|
69
|
+
}
|
|
70
|
+
function OfferingsListPage() {
|
|
71
|
+
const t = useT();
|
|
72
|
+
const router = useRouter();
|
|
73
|
+
const data = useCpqListData({
|
|
74
|
+
endpoint: "/api/cpq/product-offerings",
|
|
75
|
+
pageSize: PAGE_SIZE,
|
|
76
|
+
buildFilterParams,
|
|
77
|
+
loadErrorMessage: t("cpq.offerings.list.error.load", "Failed to load offerings")
|
|
78
|
+
});
|
|
79
|
+
const [bulkChargeOpen, setBulkChargeOpen] = React.useState(false);
|
|
80
|
+
const [bulkChargeTargets, setBulkChargeTargets] = React.useState([]);
|
|
81
|
+
const [chargeForm, setChargeForm] = React.useState({
|
|
82
|
+
code: "",
|
|
83
|
+
name: "",
|
|
84
|
+
description: "",
|
|
85
|
+
chargeType: "mrc"
|
|
86
|
+
});
|
|
87
|
+
const [chargePrices, setChargePrices] = React.useState({});
|
|
88
|
+
const [chargeCurrency, setChargeCurrency] = React.useState("USD");
|
|
89
|
+
const [saving, setSaving] = React.useState(false);
|
|
90
|
+
const [error, setError] = React.useState(null);
|
|
91
|
+
const lifecycleOptions = React.useMemo(
|
|
92
|
+
() => [
|
|
93
|
+
{ value: "draft", label: t("cpq.offerings.lifecycle.draft", "Draft") },
|
|
94
|
+
{ value: "active", label: t("cpq.offerings.lifecycle.active", "Active") },
|
|
95
|
+
{ value: "deprecated", label: t("cpq.offerings.lifecycle.deprecated", "Deprecated") }
|
|
96
|
+
],
|
|
97
|
+
[t]
|
|
98
|
+
);
|
|
99
|
+
const offeringTypeOptions = React.useMemo(
|
|
100
|
+
() => [
|
|
101
|
+
{ value: "simple", label: t("cpq.offerings.type.simple", "Simple") },
|
|
102
|
+
{ value: "bundle", label: t("cpq.offerings.type.bundle", "Bundle") }
|
|
103
|
+
],
|
|
104
|
+
[t]
|
|
105
|
+
);
|
|
106
|
+
const filters = React.useMemo(
|
|
107
|
+
() => [
|
|
108
|
+
{
|
|
109
|
+
id: "lifecycleStatus",
|
|
110
|
+
label: t("cpq.offerings.filters.lifecycleStatus", "Lifecycle Status"),
|
|
111
|
+
type: "select",
|
|
112
|
+
options: lifecycleOptions
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
id: "offeringType",
|
|
116
|
+
label: t("cpq.offerings.filters.offeringType", "Type"),
|
|
117
|
+
type: "select",
|
|
118
|
+
options: offeringTypeOptions
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
id: "isActive",
|
|
122
|
+
label: t("cpq.offerings.filters.isActive", "Active"),
|
|
123
|
+
type: "checkbox"
|
|
124
|
+
}
|
|
125
|
+
],
|
|
126
|
+
[lifecycleOptions, offeringTypeOptions, t]
|
|
127
|
+
);
|
|
128
|
+
const openBulkChargeForm = React.useCallback(
|
|
129
|
+
(targets) => {
|
|
130
|
+
setBulkChargeTargets(targets);
|
|
131
|
+
setChargeForm({ code: "", name: "", description: "", chargeType: "mrc" });
|
|
132
|
+
setChargePrices({});
|
|
133
|
+
setChargeCurrency("USD");
|
|
134
|
+
setError(null);
|
|
135
|
+
setBulkChargeOpen(true);
|
|
136
|
+
},
|
|
137
|
+
[]
|
|
138
|
+
);
|
|
139
|
+
const saveChargesForSelected = React.useCallback(async () => {
|
|
140
|
+
const targets = bulkChargeTargets;
|
|
141
|
+
if (!targets.length || !chargeForm.code || !chargeForm.name) return;
|
|
142
|
+
setSaving(true);
|
|
143
|
+
setError(null);
|
|
144
|
+
try {
|
|
145
|
+
for (const offering of targets) {
|
|
146
|
+
const chargeCode = targets.length > 1 ? `${offering.code}--${chargeForm.code}` : chargeForm.code;
|
|
147
|
+
const payload = {
|
|
148
|
+
offeringId: offering.id,
|
|
149
|
+
code: chargeCode,
|
|
150
|
+
name: chargeForm.name,
|
|
151
|
+
description: chargeForm.description || null,
|
|
152
|
+
chargeType: chargeForm.chargeType,
|
|
153
|
+
pricingMethod: "flat",
|
|
154
|
+
fixedPrice: chargePrices[offering.id] || null,
|
|
155
|
+
currencyCode: chargeCurrency,
|
|
156
|
+
isActive: true,
|
|
157
|
+
sortOrder: 0
|
|
158
|
+
};
|
|
159
|
+
const res = await fetch("/api/cpq/product-charges", {
|
|
160
|
+
method: "POST",
|
|
161
|
+
headers: { "Content-Type": "application/json" },
|
|
162
|
+
body: JSON.stringify(payload)
|
|
163
|
+
});
|
|
164
|
+
if (!res.ok) {
|
|
165
|
+
const body = await res.json().catch(() => ({}));
|
|
166
|
+
setError(body.error ?? `Failed to save charge for ${offering.name}`);
|
|
167
|
+
setSaving(false);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
flash(t("cpq.offerings.flash.chargesCreated", "Charges created"), "success");
|
|
172
|
+
setBulkChargeOpen(false);
|
|
173
|
+
setBulkChargeTargets([]);
|
|
174
|
+
data.reload();
|
|
175
|
+
} catch {
|
|
176
|
+
setError("Failed to save charges");
|
|
177
|
+
} finally {
|
|
178
|
+
setSaving(false);
|
|
179
|
+
}
|
|
180
|
+
}, [
|
|
181
|
+
bulkChargeTargets,
|
|
182
|
+
chargeCurrency,
|
|
183
|
+
chargeForm,
|
|
184
|
+
chargePrices,
|
|
185
|
+
data,
|
|
186
|
+
t
|
|
187
|
+
]);
|
|
188
|
+
const columns = React.useMemo(
|
|
189
|
+
() => [
|
|
190
|
+
{
|
|
191
|
+
accessorKey: "code",
|
|
192
|
+
header: t("cpq.offerings.code", "Code"),
|
|
193
|
+
cell: ({ row }) => /* @__PURE__ */ jsx("span", { className: "font-mono text-xs", children: row.original.code })
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
accessorKey: "name",
|
|
197
|
+
header: t("cpq.offerings.name", "Name"),
|
|
198
|
+
cell: ({ row }) => /* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
|
|
199
|
+
row.original.name,
|
|
200
|
+
row.original.offeringType === "bundle" && /* @__PURE__ */ jsx(Tag, { variant: "brand", className: "ml-2 px-2 text-[10px]", children: "bundle" })
|
|
201
|
+
] })
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
accessorKey: "isActive",
|
|
205
|
+
header: t("cpq.offerings.isActive", "Is Active?"),
|
|
206
|
+
cell: ({ row }) => /* @__PURE__ */ jsx(Checkbox, { checked: row.original.isActive, disabled: true })
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
accessorKey: "lifecycleStatus",
|
|
210
|
+
header: t("cpq.offerings.lifecycleStatus", "Lifecycle Status"),
|
|
211
|
+
cell: ({ row }) => /* @__PURE__ */ jsx(Tag, { variant: lifecycleStatusMap[row.original.lifecycleStatus] ?? "neutral", dot: true, children: formatStatusLabel(row.original.lifecycleStatus) })
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
id: "charges",
|
|
215
|
+
header: t("cpq.offerings.charges", "Charges"),
|
|
216
|
+
cell: ({ row }) => {
|
|
217
|
+
const charges = row.original.charges ?? [];
|
|
218
|
+
if (charges.length === 0) return /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "\u2014" });
|
|
219
|
+
return /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", onClick: (e) => e.stopPropagation(), children: charges.map((ch) => /* @__PURE__ */ jsx(ChargePopover, { charge: ch }, ch.id)) });
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
accessorKey: "description",
|
|
224
|
+
header: t("cpq.offerings.description", "Description"),
|
|
225
|
+
cell: ({ row }) => /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: row.original.description ?? "\u2014" }),
|
|
226
|
+
meta: { truncate: true, maxWidth: 320 }
|
|
227
|
+
}
|
|
228
|
+
],
|
|
229
|
+
[t]
|
|
230
|
+
);
|
|
231
|
+
const bulkActions = React.useMemo(
|
|
232
|
+
() => [
|
|
233
|
+
{
|
|
234
|
+
id: "add-charge",
|
|
235
|
+
label: t("cpq.offerings.bulk.addCharge", "Add Charge"),
|
|
236
|
+
onExecute: (selectedRows) => {
|
|
237
|
+
if (!selectedRows.length) return { ok: false };
|
|
238
|
+
openBulkChargeForm(selectedRows);
|
|
239
|
+
return { ok: true };
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
],
|
|
243
|
+
[openBulkChargeForm, t]
|
|
244
|
+
);
|
|
245
|
+
const bulkChargeForm = bulkChargeOpen && bulkChargeTargets.length > 0 && /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card p-5 space-y-4", children: [
|
|
246
|
+
/* @__PURE__ */ jsxs("h4", { className: "font-medium text-sm", children: [
|
|
247
|
+
t("cpq.offerings.bulk.formTitle", "New Flat-Price Charge for"),
|
|
248
|
+
" ",
|
|
249
|
+
bulkChargeTargets.length,
|
|
250
|
+
" ",
|
|
251
|
+
bulkChargeTargets.length > 1 ? t("cpq.offerings.bulk.offeringsPlural", "offerings") : t("cpq.offerings.bulk.offeringsSingular", "offering")
|
|
252
|
+
] }),
|
|
253
|
+
/* @__PURE__ */ jsxs(Alert, { children: [
|
|
254
|
+
"Bulk creation supports ",
|
|
255
|
+
/* @__PURE__ */ jsx("strong", { children: "flat pricing only" }),
|
|
256
|
+
". For ",
|
|
257
|
+
/* @__PURE__ */ jsx("em", { children: "per unit" }),
|
|
258
|
+
" or ",
|
|
259
|
+
/* @__PURE__ */ jsx("em", { children: "tiered" }),
|
|
260
|
+
" pricing, open each offering individually \u2014 those methods need a pricing table and a numeric attribute that lives on the offering's spec, which usually differs between offerings."
|
|
261
|
+
] }),
|
|
262
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-3 gap-3", children: [
|
|
263
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
264
|
+
/* @__PURE__ */ jsx("label", { className: "block text-xs font-medium mb-1", children: "Code" }),
|
|
265
|
+
/* @__PURE__ */ jsx(
|
|
266
|
+
Input,
|
|
267
|
+
{
|
|
268
|
+
value: chargeForm.code,
|
|
269
|
+
onChange: (e) => setChargeForm({ ...chargeForm, code: e.target.value }),
|
|
270
|
+
placeholder: "e.g. mrc-monthly"
|
|
271
|
+
}
|
|
272
|
+
)
|
|
273
|
+
] }),
|
|
274
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
275
|
+
/* @__PURE__ */ jsx("label", { className: "block text-xs font-medium mb-1", children: "Name" }),
|
|
276
|
+
/* @__PURE__ */ jsx(
|
|
277
|
+
Input,
|
|
278
|
+
{
|
|
279
|
+
value: chargeForm.name,
|
|
280
|
+
onChange: (e) => setChargeForm({ ...chargeForm, name: e.target.value }),
|
|
281
|
+
placeholder: "e.g. Monthly Recurring"
|
|
282
|
+
}
|
|
283
|
+
)
|
|
284
|
+
] }),
|
|
285
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
286
|
+
/* @__PURE__ */ jsx("label", { className: "block text-xs font-medium mb-1", children: "Type" }),
|
|
287
|
+
/* @__PURE__ */ jsxs(
|
|
288
|
+
Select,
|
|
289
|
+
{
|
|
290
|
+
value: chargeForm.chargeType,
|
|
291
|
+
onValueChange: (value) => setChargeForm({ ...chargeForm, chargeType: value }),
|
|
292
|
+
children: [
|
|
293
|
+
/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, {}) }),
|
|
294
|
+
/* @__PURE__ */ jsxs(SelectContent, { children: [
|
|
295
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "nrc", children: "NRC (Non-Recurring)" }),
|
|
296
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "mrc", children: "MRC (Monthly Recurring)" }),
|
|
297
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "usage", children: "Usage" })
|
|
298
|
+
] })
|
|
299
|
+
]
|
|
300
|
+
}
|
|
301
|
+
)
|
|
302
|
+
] })
|
|
303
|
+
] }),
|
|
304
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
305
|
+
/* @__PURE__ */ jsx("label", { className: "block text-xs font-medium mb-1", children: "Description" }),
|
|
306
|
+
/* @__PURE__ */ jsx(
|
|
307
|
+
Input,
|
|
308
|
+
{
|
|
309
|
+
value: chargeForm.description,
|
|
310
|
+
onChange: (e) => setChargeForm({ ...chargeForm, description: e.target.value }),
|
|
311
|
+
placeholder: "User-facing charge description"
|
|
312
|
+
}
|
|
313
|
+
)
|
|
314
|
+
] }),
|
|
315
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
316
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
317
|
+
/* @__PURE__ */ jsx("label", { className: "text-xs font-medium", children: "Currency" }),
|
|
318
|
+
/* @__PURE__ */ jsx(
|
|
319
|
+
Input,
|
|
320
|
+
{
|
|
321
|
+
value: chargeCurrency,
|
|
322
|
+
onChange: (e) => setChargeCurrency(e.target.value.toUpperCase()),
|
|
323
|
+
maxLength: 3,
|
|
324
|
+
className: "w-20"
|
|
325
|
+
}
|
|
326
|
+
)
|
|
327
|
+
] }),
|
|
328
|
+
/* @__PURE__ */ jsx("div", { className: "rounded border", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-sm", children: [
|
|
329
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b bg-muted/30", children: [
|
|
330
|
+
/* @__PURE__ */ jsx("th", { className: "px-3 py-2 text-left font-medium text-xs", children: "Offering" }),
|
|
331
|
+
/* @__PURE__ */ jsxs("th", { className: "px-3 py-2 text-left font-medium text-xs", children: [
|
|
332
|
+
"Price (",
|
|
333
|
+
chargeCurrency,
|
|
334
|
+
")"
|
|
335
|
+
] })
|
|
336
|
+
] }) }),
|
|
337
|
+
/* @__PURE__ */ jsx("tbody", { children: bulkChargeTargets.map((o) => /* @__PURE__ */ jsxs("tr", { className: "border-b last:border-0", children: [
|
|
338
|
+
/* @__PURE__ */ jsxs("td", { className: "px-3 py-2 font-medium text-xs", children: [
|
|
339
|
+
o.name,
|
|
340
|
+
" ",
|
|
341
|
+
/* @__PURE__ */ jsxs("span", { className: "text-muted-foreground font-mono", children: [
|
|
342
|
+
"(",
|
|
343
|
+
o.code,
|
|
344
|
+
")"
|
|
345
|
+
] })
|
|
346
|
+
] }),
|
|
347
|
+
/* @__PURE__ */ jsx("td", { className: "px-3 py-2", children: /* @__PURE__ */ jsx(
|
|
348
|
+
NumberInput,
|
|
349
|
+
{
|
|
350
|
+
value: chargePrices[o.id] === void 0 || chargePrices[o.id] === "" ? null : Number(chargePrices[o.id]),
|
|
351
|
+
onChange: (n) => setChargePrices({ ...chargePrices, [o.id]: n == null ? "" : String(n) }),
|
|
352
|
+
placeholder: "0.00",
|
|
353
|
+
className: "w-32"
|
|
354
|
+
}
|
|
355
|
+
) })
|
|
356
|
+
] }, o.id)) })
|
|
357
|
+
] }) })
|
|
358
|
+
] }),
|
|
359
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2 pt-1", children: [
|
|
360
|
+
/* @__PURE__ */ jsx(
|
|
361
|
+
Button,
|
|
362
|
+
{
|
|
363
|
+
type: "button",
|
|
364
|
+
onClick: saveChargesForSelected,
|
|
365
|
+
disabled: saving || !chargeForm.code || !chargeForm.name,
|
|
366
|
+
children: saving ? "Saving..." : `Create Charge for ${bulkChargeTargets.length} Offering${bulkChargeTargets.length > 1 ? "s" : ""}`
|
|
367
|
+
}
|
|
368
|
+
),
|
|
369
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: () => setBulkChargeOpen(false), children: "Cancel" })
|
|
370
|
+
] })
|
|
371
|
+
] });
|
|
372
|
+
const toolbarContent = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
373
|
+
error && /* @__PURE__ */ jsx(Alert, { variant: "destructive", children: error }),
|
|
374
|
+
bulkChargeForm
|
|
375
|
+
] });
|
|
376
|
+
return /* @__PURE__ */ jsx(
|
|
377
|
+
CpqListView,
|
|
378
|
+
{
|
|
379
|
+
title: t("cpq.offerings.list.title", "Product Offerings"),
|
|
380
|
+
tableId: "cpq.offerings.list",
|
|
381
|
+
data,
|
|
382
|
+
columns,
|
|
383
|
+
filters,
|
|
384
|
+
pageSize: PAGE_SIZE,
|
|
385
|
+
searchPlaceholder: t("cpq.offerings.search.placeholder", "Search offerings..."),
|
|
386
|
+
actions: /* @__PURE__ */ jsx(Button, { asChild: true, children: /* @__PURE__ */ jsx("a", { href: "/backend/cpq/offerings/new", children: t("cpq.offerings.add", "New Offering") }) }),
|
|
387
|
+
bulkActions,
|
|
388
|
+
crud: {
|
|
389
|
+
endpoint: "/api/cpq/product-offerings",
|
|
390
|
+
entityName: t("cpq.offerings.entityName", "offering"),
|
|
391
|
+
editHref: (row) => `/backend/cpq/offerings/${row.id}`
|
|
392
|
+
},
|
|
393
|
+
onRowClick: (row) => router.push(`/backend/cpq/offerings/${row.id}`),
|
|
394
|
+
toolbarContent,
|
|
395
|
+
emptyState: /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground", children: t(
|
|
396
|
+
"cpq.offerings.empty",
|
|
397
|
+
"No product offerings found. Create one to define a sellable variant of a product specification."
|
|
398
|
+
) })
|
|
399
|
+
}
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
export {
|
|
403
|
+
OfferingsListPage as default
|
|
404
|
+
};
|
|
405
|
+
//# sourceMappingURL=page.js.map
|