@@ -2,15 +2,17 @@ package httpdriver
22
33import (
44 "context"
5- "encoding/json"
65 "fmt"
76 "net/http"
87
98 "github.com/samber/lo"
109
1110 "github.com/openmeterio/openmeter/api"
11+ "github.com/openmeterio/openmeter/openmeter/productcatalog"
12+ "github.com/openmeterio/openmeter/openmeter/productcatalog/plan"
1213 plansubscription "github.com/openmeterio/openmeter/openmeter/productcatalog/subscription"
1314 subscriptionworkflow "github.com/openmeterio/openmeter/openmeter/subscription/workflow"
15+ "github.com/openmeterio/openmeter/pkg/clock"
1416 "github.com/openmeterio/openmeter/pkg/convert"
1517 "github.com/openmeterio/openmeter/pkg/framework/commonhttp"
1618 "github.com/openmeterio/openmeter/pkg/framework/transport/httptransport"
@@ -37,90 +39,94 @@ func (h *handler) ChangeSubscription() ChangeSubscriptionHandler {
3739
3840 ns , err := h .resolveNamespace (ctx )
3941 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 )
4743 }
4844
49- var t testForCustomPlan
45+ workflowInput := subscriptionworkflow. ChangeSubscriptionWorkflowInput {}
5046
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
5549
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+ }
5957
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 )
6360 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 )
6562 }
6663
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+ })
6876 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 )
7078 }
7179
72- planInp := plansubscription.PlanInput {}
73- planInp .FromInput (& req )
80+ planInput .FromRef (& plansubscription.PlanRefInput {
81+ Key : customPlan .Key ,
82+ Version : & customPlan .Version ,
83+ })
7484
75- timing , err := MapAPITimingToTiming (parsedBody .Timing )
85+ subscriptionTiming , err := MapAPITimingToTiming (b .Timing )
7686 if err != nil {
7787 return ChangeSubscriptionRequest {}, fmt .Errorf ("failed to map timing: %w" , err )
7888 }
7989
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 ),
9096 },
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 )
9797 }
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 ,
103103 })
104104
105- timing , err := MapAPITimingToTiming (parsedBody .Timing )
105+ subscriptionTiming , err := MapAPITimingToTiming (b .Timing )
106106 if err != nil {
107107 return ChangeSubscriptionRequest {}, fmt .Errorf ("failed to map timing: %w" , err )
108108 }
109109
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 ),
120118 },
121- StartingPhase : parsedBody .StartingPhase ,
122- }, nil
119+ }
120+ } else {
121+ return ChangeSubscriptionRequest {}, models .NewGenericValidationError (fmt .Errorf ("invalid request body" ))
123122 }
123+
124+ return ChangeSubscriptionRequest {
125+ ID : models.NamespacedID {Namespace : ns , ID : params .ID },
126+ PlanInput : planInput ,
127+ WorkflowInput : workflowInput ,
128+ StartingPhase : startingPhase ,
129+ }, nil
124130 },
125131 func (ctx context.Context , request ChangeSubscriptionRequest ) (ChangeSubscriptionResponse , error ) {
126132 res , err := h .PlanSubscriptionService .Change (ctx , request )
0 commit comments