@@ -2,15 +2,17 @@ package httpdriver
2
2
3
3
import (
4
4
"context"
5
- "encoding/json"
6
5
"fmt"
7
6
"net/http"
8
7
9
8
"github.com/samber/lo"
10
9
11
10
"github.com/openmeterio/openmeter/api"
11
+ "github.com/openmeterio/openmeter/openmeter/productcatalog"
12
+ "github.com/openmeterio/openmeter/openmeter/productcatalog/plan"
12
13
plansubscription "github.com/openmeterio/openmeter/openmeter/productcatalog/subscription"
13
14
subscriptionworkflow "github.com/openmeterio/openmeter/openmeter/subscription/workflow"
15
+ "github.com/openmeterio/openmeter/pkg/clock"
14
16
"github.com/openmeterio/openmeter/pkg/convert"
15
17
"github.com/openmeterio/openmeter/pkg/framework/commonhttp"
16
18
"github.com/openmeterio/openmeter/pkg/framework/transport/httptransport"
@@ -37,90 +39,94 @@ func (h *handler) ChangeSubscription() ChangeSubscriptionHandler {
37
39
38
40
ns , err := h .resolveNamespace (ctx )
39
41
if err != nil {
40
- return ChangeSubscriptionRequest {}, err
41
- }
42
-
43
- // Any transformation function generated by the API will succeed if the body is serializable, so we have to check for the presence of
44
- // fields to determine what body type we're dealing with
45
- type testForCustomPlan struct {
46
- CustomPlan any `json:"customPlan"`
42
+ return ChangeSubscriptionRequest {}, fmt .Errorf ("failed to resolve namespace: %w" , err )
47
43
}
48
44
49
- var t testForCustomPlan
45
+ workflowInput := subscriptionworkflow. ChangeSubscriptionWorkflowInput {}
50
46
51
- bodyBytes , err := json .Marshal (body )
52
- if err != nil {
53
- return ChangeSubscriptionRequest {}, fmt .Errorf ("failed to marshal request body: %w" , err )
54
- }
47
+ var planInput plansubscription.PlanInput
48
+ var startingPhase * string
55
49
56
- if err := json .Unmarshal (bodyBytes , & t ); err != nil {
57
- return ChangeSubscriptionRequest {}, fmt .Errorf ("failed to unmarshal request body: %w" , err )
58
- }
50
+ // Try to parse as custom subscription change
51
+ if b , err := body .AsCustomSubscriptionChange (); err == nil {
52
+ // Convert API input to plan creation input using the mapping function
53
+ createPlanInput , err := AsCustomPlanCreateInput (b .CustomPlan , ns )
54
+ if err != nil {
55
+ return ChangeSubscriptionRequest {}, fmt .Errorf ("failed to convert custom plan: %w" , err )
56
+ }
59
57
60
- if t .CustomPlan != nil {
61
- // Changing to a custom Plan
62
- parsedBody , err := body .AsCustomSubscriptionChange ()
58
+ // Create the custom plan and set the reference to it in the plan input
59
+ customPlan , err := h .PlanService .CreatePlan (ctx , createPlanInput )
63
60
if err != nil {
64
- return ChangeSubscriptionRequest {}, fmt .Errorf ("failed to parse custom plan: %w" , err )
61
+ return ChangeSubscriptionRequest {}, fmt .Errorf ("failed to create custom plan: %w" , err )
65
62
}
66
63
67
- req , err := CustomPlanToCreatePlanRequest (parsedBody .CustomPlan , ns )
64
+ // Publish the custom plan to make it active
65
+ effectiveFrom := createPlanInput .EffectiveFrom
66
+ if effectiveFrom == nil {
67
+ effectiveFrom = lo .ToPtr (clock .Now ())
68
+ }
69
+ customPlan , err = h .PlanService .PublishPlan (ctx , plan.PublishPlanInput {
70
+ NamespacedID : customPlan .NamespacedID ,
71
+ EffectivePeriod : productcatalog.EffectivePeriod {
72
+ EffectiveFrom : effectiveFrom ,
73
+ EffectiveTo : createPlanInput .EffectiveTo ,
74
+ },
75
+ })
68
76
if err != nil {
69
- return ChangeSubscriptionRequest {}, fmt .Errorf ("failed to create plan request : %w" , err )
77
+ return ChangeSubscriptionRequest {}, fmt .Errorf ("failed to publish custom plan : %w" , err )
70
78
}
71
79
72
- planInp := plansubscription.PlanInput {}
73
- planInp .FromInput (& req )
80
+ planInput .FromRef (& plansubscription.PlanRefInput {
81
+ Key : customPlan .Key ,
82
+ Version : & customPlan .Version ,
83
+ })
74
84
75
- timing , err := MapAPITimingToTiming (parsedBody .Timing )
85
+ subscriptionTiming , err := MapAPITimingToTiming (b .Timing )
76
86
if err != nil {
77
87
return ChangeSubscriptionRequest {}, fmt .Errorf ("failed to map timing: %w" , err )
78
88
}
79
89
80
- return ChangeSubscriptionRequest {
81
- ID : models.NamespacedID {Namespace : ns , ID : params .ID },
82
- PlanInput : planInp ,
83
- WorkflowInput : subscriptionworkflow.ChangeSubscriptionWorkflowInput {
84
- Timing : timing ,
85
- Name : req .Name ,
86
- Description : req .Description ,
87
- MetadataModel : models.MetadataModel {
88
- Metadata : req .Metadata ,
89
- },
90
+ workflowInput = subscriptionworkflow.ChangeSubscriptionWorkflowInput {
91
+ Timing : subscriptionTiming ,
92
+ Name : b .CustomPlan .Name ,
93
+ Description : b .CustomPlan .Description ,
94
+ MetadataModel : models.MetadataModel {
95
+ Metadata : convert.DerefHeaderPtr [string ](b .CustomPlan .Metadata ),
90
96
},
91
- }, nil
92
- } else {
93
- // Changing to a Plan
94
- parsedBody , err := body .AsPlanSubscriptionChange ()
95
- if err != nil {
96
- return ChangeSubscriptionRequest {}, fmt .Errorf ("failed to parse plan: %w" , err )
97
97
}
98
-
99
- planInp := plansubscription. PlanInput {}
100
- planInp .FromRef (& plansubscription.PlanRefInput {
101
- Key : parsedBody .Plan .Key ,
102
- Version : parsedBody .Plan .Version ,
98
+ // Try to parse as plan subscription change
99
+ } else if b , err := body . AsPlanSubscriptionChange (); err == nil {
100
+ planInput .FromRef (& plansubscription.PlanRefInput {
101
+ Key : b .Plan .Key ,
102
+ Version : b .Plan .Version ,
103
103
})
104
104
105
- timing , err := MapAPITimingToTiming (parsedBody .Timing )
105
+ subscriptionTiming , err := MapAPITimingToTiming (b .Timing )
106
106
if err != nil {
107
107
return ChangeSubscriptionRequest {}, fmt .Errorf ("failed to map timing: %w" , err )
108
108
}
109
109
110
- return ChangeSubscriptionRequest {
111
- ID : models.NamespacedID {Namespace : ns , ID : params .ID },
112
- PlanInput : planInp ,
113
- WorkflowInput : subscriptionworkflow.ChangeSubscriptionWorkflowInput {
114
- Timing : timing ,
115
- MetadataModel : models.MetadataModel {
116
- Metadata : convert.DerefHeaderPtr [string ](parsedBody .Metadata ),
117
- },
118
- Name : lo .FromPtr (parsedBody .Name ),
119
- Description : parsedBody .Description ,
110
+ startingPhase = b .StartingPhase
111
+
112
+ workflowInput = subscriptionworkflow.ChangeSubscriptionWorkflowInput {
113
+ Timing : subscriptionTiming ,
114
+ Name : lo .FromPtr (b .Name ),
115
+ Description : b .Description ,
116
+ MetadataModel : models.MetadataModel {
117
+ Metadata : convert.DerefHeaderPtr [string ](b .Metadata ),
120
118
},
121
- StartingPhase : parsedBody .StartingPhase ,
122
- }, nil
119
+ }
120
+ } else {
121
+ return ChangeSubscriptionRequest {}, models .NewGenericValidationError (fmt .Errorf ("invalid request body" ))
123
122
}
123
+
124
+ return ChangeSubscriptionRequest {
125
+ ID : models.NamespacedID {Namespace : ns , ID : params .ID },
126
+ PlanInput : planInput ,
127
+ WorkflowInput : workflowInput ,
128
+ StartingPhase : startingPhase ,
129
+ }, nil
124
130
},
125
131
func (ctx context.Context , request ChangeSubscriptionRequest ) (ChangeSubscriptionResponse , error ) {
126
132
res , err := h .PlanSubscriptionService .Change (ctx , request )
0 commit comments