@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.
- package/dist/document-models/service-offering/v1/gen/controller.d.ts +4 -0
- package/dist/document-models/service-offering/v1/gen/controller.d.ts.map +1 -0
- package/dist/document-models/service-offering/v1/gen/controller.js +3 -0
- package/dist/document-models/service-offering/v1/gen/document-model.js +227 -227
- package/dist/document-models/service-offering/v1/gen/index.d.ts +1 -0
- package/dist/document-models/service-offering/v1/gen/index.d.ts.map +1 -1
- package/dist/document-models/service-offering/v1/gen/index.js +1 -2
- package/dist/document-models/service-offering/v1/gen/schema/types.d.ts +2 -0
- package/dist/document-models/service-offering/v1/gen/schema/types.d.ts.map +1 -1
- package/dist/document-models/service-offering/v1/gen/schema/zod.d.ts.map +1 -1
- package/dist/document-models/service-offering/v1/gen/schema/zod.js +2 -0
- package/dist/document-models/service-offering/v1/src/reducers/tiers.d.ts.map +1 -1
- package/dist/document-models/service-offering/v1/src/reducers/tiers.js +10 -0
- package/dist/document-models/service-offering/v1/src/utils.d.ts.map +1 -1
- package/dist/document-models/service-offering/v1/src/utils.js +7 -5
- package/dist/document-models/subscription-instance/v1/src/reducers/metrics.d.ts.map +1 -1
- package/dist/document-models/subscription-instance/v1/src/reducers/metrics.js +7 -6
- package/dist/document-models/subscription-instance/v1/src/reducers/utils.d.ts +7 -0
- package/dist/document-models/subscription-instance/v1/src/reducers/utils.d.ts.map +1 -0
- package/dist/document-models/subscription-instance/v1/src/reducers/utils.js +15 -0
- package/dist/document-models/subscription-instance/v1/tests/metrics.test.js +88 -1
- package/dist/document-models/upgrade-manifests.d.ts.map +1 -1
- package/dist/document-models/upgrade-manifests.js +2 -0
- package/dist/editors/service-offering-editor/components/TheMatrix.d.ts.map +1 -1
- package/dist/editors/service-offering-editor/components/TheMatrix.js +10 -5
- package/dist/editors/service-offering-editor/components/TierDefinition.d.ts.map +1 -1
- package/dist/editors/service-offering-editor/components/TierDefinition.js +9 -14
- package/dist/editors/subscription-instance-editor/components/mapOfferingToSubscription.d.ts.map +1 -1
- package/dist/editors/subscription-instance-editor/components/mapOfferingToSubscription.js +27 -3
- package/dist/powerhouse.manifest.json +12 -4
- package/dist/style.css +6 -0
- package/dist/subgraphs/resources-services/resolvers.d.ts.map +1 -1
- package/dist/subgraphs/resources-services/resolvers.js +11 -5
- 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|