@powerhousedao/service-offering 1.0.0-dev.11 → 1.0.0-dev.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/document-models/service-offering/v1/gen/controller.d.ts +4 -0
  2. package/dist/document-models/service-offering/v1/gen/controller.d.ts.map +1 -0
  3. package/dist/document-models/service-offering/v1/gen/controller.js +3 -0
  4. package/dist/document-models/service-offering/v1/gen/document-model.js +227 -227
  5. package/dist/document-models/service-offering/v1/gen/index.d.ts +1 -0
  6. package/dist/document-models/service-offering/v1/gen/index.d.ts.map +1 -1
  7. package/dist/document-models/service-offering/v1/gen/index.js +1 -2
  8. package/dist/document-models/service-offering/v1/gen/schema/types.d.ts +2 -0
  9. package/dist/document-models/service-offering/v1/gen/schema/types.d.ts.map +1 -1
  10. package/dist/document-models/service-offering/v1/gen/schema/zod.d.ts.map +1 -1
  11. package/dist/document-models/service-offering/v1/gen/schema/zod.js +2 -0
  12. package/dist/document-models/service-offering/v1/src/reducers/tiers.d.ts.map +1 -1
  13. package/dist/document-models/service-offering/v1/src/reducers/tiers.js +10 -0
  14. package/dist/document-models/service-offering/v1/src/utils.d.ts.map +1 -1
  15. package/dist/document-models/service-offering/v1/src/utils.js +7 -5
  16. package/dist/document-models/subscription-instance/v1/src/reducers/metrics.d.ts.map +1 -1
  17. package/dist/document-models/subscription-instance/v1/src/reducers/metrics.js +7 -6
  18. package/dist/document-models/subscription-instance/v1/src/reducers/utils.d.ts +7 -0
  19. package/dist/document-models/subscription-instance/v1/src/reducers/utils.d.ts.map +1 -0
  20. package/dist/document-models/subscription-instance/v1/src/reducers/utils.js +15 -0
  21. package/dist/document-models/subscription-instance/v1/tests/metrics.test.js +88 -1
  22. package/dist/document-models/upgrade-manifests.d.ts.map +1 -1
  23. package/dist/document-models/upgrade-manifests.js +2 -0
  24. package/dist/editors/service-offering-editor/components/TheMatrix.d.ts.map +1 -1
  25. package/dist/editors/service-offering-editor/components/TheMatrix.js +10 -5
  26. package/dist/editors/service-offering-editor/components/TierDefinition.d.ts.map +1 -1
  27. package/dist/editors/service-offering-editor/components/TierDefinition.js +9 -14
  28. package/dist/editors/subscription-instance-editor/components/mapOfferingToSubscription.d.ts.map +1 -1
  29. package/dist/editors/subscription-instance-editor/components/mapOfferingToSubscription.js +27 -3
  30. package/dist/powerhouse.manifest.json +12 -4
  31. package/dist/style.css +6 -0
  32. package/dist/subgraphs/resources-services/resolvers.d.ts.map +1 -1
  33. package/dist/subgraphs/resources-services/resolvers.js +11 -5
  34. package/package.json +1 -1
@@ -16,7 +16,7 @@ export const documentModel = {
16
16
  initialValue: "",
17
17
  },
18
18
  global: {
19
- schema: "type ServiceOfferingState {\n id: PHID\n operatorId: PHID\n resourceTemplateId: PHID\n title: String!\n summary: String!\n description: String\n thumbnailUrl: URL\n infoLink: URL\n status: ServiceStatus!\n lastModified: DateTime\n availableBillingCycles: [BillingCycle!]!\n facetTargets: [FacetTarget!]!\n services: [Service!]!\n tiers: [ServiceSubscriptionTier!]!\n optionGroups: [OptionGroup!]!\n}\n\nenum ServiceStatus {\n DRAFT\n COMING_SOON\n ACTIVE\n DEPRECATED\n}\n\ntype FacetTarget {\n id: OID!\n categoryKey: String!\n categoryLabel: String!\n selectedOptions: [String!]!\n}\n\ntype DiscountRule {\n discountType: DiscountType!\n discountValue: Float!\n}\n\nenum DiscountType {\n PERCENTAGE\n FLAT_AMOUNT\n}\n\ntype BillingCycleDiscount {\n billingCycle: BillingCycle!\n discountRule: DiscountRule!\n}\n\ntype SetupCost {\n amount: Amount_Money!\n currency: Currency!\n discount: DiscountRule\n}\n\ntype RecurringPriceOption {\n id: OID!\n billingCycle: BillingCycle!\n amount: Amount_Money!\n currency: Currency!\n discount: DiscountRule\n}\n\ntype Service {\n id: OID!\n title: String!\n description: String\n displayOrder: Int\n isSetupFormation: Boolean!\n optionGroupId: OID\n}\n\ntype ServiceSubscriptionTier {\n id: OID!\n name: String!\n description: String\n isCustomPricing: Boolean!\n pricingMode: TierPricingMode\n pricing: ServicePricing!\n defaultBillingCycle: BillingCycle\n billingCycleDiscounts: [BillingCycleDiscount!]!\n serviceLevels: [ServiceLevelBinding!]!\n usageLimits: [ServiceUsageLimit!]!\n}\n\ntype ServicePricing {\n amount: Amount_Money\n currency: Currency!\n}\n\nenum BillingCycle {\n MONTHLY\n QUARTERLY\n SEMI_ANNUAL\n ANNUAL\n ONE_TIME\n}\n\ntype ServiceLevelBinding {\n id: OID!\n serviceId: OID!\n level: ServiceLevel!\n customValue: String\n optionGroupId: OID\n}\n\nenum ServiceLevel {\n INCLUDED\n NOT_INCLUDED\n OPTIONAL\n CUSTOM\n VARIABLE\n NOT_APPLICABLE\n}\n\ntype ServiceUsageLimit {\n id: OID!\n serviceId: OID!\n metric: String!\n unitName: String\n freeLimit: Int\n paidLimit: Int\n resetCycle: UsageResetCycle\n notes: String\n unitPrice: Amount_Money\n unitPriceCurrency: Currency\n}\n\nenum UsageResetCycle {\n NONE\n HOURLY\n DAILY\n WEEKLY\n MONTHLY\n QUARTERLY\n SEMI_ANNUAL\n ANNUAL\n}\n\ntype OptionGroup {\n id: OID!\n name: String!\n description: String\n isAddOn: Boolean!\n defaultSelected: Boolean!\n pricingMode: AddOnPricingMode\n standalonePricing: StandalonePricing\n tierDependentPricing: [OptionGroupTierPricing!]\n costType: GroupCostType\n availableBillingCycles: [BillingCycle!]!\n billingCycleDiscounts: [BillingCycleDiscount!]!\n discountMode: DiscountMode\n price: Amount_Money\n currency: Currency\n}\n\nenum AddOnPricingMode {\n TIER_DEPENDENT\n STANDALONE\n}\n\nenum DiscountMode {\n INHERIT_TIER\n INDEPENDENT\n}\n\nenum TierPricingMode {\n CALCULATED\n MANUAL_OVERRIDE\n}\n\ntype StandalonePricing {\n setupCost: SetupCost\n recurringPricing: [RecurringPriceOption!]!\n}\n\ntype OptionGroupTierPricing {\n id: OID!\n tierId: OID!\n setupCost: SetupCost\n setupCostDiscounts: [BillingCycleDiscount!]!\n recurringPricing: [RecurringPriceOption!]!\n}\n\nenum GroupCostType {\n RECURRING\n SETUP\n}",
19
+ schema: "type ServiceOfferingState {\n id: PHID\n operatorId: PHID\n resourceTemplateId: PHID\n title: String!\n summary: String!\n description: String\n thumbnailUrl: URL\n infoLink: URL\n status: ServiceStatus!\n lastModified: DateTime\n availableBillingCycles: [BillingCycle!]!\n facetTargets: [FacetTarget!]!\n services: [Service!]!\n tiers: [ServiceSubscriptionTier!]!\n optionGroups: [OptionGroup!]!\n}\n\nenum ServiceStatus {\n DRAFT\n COMING_SOON\n ACTIVE\n DEPRECATED\n}\n\ntype FacetTarget {\n id: OID!\n categoryKey: String!\n categoryLabel: String!\n selectedOptions: [String!]!\n}\n\ntype DiscountRule {\n discountType: DiscountType!\n discountValue: Float!\n}\n\nenum DiscountType {\n PERCENTAGE\n FLAT_AMOUNT\n}\n\ntype BillingCycleDiscount {\n billingCycle: BillingCycle!\n discountRule: DiscountRule!\n}\n\ntype SetupCost {\n amount: Amount_Money!\n currency: Currency!\n discount: DiscountRule\n}\n\ntype RecurringPriceOption {\n id: OID!\n billingCycle: BillingCycle!\n amount: Amount_Money!\n currency: Currency!\n discount: DiscountRule\n}\n\ntype Service {\n id: OID!\n title: String!\n description: String\n displayOrder: Int\n isSetupFormation: Boolean!\n optionGroupId: OID\n}\n\ntype ServiceSubscriptionTier {\n id: OID!\n name: String!\n description: String\n isCustomPricing: Boolean!\n pricingMode: TierPricingMode\n pricing: ServicePricing!\n defaultBillingCycle: BillingCycle\n mostPopular: Boolean!\n billingCycleDiscounts: [BillingCycleDiscount!]!\n serviceLevels: [ServiceLevelBinding!]!\n usageLimits: [ServiceUsageLimit!]!\n}\n\ntype ServicePricing {\n amount: Amount_Money\n currency: Currency!\n}\n\nenum BillingCycle {\n MONTHLY\n QUARTERLY\n SEMI_ANNUAL\n ANNUAL\n ONE_TIME\n}\n\ntype ServiceLevelBinding {\n id: OID!\n serviceId: OID!\n level: ServiceLevel!\n customValue: String\n optionGroupId: OID\n}\n\nenum ServiceLevel {\n INCLUDED\n NOT_INCLUDED\n OPTIONAL\n CUSTOM\n VARIABLE\n NOT_APPLICABLE\n}\n\ntype ServiceUsageLimit {\n id: OID!\n serviceId: OID!\n metric: String!\n unitName: String\n freeLimit: Int\n paidLimit: Int\n resetCycle: UsageResetCycle\n notes: String\n unitPrice: Amount_Money\n unitPriceCurrency: Currency\n}\n\nenum UsageResetCycle {\n NONE\n HOURLY\n DAILY\n WEEKLY\n MONTHLY\n QUARTERLY\n SEMI_ANNUAL\n ANNUAL\n}\n\ntype OptionGroup {\n id: OID!\n name: String!\n description: String\n isAddOn: Boolean!\n defaultSelected: Boolean!\n pricingMode: AddOnPricingMode\n standalonePricing: StandalonePricing\n tierDependentPricing: [OptionGroupTierPricing!]\n costType: GroupCostType\n availableBillingCycles: [BillingCycle!]!\n billingCycleDiscounts: [BillingCycleDiscount!]!\n discountMode: DiscountMode\n price: Amount_Money\n currency: Currency\n}\n\nenum AddOnPricingMode {\n TIER_DEPENDENT\n STANDALONE\n}\n\nenum DiscountMode {\n INHERIT_TIER\n INDEPENDENT\n}\n\nenum TierPricingMode {\n CALCULATED\n MANUAL_OVERRIDE\n}\n\ntype StandalonePricing {\n setupCost: SetupCost\n recurringPricing: [RecurringPriceOption!]!\n}\n\ntype OptionGroupTierPricing {\n id: OID!\n tierId: OID!\n setupCost: SetupCost\n setupCostDiscounts: [BillingCycleDiscount!]!\n recurringPricing: [RecurringPriceOption!]!\n}\n\nenum GroupCostType {\n RECURRING\n SETUP\n}",
20
20
  examples: [],
21
21
  initialValue: '{\n "id": null,\n "operatorId": null,\n "resourceTemplateId": null,\n "title": "",\n "summary": "",\n "description": null,\n "thumbnailUrl": null,\n "infoLink": null,\n "status": "DRAFT",\n "lastModified": null,\n "availableBillingCycles": [],\n "facetTargets": [],\n "services": [],\n "tiers": [],\n "optionGroups": []\n}',
22
22
  },
@@ -25,637 +25,637 @@ export const documentModel = {
25
25
  {
26
26
  id: "mod-offering",
27
27
  name: "offering",
28
- description: "Offering-level metadata, status, target audiences, facet targets, and resource templates",
29
28
  operations: [
30
29
  {
31
30
  id: "op-update-offering-info",
32
31
  name: "UPDATE_OFFERING_INFO",
33
- description: "Update offering title, summary, description, URLs",
32
+ scope: "global",
33
+ errors: [],
34
34
  schema: "input UpdateOfferingInfoInput {\n title: String\n summary: String\n description: String\n thumbnailUrl: URL\n infoLink: URL\n lastModified: DateTime!\n}",
35
- template: "Update offering title, summary, description, URLs",
36
35
  reducer: "if (action.input.title) state.title = action.input.title;\nif (action.input.summary) state.summary = action.input.summary;\nif (action.input.description !== undefined) state.description = action.input.description || null;\nif (action.input.thumbnailUrl !== undefined) state.thumbnailUrl = action.input.thumbnailUrl || null;\nif (action.input.infoLink !== undefined) state.infoLink = action.input.infoLink || null;\nstate.lastModified = action.input.lastModified;",
37
- errors: [],
38
36
  examples: [],
39
- scope: "global",
37
+ template: "Update offering title, summary, description, URLs",
38
+ description: "Update offering title, summary, description, URLs",
40
39
  },
41
40
  {
42
41
  id: "op-update-offering-status",
43
42
  name: "UPDATE_OFFERING_STATUS",
44
- description: "Change offering status",
43
+ scope: "global",
44
+ errors: [],
45
45
  schema: "input UpdateOfferingStatusInput {\n status: ServiceStatus!\n lastModified: DateTime!\n}",
46
- template: "Change offering status",
47
46
  reducer: "state.status = action.input.status;\nstate.lastModified = action.input.lastModified;",
48
- errors: [],
49
47
  examples: [],
50
- scope: "global",
48
+ template: "Change offering status",
49
+ description: "Change offering status",
51
50
  },
52
51
  {
53
52
  id: "op-set-operator",
54
53
  name: "SET_OPERATOR",
55
- description: "Set operator ID",
54
+ scope: "global",
55
+ errors: [],
56
56
  schema: "input SetOperatorInput {\n operatorId: PHID!\n lastModified: DateTime!\n}",
57
- template: "Set operator ID",
58
57
  reducer: "state.operatorId = action.input.operatorId;\nstate.lastModified = action.input.lastModified;",
59
- errors: [],
60
58
  examples: [],
61
- scope: "global",
59
+ template: "Set operator ID",
60
+ description: "Set operator ID",
62
61
  },
63
62
  {
64
63
  id: "op-set-offering-id",
65
64
  name: "SET_OFFERING_ID",
66
- description: "Set offering ID",
65
+ scope: "global",
66
+ errors: [],
67
67
  schema: "input SetOfferingIdInput {\n id: PHID!\n lastModified: DateTime!\n}",
68
- template: "Set offering ID",
69
68
  reducer: "state.id = action.input.id;\nstate.lastModified = action.input.lastModified;",
70
- errors: [],
71
69
  examples: [],
72
- scope: "global",
70
+ template: "Set offering ID",
71
+ description: "Set offering ID",
73
72
  },
74
73
  {
75
74
  id: "op-set-facet-target",
76
75
  name: "SET_FACET_TARGET",
77
- description: "Set or upsert a facet target category",
76
+ scope: "global",
77
+ errors: [],
78
78
  schema: "input SetFacetTargetInput {\n id: OID!\n categoryKey: String!\n categoryLabel: String!\n selectedOptions: [String!]!\n lastModified: DateTime!\n}",
79
- template: "Set or upsert a facet target category",
80
79
  reducer: "const existingIndex = state.facetTargets.findIndex(ft => ft.categoryKey === action.input.categoryKey);\nconst facetTarget = {\n id: action.input.id,\n categoryKey: action.input.categoryKey,\n categoryLabel: action.input.categoryLabel,\n selectedOptions: action.input.selectedOptions,\n};\nif (existingIndex !== -1) {\n state.facetTargets[existingIndex] = facetTarget;\n} else {\n state.facetTargets.push(facetTarget);\n}\nstate.lastModified = action.input.lastModified;",
81
- errors: [],
82
80
  examples: [],
83
- scope: "global",
81
+ template: "Set or upsert a facet target category",
82
+ description: "Set or upsert a facet target category",
84
83
  },
85
84
  {
86
85
  id: "op-remove-facet-target",
87
86
  name: "REMOVE_FACET_TARGET",
88
- description: "Remove a facet target by category key",
89
- schema: "input RemoveFacetTargetInput {\n categoryKey: String!\n lastModified: DateTime!\n}",
90
- template: "Remove a facet target by category key",
91
- reducer: "const index = state.facetTargets.findIndex(ft => ft.categoryKey === action.input.categoryKey);\nif (index === -1) {\n throw new RemoveFacetTargetNotFoundError(`Facet target with category key ${action.input.categoryKey} not found`);\n}\nstate.facetTargets.splice(index, 1);\nstate.lastModified = action.input.lastModified;",
87
+ scope: "global",
92
88
  errors: [
93
89
  {
94
90
  id: "err-remove-ft-not-found",
95
- name: "RemoveFacetTargetNotFoundError",
96
91
  code: "FACET_TARGET_NOT_FOUND",
97
- description: "Facet target with given category key not found",
92
+ name: "RemoveFacetTargetNotFoundError",
98
93
  template: "",
94
+ description: "Facet target with given category key not found",
99
95
  },
100
96
  ],
97
+ schema: "input RemoveFacetTargetInput {\n categoryKey: String!\n lastModified: DateTime!\n}",
98
+ reducer: "const index = state.facetTargets.findIndex(ft => ft.categoryKey === action.input.categoryKey);\nif (index === -1) {\n throw new RemoveFacetTargetNotFoundError(`Facet target with category key ${action.input.categoryKey} not found`);\n}\nstate.facetTargets.splice(index, 1);\nstate.lastModified = action.input.lastModified;",
101
99
  examples: [],
102
- scope: "global",
100
+ template: "Remove a facet target by category key",
101
+ description: "Remove a facet target by category key",
103
102
  },
104
103
  {
105
104
  id: "op-add-facet-option",
106
105
  name: "ADD_FACET_OPTION",
107
- description: "Add an option to an existing facet target",
108
- schema: "input AddFacetOptionInput {\n categoryKey: String!\n optionId: String!\n lastModified: DateTime!\n}",
109
- template: "Add an option to an existing facet target",
110
- reducer: "const facetTarget = state.facetTargets.find(ft => ft.categoryKey === action.input.categoryKey);\nif (!facetTarget) {\n throw new AddFacetOptionTargetNotFoundError(`Facet target with category key ${action.input.categoryKey} not found`);\n}\nfacetTarget.selectedOptions.push(action.input.optionId);\nstate.lastModified = action.input.lastModified;",
106
+ scope: "global",
111
107
  errors: [
112
108
  {
113
109
  id: "err-add-fo-target-not-found",
114
- name: "AddFacetOptionTargetNotFoundError",
115
110
  code: "FACET_TARGET_NOT_FOUND",
116
- description: "Facet target with given category key not found",
111
+ name: "AddFacetOptionTargetNotFoundError",
117
112
  template: "",
113
+ description: "Facet target with given category key not found",
118
114
  },
119
115
  ],
116
+ schema: "input AddFacetOptionInput {\n categoryKey: String!\n optionId: String!\n lastModified: DateTime!\n}",
117
+ reducer: "const facetTarget = state.facetTargets.find(ft => ft.categoryKey === action.input.categoryKey);\nif (!facetTarget) {\n throw new AddFacetOptionTargetNotFoundError(`Facet target with category key ${action.input.categoryKey} not found`);\n}\nfacetTarget.selectedOptions.push(action.input.optionId);\nstate.lastModified = action.input.lastModified;",
120
118
  examples: [],
121
- scope: "global",
119
+ template: "Add an option to an existing facet target",
120
+ description: "Add an option to an existing facet target",
122
121
  },
123
122
  {
124
123
  id: "op-remove-facet-option",
125
124
  name: "REMOVE_FACET_OPTION",
126
- description: "Remove an option from a facet target",
127
- schema: "input RemoveFacetOptionInput {\n categoryKey: String!\n optionId: String!\n lastModified: DateTime!\n}",
128
- template: "Remove an option from a facet target",
129
- reducer: "const facetTarget = state.facetTargets.find(ft => ft.categoryKey === action.input.categoryKey);\nif (!facetTarget) {\n throw new RemoveFacetOptionTargetNotFoundError(`Facet target with category key ${action.input.categoryKey} not found`);\n}\nconst optIndex = facetTarget.selectedOptions.indexOf(action.input.optionId);\nif (optIndex !== -1) {\n facetTarget.selectedOptions.splice(optIndex, 1);\n}\nstate.lastModified = action.input.lastModified;",
125
+ scope: "global",
130
126
  errors: [
131
127
  {
132
128
  id: "err-remove-fo-target-not-found",
133
- name: "RemoveFacetOptionTargetNotFoundError",
134
129
  code: "FACET_TARGET_NOT_FOUND",
135
- description: "Facet target with given category key not found",
130
+ name: "RemoveFacetOptionTargetNotFoundError",
136
131
  template: "",
132
+ description: "Facet target with given category key not found",
137
133
  },
138
134
  ],
135
+ schema: "input RemoveFacetOptionInput {\n categoryKey: String!\n optionId: String!\n lastModified: DateTime!\n}",
136
+ reducer: "const facetTarget = state.facetTargets.find(ft => ft.categoryKey === action.input.categoryKey);\nif (!facetTarget) {\n throw new RemoveFacetOptionTargetNotFoundError(`Facet target with category key ${action.input.categoryKey} not found`);\n}\nconst optIndex = facetTarget.selectedOptions.indexOf(action.input.optionId);\nif (optIndex !== -1) {\n facetTarget.selectedOptions.splice(optIndex, 1);\n}\nstate.lastModified = action.input.lastModified;",
139
137
  examples: [],
140
- scope: "global",
138
+ template: "Remove an option from a facet target",
139
+ description: "Remove an option from a facet target",
141
140
  },
142
141
  {
143
142
  id: "op-select-resource-template",
144
143
  name: "SELECT_RESOURCE_TEMPLATE",
145
- description: "Select a resource template",
144
+ scope: "global",
145
+ errors: [],
146
146
  schema: "input SelectResourceTemplateInput {\n resourceTemplateId: PHID!\n lastModified: DateTime!\n}",
147
- template: "Select a resource template",
148
147
  reducer: "state.resourceTemplateId = action.input.resourceTemplateId;\nstate.lastModified = action.input.lastModified;",
149
- errors: [],
150
148
  examples: [],
151
- scope: "global",
149
+ template: "Select a resource template",
150
+ description: "Select a resource template",
152
151
  },
153
152
  {
154
153
  id: "op-change-resource-template",
155
154
  name: "CHANGE_RESOURCE_TEMPLATE",
156
- description: "Change the resource template",
157
- schema: "input ChangeResourceTemplateInput {\n previousTemplateId: PHID!\n newTemplateId: PHID!\n lastModified: DateTime!\n}",
158
- template: "Change the resource template",
159
- reducer: "if (state.resourceTemplateId !== action.input.previousTemplateId) {\n throw new ChangeResourceTemplateMismatchError(`Current template ${state.resourceTemplateId} does not match previous template ${action.input.previousTemplateId}`);\n}\nstate.resourceTemplateId = action.input.newTemplateId;\nstate.lastModified = action.input.lastModified;",
155
+ scope: "global",
160
156
  errors: [
161
157
  {
162
158
  id: "err-change-rt-mismatch",
163
- name: "ChangeResourceTemplateMismatchError",
164
159
  code: "TEMPLATE_MISMATCH",
165
- description: "The previous template ID does not match the current resource template",
160
+ name: "ChangeResourceTemplateMismatchError",
166
161
  template: "",
162
+ description: "The previous template ID does not match the current resource template",
167
163
  },
168
164
  ],
165
+ schema: "input ChangeResourceTemplateInput {\n previousTemplateId: PHID!\n newTemplateId: PHID!\n lastModified: DateTime!\n}",
166
+ reducer: "if (state.resourceTemplateId !== action.input.previousTemplateId) {\n throw new ChangeResourceTemplateMismatchError(`Current template ${state.resourceTemplateId} does not match previous template ${action.input.previousTemplateId}`);\n}\nstate.resourceTemplateId = action.input.newTemplateId;\nstate.lastModified = action.input.lastModified;",
169
167
  examples: [],
170
- scope: "global",
168
+ template: "Change the resource template",
169
+ description: "Change the resource template",
171
170
  },
172
171
  {
173
172
  id: "op-set-available-billing-cycles",
174
173
  name: "SET_AVAILABLE_BILLING_CYCLES",
175
- description: "Set the available billing cycles for the offering",
176
- schema: "input SetAvailableBillingCyclesInput {\n billingCycles: [BillingCycle!]!\n lastModified: DateTime!\n}",
177
- template: "Set the available billing cycles for the offering",
178
- reducer: 'if (action.input.billingCycles.length === 0) {\n throw new NoBillingCyclesSelectedError("At least one billing cycle must be selected");\n}\nstate.availableBillingCycles = action.input.billingCycles;\nstate.lastModified = action.input.lastModified;',
174
+ scope: "global",
179
175
  errors: [
180
176
  {
181
177
  id: "err-no-billing-cycles",
182
- name: "NoBillingCyclesSelectedError",
183
178
  code: "NO_BILLING_CYCLES_SELECTED",
184
- description: "At least one billing cycle must be selected",
179
+ name: "NoBillingCyclesSelectedError",
185
180
  template: "",
181
+ description: "At least one billing cycle must be selected",
186
182
  },
187
183
  ],
184
+ schema: "input SetAvailableBillingCyclesInput {\n billingCycles: [BillingCycle!]!\n lastModified: DateTime!\n}",
185
+ reducer: 'if (action.input.billingCycles.length === 0) {\n throw new NoBillingCyclesSelectedError("At least one billing cycle must be selected");\n}\nstate.availableBillingCycles = action.input.billingCycles;\nstate.lastModified = action.input.lastModified;',
188
186
  examples: [],
189
- scope: "global",
187
+ template: "Set the available billing cycles for the offering",
188
+ description: "Set the available billing cycles for the offering",
190
189
  },
191
190
  ],
191
+ description: "Offering-level metadata, status, target audiences, facet targets, and resource templates",
192
192
  },
193
193
  {
194
194
  id: "mod-services",
195
195
  name: "services",
196
- description: "Service CRUD and facet bindings",
197
196
  operations: [
198
197
  {
199
198
  id: "op-add-service",
200
199
  name: "ADD_SERVICE",
201
- description: "Add a new service",
200
+ scope: "global",
201
+ errors: [],
202
202
  schema: "input AddServiceInput {\n id: OID!\n title: String!\n description: String\n displayOrder: Int\n isSetupFormation: Boolean\n optionGroupId: OID\n lastModified: DateTime!\n}",
203
- template: "Add a new service",
204
203
  reducer: "state.services.push({\n id: action.input.id,\n title: action.input.title,\n description: action.input.description || null,\n displayOrder: action.input.displayOrder || null,\n isSetupFormation: action.input.isSetupFormation || false,\n optionGroupId: action.input.optionGroupId || null,\n});\nstate.lastModified = action.input.lastModified;",
205
- errors: [],
206
204
  examples: [],
207
- scope: "global",
205
+ template: "Add a new service",
206
+ description: "Add a new service",
208
207
  },
209
208
  {
210
209
  id: "op-update-service",
211
210
  name: "UPDATE_SERVICE",
212
- description: "Update service fields",
213
- schema: "input UpdateServiceInput {\n id: OID!\n title: String\n description: String\n displayOrder: Int\n isSetupFormation: Boolean\n optionGroupId: OID\n lastModified: DateTime!\n}",
214
- template: "Update service fields",
215
- reducer: "const service = state.services.find((s) => s.id === action.input.id);\nif (!service) {\n throw new UpdateServiceNotFoundError(`Service with ID ${action.input.id} not found`);\n}\nif (action.input.title) service.title = action.input.title;\nif (action.input.description !== undefined) service.description = action.input.description || null;\nif (action.input.displayOrder !== undefined) service.displayOrder = action.input.displayOrder || null;\nif (action.input.isSetupFormation !== undefined && action.input.isSetupFormation !== null) service.isSetupFormation = action.input.isSetupFormation;\nif (action.input.optionGroupId !== undefined) service.optionGroupId = action.input.optionGroupId || null;\nstate.lastModified = action.input.lastModified;",
211
+ scope: "global",
216
212
  errors: [
217
213
  {
218
214
  id: "err-update-service-not-found",
219
- name: "UpdateServiceNotFoundError",
220
215
  code: "SERVICE_NOT_FOUND",
221
- description: "Service with given ID not found",
216
+ name: "UpdateServiceNotFoundError",
222
217
  template: "",
218
+ description: "Service with given ID not found",
223
219
  },
224
220
  ],
221
+ schema: "input UpdateServiceInput {\n id: OID!\n title: String\n description: String\n displayOrder: Int\n isSetupFormation: Boolean\n optionGroupId: OID\n lastModified: DateTime!\n}",
222
+ reducer: "const service = state.services.find((s) => s.id === action.input.id);\nif (!service) {\n throw new UpdateServiceNotFoundError(`Service with ID ${action.input.id} not found`);\n}\nif (action.input.title) service.title = action.input.title;\nif (action.input.description !== undefined) service.description = action.input.description || null;\nif (action.input.displayOrder !== undefined) service.displayOrder = action.input.displayOrder || null;\nif (action.input.isSetupFormation !== undefined && action.input.isSetupFormation !== null) service.isSetupFormation = action.input.isSetupFormation;\nif (action.input.optionGroupId !== undefined) service.optionGroupId = action.input.optionGroupId || null;\nstate.lastModified = action.input.lastModified;",
225
223
  examples: [],
226
- scope: "global",
224
+ template: "Update service fields",
225
+ description: "Update service fields",
227
226
  },
228
227
  {
229
228
  id: "op-delete-service",
230
229
  name: "DELETE_SERVICE",
231
- description: "Delete a service",
232
- schema: "input DeleteServiceInput {\n id: OID!\n lastModified: DateTime!\n}",
233
- template: "Delete a service",
234
- reducer: "const index = state.services.findIndex(s => s.id === action.input.id);\nif (index === -1) {\n throw new DeleteServiceNotFoundError(`Service with ID ${action.input.id} not found`);\n}\nstate.services.splice(index, 1);\nstate.lastModified = action.input.lastModified;",
230
+ scope: "global",
235
231
  errors: [
236
232
  {
237
233
  id: "err-delete-service-not-found",
238
- name: "DeleteServiceNotFoundError",
239
234
  code: "SERVICE_NOT_FOUND",
240
- description: "Service with given ID not found",
235
+ name: "DeleteServiceNotFoundError",
241
236
  template: "",
237
+ description: "Service with given ID not found",
242
238
  },
243
239
  ],
240
+ schema: "input DeleteServiceInput {\n id: OID!\n lastModified: DateTime!\n}",
241
+ reducer: "const index = state.services.findIndex(s => s.id === action.input.id);\nif (index === -1) {\n throw new DeleteServiceNotFoundError(`Service with ID ${action.input.id} not found`);\n}\nstate.services.splice(index, 1);\nstate.lastModified = action.input.lastModified;",
244
242
  examples: [],
245
- scope: "global",
243
+ template: "Delete a service",
244
+ description: "Delete a service",
246
245
  },
247
246
  ],
247
+ description: "Service CRUD and facet bindings",
248
248
  },
249
249
  {
250
250
  id: "mod-tiers",
251
251
  name: "tiers",
252
- description: "Subscription tiers, service levels, usage limits, billing cycles, and discounts",
253
252
  operations: [
254
253
  {
255
254
  id: "op-add-tier",
256
255
  name: "ADD_TIER",
257
- description: "Add a subscription tier",
256
+ scope: "global",
257
+ errors: [],
258
258
  schema: "input AddTierInput {\n id: OID!\n name: String!\n description: String\n amount: Amount_Money\n currency: Currency!\n isCustomPricing: Boolean\n lastModified: DateTime!\n}",
259
- template: "Add a subscription tier",
260
259
  reducer: "state.tiers.push({\n id: action.input.id,\n name: action.input.name,\n description: action.input.description || null,\n isCustomPricing: action.input.isCustomPricing || false,\n pricingMode: null,\n pricing: {\n amount: action.input.amount || null,\n currency: action.input.currency,\n },\n defaultBillingCycle: null,\n billingCycleDiscounts: [],\n serviceLevels: [],\n usageLimits: [],\n});\nstate.lastModified = action.input.lastModified;",
261
- errors: [],
262
260
  examples: [],
263
- scope: "global",
261
+ template: "Add a subscription tier",
262
+ description: "Add a subscription tier",
264
263
  },
265
264
  {
266
265
  id: "op-update-tier",
267
266
  name: "UPDATE_TIER",
268
- description: "Update tier metadata",
269
- schema: "input UpdateTierInput {\n id: OID!\n name: String\n description: String\n isCustomPricing: Boolean\n lastModified: DateTime!\n}",
270
- template: "Update tier metadata",
271
- reducer: "const tier = state.tiers.find(t => t.id === action.input.id);\nif (!tier) {\n throw new UpdateTierNotFoundError(`Tier with ID ${action.input.id} not found`);\n}\nif (action.input.name) tier.name = action.input.name;\nif (action.input.description !== undefined) tier.description = action.input.description || null;\nif (action.input.isCustomPricing !== undefined && action.input.isCustomPricing !== null) tier.isCustomPricing = action.input.isCustomPricing;\nstate.lastModified = action.input.lastModified;",
267
+ scope: "global",
272
268
  errors: [
273
269
  {
274
270
  id: "err-update-tier-not-found",
275
- name: "UpdateTierNotFoundError",
276
271
  code: "TIER_NOT_FOUND",
277
- description: "Tier with given ID not found",
272
+ name: "UpdateTierNotFoundError",
278
273
  template: "",
274
+ description: "Tier with given ID not found",
279
275
  },
280
276
  ],
277
+ schema: "input UpdateTierInput {\n id: OID!\n name: String\n description: String\n isCustomPricing: Boolean\n lastModified: DateTime!\n mostPopular: Boolean\n}",
278
+ reducer: "const tier = state.tiers.find(t => t.id === action.input.id);\nif (!tier) {\n throw new UpdateTierNotFoundError(`Tier with ID ${action.input.id} not found`);\n}\nif (action.input.name) tier.name = action.input.name;\nif (action.input.description !== undefined) tier.description = action.input.description || null;\nif (action.input.isCustomPricing !== undefined && action.input.isCustomPricing !== null) tier.isCustomPricing = action.input.isCustomPricing;\nstate.lastModified = action.input.lastModified;",
281
279
  examples: [],
282
- scope: "global",
280
+ template: "Update tier metadata",
281
+ description: "Update tier metadata",
283
282
  },
284
283
  {
285
284
  id: "op-update-tier-pricing",
286
285
  name: "UPDATE_TIER_PRICING",
287
- description: "Update tier base pricing",
288
- schema: "input UpdateTierPricingInput {\n tierId: OID!\n amount: Amount_Money\n currency: Currency\n lastModified: DateTime!\n}",
289
- template: "Update tier base pricing",
290
- reducer: "const tier = state.tiers.find(t => t.id === action.input.tierId);\nif (!tier) {\n throw new UpdateTierPricingNotFoundError(`Tier with ID ${action.input.tierId} not found`);\n}\nif (action.input.amount !== undefined) tier.pricing.amount = action.input.amount || null;\nif (action.input.currency) tier.pricing.currency = action.input.currency;\nstate.lastModified = action.input.lastModified;",
286
+ scope: "global",
291
287
  errors: [
292
288
  {
293
289
  id: "err-update-tier-pricing-not-found",
294
- name: "UpdateTierPricingNotFoundError",
295
290
  code: "TIER_NOT_FOUND",
296
- description: "Tier with given ID not found",
291
+ name: "UpdateTierPricingNotFoundError",
297
292
  template: "",
293
+ description: "Tier with given ID not found",
298
294
  },
299
295
  ],
296
+ schema: "input UpdateTierPricingInput {\n tierId: OID!\n amount: Amount_Money\n currency: Currency\n lastModified: DateTime!\n}",
297
+ reducer: "const tier = state.tiers.find(t => t.id === action.input.tierId);\nif (!tier) {\n throw new UpdateTierPricingNotFoundError(`Tier with ID ${action.input.tierId} not found`);\n}\nif (action.input.amount !== undefined) tier.pricing.amount = action.input.amount || null;\nif (action.input.currency) tier.pricing.currency = action.input.currency;\nstate.lastModified = action.input.lastModified;",
300
298
  examples: [],
301
- scope: "global",
299
+ template: "Update tier base pricing",
300
+ description: "Update tier base pricing",
302
301
  },
303
302
  {
304
303
  id: "op-delete-tier",
305
304
  name: "DELETE_TIER",
306
- description: "Delete a tier",
307
- schema: "input DeleteTierInput {\n id: OID!\n lastModified: DateTime!\n}",
308
- template: "Delete a tier",
309
- reducer: "const index = state.tiers.findIndex(t => t.id === action.input.id);\nif (index === -1) {\n throw new DeleteTierNotFoundError(`Tier with ID ${action.input.id} not found`);\n}\nstate.tiers.splice(index, 1);\nstate.lastModified = action.input.lastModified;",
305
+ scope: "global",
310
306
  errors: [
311
307
  {
312
308
  id: "err-delete-tier-not-found",
313
- name: "DeleteTierNotFoundError",
314
309
  code: "TIER_NOT_FOUND",
315
- description: "Tier with given ID not found",
310
+ name: "DeleteTierNotFoundError",
316
311
  template: "",
312
+ description: "Tier with given ID not found",
317
313
  },
318
314
  ],
315
+ schema: "input DeleteTierInput {\n id: OID!\n lastModified: DateTime!\n}",
316
+ reducer: "const index = state.tiers.findIndex(t => t.id === action.input.id);\nif (index === -1) {\n throw new DeleteTierNotFoundError(`Tier with ID ${action.input.id} not found`);\n}\nstate.tiers.splice(index, 1);\nstate.lastModified = action.input.lastModified;",
319
317
  examples: [],
320
- scope: "global",
318
+ template: "Delete a tier",
319
+ description: "Delete a tier",
321
320
  },
322
321
  {
323
322
  id: "op-add-service-level",
324
323
  name: "ADD_SERVICE_LEVEL",
325
- description: "Bind a service level to a tier",
326
- schema: "input AddServiceLevelInput {\n tierId: OID!\n serviceLevelId: OID!\n serviceId: OID!\n level: ServiceLevel!\n optionGroupId: OID\n customValue: String\n lastModified: DateTime!\n}",
327
- template: "Bind a service level to a tier",
328
- reducer: "const tier = state.tiers.find(t => t.id === action.input.tierId);\nif (!tier) {\n throw new AddServiceLevelTierNotFoundError(`Tier with ID ${action.input.tierId} not found`);\n}\ntier.serviceLevels.push({\n id: action.input.serviceLevelId,\n serviceId: action.input.serviceId,\n level: action.input.level,\n customValue: action.input.customValue || null,\n optionGroupId: action.input.optionGroupId || null,\n});\nstate.lastModified = action.input.lastModified;",
324
+ scope: "global",
329
325
  errors: [
330
326
  {
331
327
  id: "err-add-sl-tier-not-found",
332
- name: "AddServiceLevelTierNotFoundError",
333
328
  code: "TIER_NOT_FOUND",
334
- description: "Tier with given ID not found",
329
+ name: "AddServiceLevelTierNotFoundError",
335
330
  template: "",
331
+ description: "Tier with given ID not found",
336
332
  },
337
333
  ],
334
+ schema: "input AddServiceLevelInput {\n tierId: OID!\n serviceLevelId: OID!\n serviceId: OID!\n level: ServiceLevel!\n optionGroupId: OID\n customValue: String\n lastModified: DateTime!\n}",
335
+ reducer: "const tier = state.tiers.find(t => t.id === action.input.tierId);\nif (!tier) {\n throw new AddServiceLevelTierNotFoundError(`Tier with ID ${action.input.tierId} not found`);\n}\ntier.serviceLevels.push({\n id: action.input.serviceLevelId,\n serviceId: action.input.serviceId,\n level: action.input.level,\n customValue: action.input.customValue || null,\n optionGroupId: action.input.optionGroupId || null,\n});\nstate.lastModified = action.input.lastModified;",
338
336
  examples: [],
339
- scope: "global",
337
+ template: "Bind a service level to a tier",
338
+ description: "Bind a service level to a tier",
340
339
  },
341
340
  {
342
341
  id: "op-update-service-level",
343
342
  name: "UPDATE_SERVICE_LEVEL",
344
- description: "Update a service level binding",
345
- schema: "input UpdateServiceLevelInput {\n tierId: OID!\n serviceLevelId: OID!\n level: ServiceLevel\n optionGroupId: OID\n customValue: String\n lastModified: DateTime!\n}",
346
- template: "Update a service level binding",
347
- reducer: "const tier = state.tiers.find(t => t.id === action.input.tierId);\nif (!tier) {\n throw new UpdateServiceLevelTierNotFoundError(`Tier with ID ${action.input.tierId} not found`);\n}\nconst sl = tier.serviceLevels.find(s => s.id === action.input.serviceLevelId);\nif (!sl) {\n throw new UpdateServiceLevelNotFoundError(`Service level with ID ${action.input.serviceLevelId} not found`);\n}\nif (action.input.level) sl.level = action.input.level;\nif (action.input.customValue !== undefined) sl.customValue = action.input.customValue || null;\nif (action.input.optionGroupId !== undefined) sl.optionGroupId = action.input.optionGroupId || null;\nstate.lastModified = action.input.lastModified;",
343
+ scope: "global",
348
344
  errors: [
349
345
  {
350
346
  id: "err-update-sl-tier-not-found",
351
- name: "UpdateServiceLevelTierNotFoundError",
352
347
  code: "TIER_NOT_FOUND",
353
- description: "Tier with given ID not found",
348
+ name: "UpdateServiceLevelTierNotFoundError",
354
349
  template: "",
350
+ description: "Tier with given ID not found",
355
351
  },
356
352
  {
357
353
  id: "err-update-sl-not-found",
358
- name: "UpdateServiceLevelNotFoundError",
359
354
  code: "SERVICE_LEVEL_NOT_FOUND",
360
- description: "Service level binding with given ID not found",
355
+ name: "UpdateServiceLevelNotFoundError",
361
356
  template: "",
357
+ description: "Service level binding with given ID not found",
362
358
  },
363
359
  ],
360
+ schema: "input UpdateServiceLevelInput {\n tierId: OID!\n serviceLevelId: OID!\n level: ServiceLevel\n optionGroupId: OID\n customValue: String\n lastModified: DateTime!\n}",
361
+ reducer: "const tier = state.tiers.find(t => t.id === action.input.tierId);\nif (!tier) {\n throw new UpdateServiceLevelTierNotFoundError(`Tier with ID ${action.input.tierId} not found`);\n}\nconst sl = tier.serviceLevels.find(s => s.id === action.input.serviceLevelId);\nif (!sl) {\n throw new UpdateServiceLevelNotFoundError(`Service level with ID ${action.input.serviceLevelId} not found`);\n}\nif (action.input.level) sl.level = action.input.level;\nif (action.input.customValue !== undefined) sl.customValue = action.input.customValue || null;\nif (action.input.optionGroupId !== undefined) sl.optionGroupId = action.input.optionGroupId || null;\nstate.lastModified = action.input.lastModified;",
364
362
  examples: [],
365
- scope: "global",
363
+ template: "Update a service level binding",
364
+ description: "Update a service level binding",
366
365
  },
367
366
  {
368
367
  id: "op-remove-service-level",
369
368
  name: "REMOVE_SERVICE_LEVEL",
370
- description: "Remove a service level from a tier",
371
- schema: "input RemoveServiceLevelInput {\n tierId: OID!\n serviceLevelId: OID!\n lastModified: DateTime!\n}",
372
- template: "Remove a service level from a tier",
373
- reducer: "const tier = state.tiers.find(t => t.id === action.input.tierId);\nif (!tier) {\n throw new RemoveServiceLevelTierNotFoundError(`Tier with ID ${action.input.tierId} not found`);\n}\nconst index = tier.serviceLevels.findIndex(s => s.id === action.input.serviceLevelId);\nif (index !== -1) {\n tier.serviceLevels.splice(index, 1);\n}\nstate.lastModified = action.input.lastModified;",
369
+ scope: "global",
374
370
  errors: [
375
371
  {
376
372
  id: "err-remove-sl-tier-not-found",
377
- name: "RemoveServiceLevelTierNotFoundError",
378
373
  code: "TIER_NOT_FOUND",
379
- description: "Tier with given ID not found",
374
+ name: "RemoveServiceLevelTierNotFoundError",
380
375
  template: "",
376
+ description: "Tier with given ID not found",
381
377
  },
382
378
  ],
379
+ schema: "input RemoveServiceLevelInput {\n tierId: OID!\n serviceLevelId: OID!\n lastModified: DateTime!\n}",
380
+ reducer: "const tier = state.tiers.find(t => t.id === action.input.tierId);\nif (!tier) {\n throw new RemoveServiceLevelTierNotFoundError(`Tier with ID ${action.input.tierId} not found`);\n}\nconst index = tier.serviceLevels.findIndex(s => s.id === action.input.serviceLevelId);\nif (index !== -1) {\n tier.serviceLevels.splice(index, 1);\n}\nstate.lastModified = action.input.lastModified;",
383
381
  examples: [],
384
- scope: "global",
382
+ template: "Remove a service level from a tier",
383
+ description: "Remove a service level from a tier",
385
384
  },
386
385
  {
387
386
  id: "op-add-usage-limit",
388
387
  name: "ADD_USAGE_LIMIT",
389
- description: "Add a usage limit to a tier",
390
- schema: "input AddUsageLimitInput {\n tierId: OID!\n limitId: OID!\n serviceId: OID!\n metric: String!\n unitName: String\n freeLimit: Int\n paidLimit: Int\n resetCycle: UsageResetCycle\n notes: String\n unitPrice: Amount_Money\n unitPriceCurrency: Currency\n lastModified: DateTime!\n}",
391
- template: "Add a usage limit to a tier",
392
- reducer: "const tier = state.tiers.find(t => t.id === action.input.tierId);\nif (!tier) {\n throw new AddUsageLimitTierNotFoundError(`Tier with ID ${action.input.tierId} not found`);\n}\ntier.usageLimits.push({\n id: action.input.limitId,\n serviceId: action.input.serviceId,\n metric: action.input.metric,\n unitName: action.input.unitName || null,\n freeLimit: action.input.freeLimit || null,\n paidLimit: action.input.paidLimit || null,\n resetCycle: action.input.resetCycle || null,\n notes: action.input.notes || null,\n unitPrice: action.input.unitPrice || null,\n unitPriceCurrency: action.input.unitPriceCurrency || null,\n});\nstate.lastModified = action.input.lastModified;",
388
+ scope: "global",
393
389
  errors: [
394
390
  {
395
391
  id: "err-add-ul-tier-not-found",
396
- name: "AddUsageLimitTierNotFoundError",
397
392
  code: "TIER_NOT_FOUND",
398
- description: "Tier with given ID not found",
393
+ name: "AddUsageLimitTierNotFoundError",
399
394
  template: "",
395
+ description: "Tier with given ID not found",
400
396
  },
401
397
  ],
398
+ schema: "input AddUsageLimitInput {\n tierId: OID!\n limitId: OID!\n serviceId: OID!\n metric: String!\n unitName: String\n freeLimit: Int\n paidLimit: Int\n resetCycle: UsageResetCycle\n notes: String\n unitPrice: Amount_Money\n unitPriceCurrency: Currency\n lastModified: DateTime!\n}",
399
+ reducer: "const tier = state.tiers.find(t => t.id === action.input.tierId);\nif (!tier) {\n throw new AddUsageLimitTierNotFoundError(`Tier with ID ${action.input.tierId} not found`);\n}\ntier.usageLimits.push({\n id: action.input.limitId,\n serviceId: action.input.serviceId,\n metric: action.input.metric,\n unitName: action.input.unitName || null,\n freeLimit: action.input.freeLimit || null,\n paidLimit: action.input.paidLimit || null,\n resetCycle: action.input.resetCycle || null,\n notes: action.input.notes || null,\n unitPrice: action.input.unitPrice || null,\n unitPriceCurrency: action.input.unitPriceCurrency || null,\n});\nstate.lastModified = action.input.lastModified;",
402
400
  examples: [],
403
- scope: "global",
401
+ template: "Add a usage limit to a tier",
402
+ description: "Add a usage limit to a tier",
404
403
  },
405
404
  {
406
405
  id: "op-update-usage-limit",
407
406
  name: "UPDATE_USAGE_LIMIT",
408
- description: "Update a usage limit",
409
- schema: "input UpdateUsageLimitInput {\n tierId: OID!\n limitId: OID!\n metric: String\n unitName: String\n freeLimit: Int\n paidLimit: Int\n resetCycle: UsageResetCycle\n notes: String\n unitPrice: Amount_Money\n unitPriceCurrency: Currency\n lastModified: DateTime!\n}",
410
- template: "Update a usage limit",
411
- reducer: "const tier = state.tiers.find(t => t.id === action.input.tierId);\nif (!tier) {\n throw new UpdateUsageLimitTierNotFoundError(`Tier with ID ${action.input.tierId} not found`);\n}\nconst ul = tier.usageLimits.find(u => u.id === action.input.limitId);\nif (!ul) {\n throw new UpdateUsageLimitNotFoundError(`Usage limit with ID ${action.input.limitId} not found`);\n}\nif (action.input.metric) ul.metric = action.input.metric;\nif (action.input.unitName !== undefined) ul.unitName = action.input.unitName || null;\nif (action.input.freeLimit !== undefined) ul.freeLimit = action.input.freeLimit || null;\nif (action.input.paidLimit !== undefined) ul.paidLimit = action.input.paidLimit || null;\nif (action.input.resetCycle !== undefined) ul.resetCycle = action.input.resetCycle || null;\nif (action.input.notes !== undefined) ul.notes = action.input.notes || null;\nif (action.input.unitPrice !== undefined) ul.unitPrice = action.input.unitPrice || null;\nif (action.input.unitPriceCurrency !== undefined) ul.unitPriceCurrency = action.input.unitPriceCurrency || null;\nstate.lastModified = action.input.lastModified;",
407
+ scope: "global",
412
408
  errors: [
413
409
  {
414
410
  id: "err-update-ul-tier-not-found",
415
- name: "UpdateUsageLimitTierNotFoundError",
416
411
  code: "TIER_NOT_FOUND",
417
- description: "Tier with given ID not found",
412
+ name: "UpdateUsageLimitTierNotFoundError",
418
413
  template: "",
414
+ description: "Tier with given ID not found",
419
415
  },
420
416
  {
421
417
  id: "err-update-ul-not-found",
422
- name: "UpdateUsageLimitNotFoundError",
423
418
  code: "USAGE_LIMIT_NOT_FOUND",
424
- description: "Usage limit with given ID not found",
419
+ name: "UpdateUsageLimitNotFoundError",
425
420
  template: "",
421
+ description: "Usage limit with given ID not found",
426
422
  },
427
423
  ],
424
+ schema: "input UpdateUsageLimitInput {\n tierId: OID!\n limitId: OID!\n metric: String\n unitName: String\n freeLimit: Int\n paidLimit: Int\n resetCycle: UsageResetCycle\n notes: String\n unitPrice: Amount_Money\n unitPriceCurrency: Currency\n lastModified: DateTime!\n}",
425
+ reducer: "const tier = state.tiers.find(t => t.id === action.input.tierId);\nif (!tier) {\n throw new UpdateUsageLimitTierNotFoundError(`Tier with ID ${action.input.tierId} not found`);\n}\nconst ul = tier.usageLimits.find(u => u.id === action.input.limitId);\nif (!ul) {\n throw new UpdateUsageLimitNotFoundError(`Usage limit with ID ${action.input.limitId} not found`);\n}\nif (action.input.metric) ul.metric = action.input.metric;\nif (action.input.unitName !== undefined) ul.unitName = action.input.unitName || null;\nif (action.input.freeLimit !== undefined) ul.freeLimit = action.input.freeLimit || null;\nif (action.input.paidLimit !== undefined) ul.paidLimit = action.input.paidLimit || null;\nif (action.input.resetCycle !== undefined) ul.resetCycle = action.input.resetCycle || null;\nif (action.input.notes !== undefined) ul.notes = action.input.notes || null;\nif (action.input.unitPrice !== undefined) ul.unitPrice = action.input.unitPrice || null;\nif (action.input.unitPriceCurrency !== undefined) ul.unitPriceCurrency = action.input.unitPriceCurrency || null;\nstate.lastModified = action.input.lastModified;",
428
426
  examples: [],
429
- scope: "global",
427
+ template: "Update a usage limit",
428
+ description: "Update a usage limit",
430
429
  },
431
430
  {
432
431
  id: "op-remove-usage-limit",
433
432
  name: "REMOVE_USAGE_LIMIT",
434
- description: "Remove a usage limit from a tier",
435
- schema: "input RemoveUsageLimitInput {\n tierId: OID!\n limitId: OID!\n lastModified: DateTime!\n}",
436
- template: "Remove a usage limit from a tier",
437
- reducer: "const tier = state.tiers.find(t => t.id === action.input.tierId);\nif (!tier) {\n throw new RemoveUsageLimitTierNotFoundError(`Tier with ID ${action.input.tierId} not found`);\n}\nconst index = tier.usageLimits.findIndex(u => u.id === action.input.limitId);\nif (index !== -1) {\n tier.usageLimits.splice(index, 1);\n}\nstate.lastModified = action.input.lastModified;",
433
+ scope: "global",
438
434
  errors: [
439
435
  {
440
436
  id: "err-remove-ul-tier-not-found",
441
- name: "RemoveUsageLimitTierNotFoundError",
442
437
  code: "TIER_NOT_FOUND",
443
- description: "Tier with given ID not found",
438
+ name: "RemoveUsageLimitTierNotFoundError",
444
439
  template: "",
440
+ description: "Tier with given ID not found",
445
441
  },
446
442
  ],
443
+ schema: "input RemoveUsageLimitInput {\n tierId: OID!\n limitId: OID!\n lastModified: DateTime!\n}",
444
+ reducer: "const tier = state.tiers.find(t => t.id === action.input.tierId);\nif (!tier) {\n throw new RemoveUsageLimitTierNotFoundError(`Tier with ID ${action.input.tierId} not found`);\n}\nconst index = tier.usageLimits.findIndex(u => u.id === action.input.limitId);\nif (index !== -1) {\n tier.usageLimits.splice(index, 1);\n}\nstate.lastModified = action.input.lastModified;",
447
445
  examples: [],
448
- scope: "global",
446
+ template: "Remove a usage limit from a tier",
447
+ description: "Remove a usage limit from a tier",
449
448
  },
450
449
  {
451
450
  id: "op-set-tier-default-billing-cycle",
452
451
  name: "SET_TIER_DEFAULT_BILLING_CYCLE",
453
- description: "Set the default billing cycle for a tier",
454
- schema: "input SetTierDefaultBillingCycleInput {\n tierId: OID!\n defaultBillingCycle: BillingCycle!\n lastModified: DateTime!\n}",
455
- template: "Set the default billing cycle for a tier",
456
- reducer: "const tier = state.tiers.find(t => t.id === action.input.tierId);\nif (!tier) {\n throw new SetTierDefaultBillingCycleTierNotFoundError(`Tier with ID ${action.input.tierId} not found`);\n}\ntier.defaultBillingCycle = action.input.defaultBillingCycle;\nstate.lastModified = action.input.lastModified;",
452
+ scope: "global",
457
453
  errors: [
458
454
  {
459
455
  id: "err-set-tbc-tier-not-found",
460
- name: "SetTierDefaultBillingCycleTierNotFoundError",
461
456
  code: "TIER_NOT_FOUND",
462
- description: "Tier with given ID not found",
457
+ name: "SetTierDefaultBillingCycleTierNotFoundError",
463
458
  template: "",
459
+ description: "Tier with given ID not found",
464
460
  },
465
461
  ],
462
+ schema: "input SetTierDefaultBillingCycleInput {\n tierId: OID!\n defaultBillingCycle: BillingCycle!\n lastModified: DateTime!\n}",
463
+ reducer: "const tier = state.tiers.find(t => t.id === action.input.tierId);\nif (!tier) {\n throw new SetTierDefaultBillingCycleTierNotFoundError(`Tier with ID ${action.input.tierId} not found`);\n}\ntier.defaultBillingCycle = action.input.defaultBillingCycle;\nstate.lastModified = action.input.lastModified;",
466
464
  examples: [],
467
- scope: "global",
465
+ template: "Set the default billing cycle for a tier",
466
+ description: "Set the default billing cycle for a tier",
468
467
  },
469
468
  {
470
469
  id: "op-set-tier-billing-cycle-discounts",
471
470
  name: "SET_TIER_BILLING_CYCLE_DISCOUNTS",
472
- description: "Set billing cycle discounts for a tier",
473
- schema: "input DiscountRuleInput {\n discountType: DiscountType!\n discountValue: Float!\n}\n\ninput BillingCycleDiscountInput {\n billingCycle: BillingCycle!\n discountRule: DiscountRuleInput!\n}\n\ninput SetTierBillingCycleDiscountsInput {\n tierId: OID!\n discounts: [BillingCycleDiscountInput!]!\n lastModified: DateTime!\n}",
474
- template: "Set billing cycle discounts for a tier",
475
- reducer: "const tier = state.tiers.find(t => t.id === action.input.tierId);\nif (!tier) {\n throw new SetTierBillingCycleDiscountsTierNotFoundError(`Tier with ID ${action.input.tierId} not found`);\n}\ntier.billingCycleDiscounts = action.input.discounts.map(d => ({\n billingCycle: d.billingCycle,\n discountRule: {\n discountType: d.discountRule.discountType,\n discountValue: d.discountRule.discountValue,\n },\n}));\nstate.lastModified = action.input.lastModified;",
471
+ scope: "global",
476
472
  errors: [
477
473
  {
478
474
  id: "err-set-tbcd-tier-not-found",
479
- name: "SetTierBillingCycleDiscountsTierNotFoundError",
480
475
  code: "TIER_NOT_FOUND",
481
- description: "Tier with given ID not found",
476
+ name: "SetTierBillingCycleDiscountsTierNotFoundError",
482
477
  template: "",
478
+ description: "Tier with given ID not found",
483
479
  },
484
480
  ],
481
+ schema: "input DiscountRuleInput {\n discountType: DiscountType!\n discountValue: Float!\n}\n\ninput BillingCycleDiscountInput {\n billingCycle: BillingCycle!\n discountRule: DiscountRuleInput!\n}\n\ninput SetTierBillingCycleDiscountsInput {\n tierId: OID!\n discounts: [BillingCycleDiscountInput!]!\n lastModified: DateTime!\n}",
482
+ reducer: "const tier = state.tiers.find(t => t.id === action.input.tierId);\nif (!tier) {\n throw new SetTierBillingCycleDiscountsTierNotFoundError(`Tier with ID ${action.input.tierId} not found`);\n}\ntier.billingCycleDiscounts = action.input.discounts.map(d => ({\n billingCycle: d.billingCycle,\n discountRule: {\n discountType: d.discountRule.discountType,\n discountValue: d.discountRule.discountValue,\n },\n}));\nstate.lastModified = action.input.lastModified;",
485
483
  examples: [],
486
- scope: "global",
484
+ template: "Set billing cycle discounts for a tier",
485
+ description: "Set billing cycle discounts for a tier",
487
486
  },
488
487
  {
489
488
  id: "op-set-tier-pricing-mode",
490
489
  name: "SET_TIER_PRICING_MODE",
491
- description: "Set the pricing mode for a tier",
492
- schema: "input SetTierPricingModeInput {\n tierId: OID!\n pricingMode: TierPricingMode!\n lastModified: DateTime!\n}",
493
- template: "Set the pricing mode for a tier",
494
- reducer: "const tier = state.tiers.find(t => t.id === action.input.tierId);\nif (!tier) {\n throw new SetTierPricingModeTierNotFoundError(`Tier with ID ${action.input.tierId} not found`);\n}\ntier.pricingMode = action.input.pricingMode;\nstate.lastModified = action.input.lastModified;",
490
+ scope: "global",
495
491
  errors: [
496
492
  {
497
493
  id: "err-set-tpm-tier-not-found",
498
- name: "SetTierPricingModeTierNotFoundError",
499
494
  code: "TIER_NOT_FOUND",
500
- description: "Tier with given ID not found",
495
+ name: "SetTierPricingModeTierNotFoundError",
501
496
  template: "",
497
+ description: "Tier with given ID not found",
502
498
  },
503
499
  ],
500
+ schema: "input SetTierPricingModeInput {\n tierId: OID!\n pricingMode: TierPricingMode!\n lastModified: DateTime!\n}",
501
+ reducer: "const tier = state.tiers.find(t => t.id === action.input.tierId);\nif (!tier) {\n throw new SetTierPricingModeTierNotFoundError(`Tier with ID ${action.input.tierId} not found`);\n}\ntier.pricingMode = action.input.pricingMode;\nstate.lastModified = action.input.lastModified;",
504
502
  examples: [],
505
- scope: "global",
503
+ template: "Set the pricing mode for a tier",
504
+ description: "Set the pricing mode for a tier",
506
505
  },
507
506
  ],
507
+ description: "Subscription tiers, service levels, usage limits, billing cycles, and discounts",
508
508
  },
509
509
  {
510
510
  id: "mod-option-groups",
511
511
  name: "option-groups",
512
- description: "Add-on option groups with standalone and tier-dependent pricing",
513
512
  operations: [
514
513
  {
515
514
  id: "op-add-option-group",
516
515
  name: "ADD_OPTION_GROUP",
517
- description: "Add an option group",
516
+ scope: "global",
517
+ errors: [],
518
518
  schema: "input AddOptionGroupInput {\n id: OID!\n name: String!\n description: String\n isAddOn: Boolean!\n defaultSelected: Boolean!\n costType: GroupCostType\n availableBillingCycles: [BillingCycle!]\n price: Amount_Money\n currency: Currency\n lastModified: DateTime!\n}",
519
- template: "Add an option group",
520
519
  reducer: "state.optionGroups.push({\n id: action.input.id,\n name: action.input.name,\n description: action.input.description || null,\n isAddOn: action.input.isAddOn,\n defaultSelected: action.input.defaultSelected,\n pricingMode: null,\n standalonePricing: null,\n tierDependentPricing: null,\n costType: action.input.costType || null,\n availableBillingCycles: action.input.availableBillingCycles || [],\n billingCycleDiscounts: [],\n discountMode: null,\n price: action.input.price || null,\n currency: action.input.currency || null,\n});\nstate.lastModified = action.input.lastModified;",
521
- errors: [],
522
520
  examples: [],
523
- scope: "global",
521
+ template: "Add an option group",
522
+ description: "Add an option group",
524
523
  },
525
524
  {
526
525
  id: "op-update-option-group",
527
526
  name: "UPDATE_OPTION_GROUP",
528
- description: "Update option group fields",
529
- schema: "input UpdateOptionGroupInput {\n id: OID!\n name: String\n description: String\n isAddOn: Boolean\n defaultSelected: Boolean\n costType: GroupCostType\n availableBillingCycles: [BillingCycle!]\n price: Amount_Money\n currency: Currency\n lastModified: DateTime!\n}",
530
- template: "Update option group fields",
531
- reducer: "const og = state.optionGroups.find(g => g.id === action.input.id);\nif (!og) {\n throw new UpdateOptionGroupNotFoundError(`Option group with ID ${action.input.id} not found`);\n}\nif (action.input.name) og.name = action.input.name;\nif (action.input.description !== undefined) og.description = action.input.description || null;\nif (action.input.isAddOn !== undefined && action.input.isAddOn !== null) og.isAddOn = action.input.isAddOn;\nif (action.input.defaultSelected !== undefined && action.input.defaultSelected !== null) og.defaultSelected = action.input.defaultSelected;\nif (action.input.costType !== undefined) og.costType = action.input.costType || null;\nif (action.input.availableBillingCycles) og.availableBillingCycles = action.input.availableBillingCycles;\nif (action.input.price !== undefined) og.price = action.input.price || null;\nif (action.input.currency !== undefined) og.currency = action.input.currency || null;\nstate.lastModified = action.input.lastModified;",
527
+ scope: "global",
532
528
  errors: [
533
529
  {
534
530
  id: "err-update-og-not-found",
535
- name: "UpdateOptionGroupNotFoundError",
536
531
  code: "OPTION_GROUP_NOT_FOUND",
537
- description: "Option group with given ID not found",
532
+ name: "UpdateOptionGroupNotFoundError",
538
533
  template: "",
534
+ description: "Option group with given ID not found",
539
535
  },
540
536
  ],
537
+ schema: "input UpdateOptionGroupInput {\n id: OID!\n name: String\n description: String\n isAddOn: Boolean\n defaultSelected: Boolean\n costType: GroupCostType\n availableBillingCycles: [BillingCycle!]\n price: Amount_Money\n currency: Currency\n lastModified: DateTime!\n}",
538
+ reducer: "const og = state.optionGroups.find(g => g.id === action.input.id);\nif (!og) {\n throw new UpdateOptionGroupNotFoundError(`Option group with ID ${action.input.id} not found`);\n}\nif (action.input.name) og.name = action.input.name;\nif (action.input.description !== undefined) og.description = action.input.description || null;\nif (action.input.isAddOn !== undefined && action.input.isAddOn !== null) og.isAddOn = action.input.isAddOn;\nif (action.input.defaultSelected !== undefined && action.input.defaultSelected !== null) og.defaultSelected = action.input.defaultSelected;\nif (action.input.costType !== undefined) og.costType = action.input.costType || null;\nif (action.input.availableBillingCycles) og.availableBillingCycles = action.input.availableBillingCycles;\nif (action.input.price !== undefined) og.price = action.input.price || null;\nif (action.input.currency !== undefined) og.currency = action.input.currency || null;\nstate.lastModified = action.input.lastModified;",
541
539
  examples: [],
542
- scope: "global",
540
+ template: "Update option group fields",
541
+ description: "Update option group fields",
543
542
  },
544
543
  {
545
544
  id: "op-delete-option-group",
546
545
  name: "DELETE_OPTION_GROUP",
547
- description: "Delete an option group",
548
- schema: "input DeleteOptionGroupInput {\n id: OID!\n lastModified: DateTime!\n}",
549
- template: "Delete an option group",
550
- reducer: "const index = state.optionGroups.findIndex(g => g.id === action.input.id);\nif (index === -1) {\n throw new DeleteOptionGroupNotFoundError(`Option group with ID ${action.input.id} not found`);\n}\nstate.optionGroups.splice(index, 1);\nstate.lastModified = action.input.lastModified;",
546
+ scope: "global",
551
547
  errors: [
552
548
  {
553
549
  id: "err-delete-og-not-found",
554
- name: "DeleteOptionGroupNotFoundError",
555
550
  code: "OPTION_GROUP_NOT_FOUND",
556
- description: "Option group with given ID not found",
551
+ name: "DeleteOptionGroupNotFoundError",
557
552
  template: "",
553
+ description: "Option group with given ID not found",
558
554
  },
559
555
  ],
556
+ schema: "input DeleteOptionGroupInput {\n id: OID!\n lastModified: DateTime!\n}",
557
+ reducer: "const index = state.optionGroups.findIndex(g => g.id === action.input.id);\nif (index === -1) {\n throw new DeleteOptionGroupNotFoundError(`Option group with ID ${action.input.id} not found`);\n}\nstate.optionGroups.splice(index, 1);\nstate.lastModified = action.input.lastModified;",
560
558
  examples: [],
561
- scope: "global",
559
+ template: "Delete an option group",
560
+ description: "Delete an option group",
562
561
  },
563
562
  {
564
563
  id: "op-set-option-group-standalone-pricing",
565
564
  name: "SET_OPTION_GROUP_STANDALONE_PRICING",
566
- description: "Set standalone pricing for an option group",
567
- schema: "input RecurringPriceOptionInput {\n id: OID!\n billingCycle: BillingCycle!\n amount: Amount_Money!\n currency: Currency!\n discount: DiscountRuleInput\n}\n\ninput SetupCostInput {\n amount: Amount_Money!\n currency: Currency!\n discount: DiscountRuleInput\n}\n\ninput SetOptionGroupStandalonePricingInput {\n optionGroupId: OID!\n setupCost: SetupCostInput\n recurringPricing: [RecurringPriceOptionInput!]!\n billingCycleDiscounts: [BillingCycleDiscountInput!]\n lastModified: DateTime!\n}",
568
- template: "Set standalone pricing for an option group",
569
- reducer: 'const og = state.optionGroups.find(g => g.id === action.input.optionGroupId);\nif (!og) {\n throw new SetOptionGroupStandalonePricingNotFoundError(`Option group with ID ${action.input.optionGroupId} not found`);\n}\nog.pricingMode = "STANDALONE";\nog.standalonePricing = {\n setupCost: action.input.setupCost ? {\n amount: action.input.setupCost.amount,\n currency: action.input.setupCost.currency,\n discount: action.input.setupCost.discount ? {\n discountType: action.input.setupCost.discount.discountType,\n discountValue: action.input.setupCost.discount.discountValue,\n } : null,\n } : null,\n recurringPricing: action.input.recurringPricing.map(rp => ({\n id: rp.id,\n billingCycle: rp.billingCycle,\n amount: rp.amount,\n currency: rp.currency,\n discount: rp.discount ? {\n discountType: rp.discount.discountType,\n discountValue: rp.discount.discountValue,\n } : null,\n })),\n};\nif (action.input.billingCycleDiscounts) {\n og.billingCycleDiscounts = action.input.billingCycleDiscounts.map(d => ({\n billingCycle: d.billingCycle,\n discountRule: {\n discountType: d.discountRule.discountType,\n discountValue: d.discountRule.discountValue,\n },\n }));\n}\nstate.lastModified = action.input.lastModified;',
565
+ scope: "global",
570
566
  errors: [
571
567
  {
572
568
  id: "err-set-ogsp-not-found",
573
- name: "SetOptionGroupStandalonePricingNotFoundError",
574
569
  code: "OPTION_GROUP_NOT_FOUND",
575
- description: "Option group with given ID not found",
570
+ name: "SetOptionGroupStandalonePricingNotFoundError",
576
571
  template: "",
572
+ description: "Option group with given ID not found",
577
573
  },
578
574
  ],
575
+ schema: "input RecurringPriceOptionInput {\n id: OID!\n billingCycle: BillingCycle!\n amount: Amount_Money!\n currency: Currency!\n discount: DiscountRuleInput\n}\n\ninput SetupCostInput {\n amount: Amount_Money!\n currency: Currency!\n discount: DiscountRuleInput\n}\n\ninput SetOptionGroupStandalonePricingInput {\n optionGroupId: OID!\n setupCost: SetupCostInput\n recurringPricing: [RecurringPriceOptionInput!]!\n billingCycleDiscounts: [BillingCycleDiscountInput!]\n lastModified: DateTime!\n}",
576
+ reducer: 'const og = state.optionGroups.find(g => g.id === action.input.optionGroupId);\nif (!og) {\n throw new SetOptionGroupStandalonePricingNotFoundError(`Option group with ID ${action.input.optionGroupId} not found`);\n}\nog.pricingMode = "STANDALONE";\nog.standalonePricing = {\n setupCost: action.input.setupCost ? {\n amount: action.input.setupCost.amount,\n currency: action.input.setupCost.currency,\n discount: action.input.setupCost.discount ? {\n discountType: action.input.setupCost.discount.discountType,\n discountValue: action.input.setupCost.discount.discountValue,\n } : null,\n } : null,\n recurringPricing: action.input.recurringPricing.map(rp => ({\n id: rp.id,\n billingCycle: rp.billingCycle,\n amount: rp.amount,\n currency: rp.currency,\n discount: rp.discount ? {\n discountType: rp.discount.discountType,\n discountValue: rp.discount.discountValue,\n } : null,\n })),\n};\nif (action.input.billingCycleDiscounts) {\n og.billingCycleDiscounts = action.input.billingCycleDiscounts.map(d => ({\n billingCycle: d.billingCycle,\n discountRule: {\n discountType: d.discountRule.discountType,\n discountValue: d.discountRule.discountValue,\n },\n }));\n}\nstate.lastModified = action.input.lastModified;',
579
577
  examples: [],
580
- scope: "global",
578
+ template: "Set standalone pricing for an option group",
579
+ description: "Set standalone pricing for an option group",
581
580
  },
582
581
  {
583
582
  id: "op-add-option-group-tier-pricing",
584
583
  name: "ADD_OPTION_GROUP_TIER_PRICING",
585
- description: "Add tier-dependent pricing to an option group",
586
- schema: "input AddOptionGroupTierPricingInput {\n optionGroupId: OID!\n tierPricingId: OID!\n tierId: OID!\n setupCost: SetupCostInput\n setupCostDiscounts: [BillingCycleDiscountInput!]\n recurringPricing: [RecurringPriceOptionInput!]!\n lastModified: DateTime!\n}",
587
- template: "Add tier-dependent pricing to an option group",
588
- reducer: 'const og = state.optionGroups.find(g => g.id === action.input.optionGroupId);\nif (!og) {\n throw new AddOptionGroupTierPricingNotFoundError(`Option group with ID ${action.input.optionGroupId} not found`);\n}\nog.pricingMode = "TIER_DEPENDENT";\nif (!og.tierDependentPricing) {\n og.tierDependentPricing = [];\n}\nog.tierDependentPricing.push({\n id: action.input.tierPricingId,\n tierId: action.input.tierId,\n setupCost: action.input.setupCost ? {\n amount: action.input.setupCost.amount,\n currency: action.input.setupCost.currency,\n discount: action.input.setupCost.discount ? {\n discountType: action.input.setupCost.discount.discountType,\n discountValue: action.input.setupCost.discount.discountValue,\n } : null,\n } : null,\n setupCostDiscounts: (action.input.setupCostDiscounts || []).map(d => ({\n billingCycle: d.billingCycle,\n discountRule: {\n discountType: d.discountRule.discountType,\n discountValue: d.discountRule.discountValue,\n },\n })),\n recurringPricing: action.input.recurringPricing.map(rp => ({\n id: rp.id,\n billingCycle: rp.billingCycle,\n amount: rp.amount,\n currency: rp.currency,\n discount: rp.discount ? {\n discountType: rp.discount.discountType,\n discountValue: rp.discount.discountValue,\n } : null,\n })),\n});\nstate.lastModified = action.input.lastModified;',
584
+ scope: "global",
589
585
  errors: [
590
586
  {
591
587
  id: "err-add-ogtp-not-found",
592
- name: "AddOptionGroupTierPricingNotFoundError",
593
588
  code: "OPTION_GROUP_NOT_FOUND",
594
- description: "Option group with given ID not found",
589
+ name: "AddOptionGroupTierPricingNotFoundError",
595
590
  template: "",
591
+ description: "Option group with given ID not found",
596
592
  },
597
593
  ],
594
+ schema: "input AddOptionGroupTierPricingInput {\n optionGroupId: OID!\n tierPricingId: OID!\n tierId: OID!\n setupCost: SetupCostInput\n setupCostDiscounts: [BillingCycleDiscountInput!]\n recurringPricing: [RecurringPriceOptionInput!]!\n lastModified: DateTime!\n}",
595
+ reducer: 'const og = state.optionGroups.find(g => g.id === action.input.optionGroupId);\nif (!og) {\n throw new AddOptionGroupTierPricingNotFoundError(`Option group with ID ${action.input.optionGroupId} not found`);\n}\nog.pricingMode = "TIER_DEPENDENT";\nif (!og.tierDependentPricing) {\n og.tierDependentPricing = [];\n}\nog.tierDependentPricing.push({\n id: action.input.tierPricingId,\n tierId: action.input.tierId,\n setupCost: action.input.setupCost ? {\n amount: action.input.setupCost.amount,\n currency: action.input.setupCost.currency,\n discount: action.input.setupCost.discount ? {\n discountType: action.input.setupCost.discount.discountType,\n discountValue: action.input.setupCost.discount.discountValue,\n } : null,\n } : null,\n setupCostDiscounts: (action.input.setupCostDiscounts || []).map(d => ({\n billingCycle: d.billingCycle,\n discountRule: {\n discountType: d.discountRule.discountType,\n discountValue: d.discountRule.discountValue,\n },\n })),\n recurringPricing: action.input.recurringPricing.map(rp => ({\n id: rp.id,\n billingCycle: rp.billingCycle,\n amount: rp.amount,\n currency: rp.currency,\n discount: rp.discount ? {\n discountType: rp.discount.discountType,\n discountValue: rp.discount.discountValue,\n } : null,\n })),\n});\nstate.lastModified = action.input.lastModified;',
598
596
  examples: [],
599
- scope: "global",
597
+ template: "Add tier-dependent pricing to an option group",
598
+ description: "Add tier-dependent pricing to an option group",
600
599
  },
601
600
  {
602
601
  id: "op-update-option-group-tier-pricing",
603
602
  name: "UPDATE_OPTION_GROUP_TIER_PRICING",
604
- description: "Update tier-dependent pricing for an option group",
605
- schema: "input UpdateOptionGroupTierPricingInput {\n optionGroupId: OID!\n tierId: OID!\n setupCost: SetupCostInput\n setupCostDiscounts: [BillingCycleDiscountInput!]\n recurringPricing: [RecurringPriceOptionInput!]\n lastModified: DateTime!\n}",
606
- template: "Update tier-dependent pricing for an option group",
607
- reducer: "const og = state.optionGroups.find(g => g.id === action.input.optionGroupId);\nif (!og) {\n throw new UpdateOptionGroupTierPricingNotFoundError(`Option group with ID ${action.input.optionGroupId} not found`);\n}\nconst tp = og.tierDependentPricing?.find(t => t.tierId === action.input.tierId);\nif (tp) {\n if (action.input.setupCost !== undefined) {\n tp.setupCost = action.input.setupCost ? {\n amount: action.input.setupCost.amount,\n currency: action.input.setupCost.currency,\n discount: action.input.setupCost.discount ? {\n discountType: action.input.setupCost.discount.discountType,\n discountValue: action.input.setupCost.discount.discountValue,\n } : null,\n } : null;\n }\n if (action.input.setupCostDiscounts !== undefined && action.input.setupCostDiscounts !== null) {\n tp.setupCostDiscounts = action.input.setupCostDiscounts.map(d => ({\n billingCycle: d.billingCycle,\n discountRule: {\n discountType: d.discountRule.discountType,\n discountValue: d.discountRule.discountValue,\n },\n }));\n }\n if (action.input.recurringPricing) {\n tp.recurringPricing = action.input.recurringPricing.map(rp => ({\n id: rp.id,\n billingCycle: rp.billingCycle,\n amount: rp.amount,\n currency: rp.currency,\n discount: rp.discount ? {\n discountType: rp.discount.discountType,\n discountValue: rp.discount.discountValue,\n } : null,\n }));\n }\n}\nstate.lastModified = action.input.lastModified;",
603
+ scope: "global",
608
604
  errors: [
609
605
  {
610
606
  id: "err-update-ogtp-not-found",
611
- name: "UpdateOptionGroupTierPricingNotFoundError",
612
607
  code: "OPTION_GROUP_NOT_FOUND",
613
- description: "Option group with given ID not found",
608
+ name: "UpdateOptionGroupTierPricingNotFoundError",
614
609
  template: "",
610
+ description: "Option group with given ID not found",
615
611
  },
616
612
  ],
613
+ schema: "input UpdateOptionGroupTierPricingInput {\n optionGroupId: OID!\n tierId: OID!\n setupCost: SetupCostInput\n setupCostDiscounts: [BillingCycleDiscountInput!]\n recurringPricing: [RecurringPriceOptionInput!]\n lastModified: DateTime!\n}",
614
+ reducer: "const og = state.optionGroups.find(g => g.id === action.input.optionGroupId);\nif (!og) {\n throw new UpdateOptionGroupTierPricingNotFoundError(`Option group with ID ${action.input.optionGroupId} not found`);\n}\nconst tp = og.tierDependentPricing?.find(t => t.tierId === action.input.tierId);\nif (tp) {\n if (action.input.setupCost !== undefined) {\n tp.setupCost = action.input.setupCost ? {\n amount: action.input.setupCost.amount,\n currency: action.input.setupCost.currency,\n discount: action.input.setupCost.discount ? {\n discountType: action.input.setupCost.discount.discountType,\n discountValue: action.input.setupCost.discount.discountValue,\n } : null,\n } : null;\n }\n if (action.input.setupCostDiscounts !== undefined && action.input.setupCostDiscounts !== null) {\n tp.setupCostDiscounts = action.input.setupCostDiscounts.map(d => ({\n billingCycle: d.billingCycle,\n discountRule: {\n discountType: d.discountRule.discountType,\n discountValue: d.discountRule.discountValue,\n },\n }));\n }\n if (action.input.recurringPricing) {\n tp.recurringPricing = action.input.recurringPricing.map(rp => ({\n id: rp.id,\n billingCycle: rp.billingCycle,\n amount: rp.amount,\n currency: rp.currency,\n discount: rp.discount ? {\n discountType: rp.discount.discountType,\n discountValue: rp.discount.discountValue,\n } : null,\n }));\n }\n}\nstate.lastModified = action.input.lastModified;",
617
615
  examples: [],
618
- scope: "global",
616
+ template: "Update tier-dependent pricing for an option group",
617
+ description: "Update tier-dependent pricing for an option group",
619
618
  },
620
619
  {
621
620
  id: "op-remove-option-group-tier-pricing",
622
621
  name: "REMOVE_OPTION_GROUP_TIER_PRICING",
623
- description: "Remove tier-dependent pricing from an option group",
624
- schema: "input RemoveOptionGroupTierPricingInput {\n optionGroupId: OID!\n tierId: OID!\n lastModified: DateTime!\n}",
625
- template: "Remove tier-dependent pricing from an option group",
626
- reducer: "const og = state.optionGroups.find(g => g.id === action.input.optionGroupId);\nif (!og) {\n throw new RemoveOptionGroupTierPricingNotFoundError(`Option group with ID ${action.input.optionGroupId} not found`);\n}\nif (og.tierDependentPricing) {\n const index = og.tierDependentPricing.findIndex(t => t.tierId === action.input.tierId);\n if (index !== -1) {\n og.tierDependentPricing.splice(index, 1);\n }\n}\nstate.lastModified = action.input.lastModified;",
622
+ scope: "global",
627
623
  errors: [
628
624
  {
629
625
  id: "err-remove-ogtp-not-found",
630
- name: "RemoveOptionGroupTierPricingNotFoundError",
631
626
  code: "OPTION_GROUP_NOT_FOUND",
632
- description: "Option group with given ID not found",
627
+ name: "RemoveOptionGroupTierPricingNotFoundError",
633
628
  template: "",
629
+ description: "Option group with given ID not found",
634
630
  },
635
631
  ],
632
+ schema: "input RemoveOptionGroupTierPricingInput {\n optionGroupId: OID!\n tierId: OID!\n lastModified: DateTime!\n}",
633
+ reducer: "const og = state.optionGroups.find(g => g.id === action.input.optionGroupId);\nif (!og) {\n throw new RemoveOptionGroupTierPricingNotFoundError(`Option group with ID ${action.input.optionGroupId} not found`);\n}\nif (og.tierDependentPricing) {\n const index = og.tierDependentPricing.findIndex(t => t.tierId === action.input.tierId);\n if (index !== -1) {\n og.tierDependentPricing.splice(index, 1);\n }\n}\nstate.lastModified = action.input.lastModified;",
636
634
  examples: [],
637
- scope: "global",
635
+ template: "Remove tier-dependent pricing from an option group",
636
+ description: "Remove tier-dependent pricing from an option group",
638
637
  },
639
638
  {
640
639
  id: "op-set-option-group-discount-mode",
641
640
  name: "SET_OPTION_GROUP_DISCOUNT_MODE",
642
- description: "Set the discount mode for an option group",
643
- schema: "input SetOptionGroupDiscountModeInput {\n optionGroupId: OID!\n discountMode: DiscountMode!\n lastModified: DateTime!\n}",
644
- template: "Set the discount mode for an option group",
645
- reducer: "const og = state.optionGroups.find(g => g.id === action.input.optionGroupId);\nif (!og) {\n throw new SetOptionGroupDiscountModeNotFoundError(`Option group with ID ${action.input.optionGroupId} not found`);\n}\nog.discountMode = action.input.discountMode;\nstate.lastModified = action.input.lastModified;",
641
+ scope: "global",
646
642
  errors: [
647
643
  {
648
644
  id: "err-set-ogdm-not-found",
649
- name: "SetOptionGroupDiscountModeNotFoundError",
650
645
  code: "OPTION_GROUP_NOT_FOUND",
651
- description: "Option group with given ID not found",
646
+ name: "SetOptionGroupDiscountModeNotFoundError",
652
647
  template: "",
648
+ description: "Option group with given ID not found",
653
649
  },
654
650
  ],
651
+ schema: "input SetOptionGroupDiscountModeInput {\n optionGroupId: OID!\n discountMode: DiscountMode!\n lastModified: DateTime!\n}",
652
+ reducer: "const og = state.optionGroups.find(g => g.id === action.input.optionGroupId);\nif (!og) {\n throw new SetOptionGroupDiscountModeNotFoundError(`Option group with ID ${action.input.optionGroupId} not found`);\n}\nog.discountMode = action.input.discountMode;\nstate.lastModified = action.input.lastModified;",
655
653
  examples: [],
656
- scope: "global",
654
+ template: "Set the discount mode for an option group",
655
+ description: "Set the discount mode for an option group",
657
656
  },
658
657
  ],
658
+ description: "Add-on option groups with standalone and tier-dependent pricing",
659
659
  },
660
660
  ],
661
661
  version: 1,