Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Subscription discounts #2101

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,316 changes: 665 additions & 651 deletions api/api.gen.go

Large diffs are not rendered by default.

1,334 changes: 674 additions & 660 deletions api/client/go/client.gen.go

Large diffs are not rendered by default.

25 changes: 22 additions & 3 deletions api/openapi.cloud.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8781,6 +8781,25 @@ components:
- $ref: '#/components/schemas/BillingWorkflowPaymentSettings'
description: The payment settings for this workflow
description: BillingWorkflowSettings represents the settings for a billing workflow.
CadencedDiscount:
type: object
required:
- activeFrom
- discount
properties:
activeFrom:
type: string
format: date-time
example: 2023-01-01T01:01:01.001Z
description: The cadence start of the resource.
activeTo:
type: string
format: date-time
example: 2023-01-01T01:01:01.001Z
description: The cadence end of the resource.
discount:
$ref: '#/components/schemas/Discount'
description: Discount with information about when it applies.
CheckoutSessionCustomTextAfterSubmitParams:
type: object
properties:
Expand Down Expand Up @@ -15100,6 +15119,7 @@ components:
- createdAt
- updatedAt
- key
- discounts
- activeFrom
- items
properties:
Expand Down Expand Up @@ -15158,9 +15178,8 @@ components:
discounts:
type: array
items:
$ref: '#/components/schemas/Discount'
description: The discounts on the plan.
title: Discounts
$ref: '#/components/schemas/CadencedDiscount'
description: The discounts on the phase.
activeFrom:
type: string
format: date-time
Expand Down
73 changes: 67 additions & 6 deletions api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8475,6 +8475,25 @@ components:
- $ref: '#/components/schemas/BillingWorkflowPaymentSettings'
description: The payment settings for this workflow
description: BillingWorkflowSettings represents the settings for a billing workflow.
CadencedDiscount:
type: object
required:
- activeFrom
- discount
properties:
activeFrom:
type: string
format: date-time
example: 2023-01-01T01:01:01.001Z
description: The cadence start of the resource.
activeTo:
type: string
format: date-time
example: 2023-01-01T01:01:01.001Z
description: The cadence end of the resource.
discount:
$ref: '#/components/schemas/Discount'
description: Discount with information about when it applies.
CheckoutSessionCustomTextAfterSubmitParams:
type: object
properties:
Expand Down Expand Up @@ -9090,6 +9109,32 @@ components:
- add_phase
- remove_phase
- stretch_phase
- add_discount
- remove_discount
EditSubscriptionAddDiscount:
type: object
required:
- op
- phaseKey
- insertAt
- discount
properties:
op:
type: string
enum:
- add_discount
phaseKey:
type: string
insertAt:
type: integer
description: |-
The index at which to insert the discount.
The new discount will become the discount at the specified index.
If there is already a discount at the specified index, that and all later indexes will be shifted.
If the index is greater than the number of discounts, the new discount will be appended to the end.
discount:
$ref: '#/components/schemas/Discount'
description: Add a new discount to a phase.
EditSubscriptionAddItem:
type: object
required:
Expand Down Expand Up @@ -9119,6 +9164,22 @@ components:
phase:
$ref: '#/components/schemas/SubscriptionPhaseCreate'
description: Add a new phase
EditSubscriptionRemoveDiscount:
type: object
required:
- op
- phaseKey
- discountIndex
properties:
op:
type: string
enum:
- remove_discount
phaseKey:
type: string
discountIndex:
type: integer
description: Remove a discount from a phase.
EditSubscriptionRemoveItem:
type: object
required:
Expand Down Expand Up @@ -14888,6 +14949,7 @@ components:
- createdAt
- updatedAt
- key
- discounts
- activeFrom
properties:
id:
Expand Down Expand Up @@ -14945,9 +15007,8 @@ components:
discounts:
type: array
items:
$ref: '#/components/schemas/Discount'
description: The discounts on the plan.
title: Discounts
$ref: '#/components/schemas/CadencedDiscount'
description: The discounts on the phase.
activeFrom:
type: string
format: date-time
Expand Down Expand Up @@ -15010,6 +15071,7 @@ components:
- createdAt
- updatedAt
- key
- discounts
- activeFrom
- items
properties:
Expand Down Expand Up @@ -15068,9 +15130,8 @@ components:
discounts:
type: array
items:
$ref: '#/components/schemas/Discount'
description: The discounts on the plan.
title: Discounts
$ref: '#/components/schemas/CadencedDiscount'
description: The discounts on the phase.
activeFrom:
type: string
format: date-time
Expand Down
53 changes: 52 additions & 1 deletion api/spec/src/productcatalog/subscription.tsp
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,14 @@ model SubscriptionPhase {
// TODO: lets try this with visibility
...OmitProperties<
SubscriptionPhaseCreate,
"startAfter" | "duration" | "key" | "name" | "description"
"startAfter" | "duration" | "key" | "name" | "description" | "discounts"
>;

/**
* The discounts on the phase.
*/
discounts: CadencedDiscount[];

/**
* The time from which the phase is active.
*/
Expand All @@ -103,6 +108,15 @@ model SubscriptionPhase {
activeTo?: DateTime;
}

/**
* Discount with information about when it applies.
*/
@friendlyName("CadencedDiscount")
model CadencedDiscount {
...CadencedResource;
discount: Discount;
}

/**
* Subscription phase create input.
*/
Expand Down Expand Up @@ -319,6 +333,9 @@ model PlanSubscriptionChange {
description?: string;
}

/**
* Edit operations for a subscription.
*/
@friendlyName("SubscriptionEditOperation")
@oneOf
@discriminator("op")
Expand All @@ -330,13 +347,18 @@ union SubscriptionEditOperation {
EditSubscriptionStretchPhase,
}

/**
* Edit operation enum.
*/
@friendlyName("EditOp")
enum EditOp {
AddItem: "add_item",
RemoveItem: "remove_item",
AddPhase: "add_phase",
RemovePhase: "remove_phase",
StretchPhase: "stretch_phase",
AddDiscount: "add_discount",
RemoveDiscount: "remove_discount",
}

/**
Expand All @@ -359,6 +381,35 @@ model EditSubscriptionRemoveItem {
itemKey: string;
}

/**
* Add a new discount to a phase.
*/
@friendlyName("EditSubscriptionAddDiscount")
model EditSubscriptionAddDiscount {
`op`: EditOp.AddDiscount;
phaseKey: string;

/**
* The index at which to insert the discount.
* The new discount will become the discount at the specified index.
* If there is already a discount at the specified index, that and all later indexes will be shifted.
* If the index is greater than the number of discounts, the new discount will be appended to the end.
*/
insertAt: integer;

discount: Discount;
}

/**
* Remove a discount from a phase.
*/
@friendlyName("EditSubscriptionRemoveDiscount")
model EditSubscriptionRemoveDiscount {
`op`: EditOp.RemoveDiscount;
phaseKey: string;
discountIndex: integer;
}

/**
* Add a new phase
*/
Expand Down
23 changes: 23 additions & 0 deletions openmeter/subscription/discount.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package subscription

import (
"github.com/openmeterio/openmeter/openmeter/productcatalog"
"github.com/openmeterio/openmeter/pkg/models"
)

type Discount struct {
models.NamespacedID
models.CadencedModel
productcatalog.Discount

PhaseID string `json:"phaseId"`
SubscriptionID string `json:"subscriptionId"`
}

func (d Discount) Validate() error {
if err := d.Discount.Validate(); err != nil {
return err
}

return nil
}
17 changes: 7 additions & 10 deletions openmeter/subscription/item.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package subscription

import (
"github.com/openmeterio/openmeter/pkg/datex"
"github.com/openmeterio/openmeter/pkg/models"
)

Expand All @@ -11,9 +10,7 @@ type SubscriptionItem struct {
models.AnnotatedModel `json:",inline"`

// SubscriptionItem doesn't have a separate Cadence, only one relative to the phase, denoting if it's intentionally different from the phase's cadence.
// The durations are relative to phase start.
ActiveFromOverrideRelativeToPhaseStart *datex.Period `json:"activeFromOverrideRelativeToPhaseStart,omitempty"`
ActiveToOverrideRelativeToPhaseStart *datex.Period `json:"activeToOverrideRelativeToPhaseStart,omitempty"`
CadenceOverrideRelativeToPhaseStart

// The defacto cadence of the item is calculated and persisted after each change.
models.CadencedModel `json:",inline"`
Expand All @@ -38,14 +35,14 @@ type SubscriptionItem struct {
func (i SubscriptionItem) GetCadence(phaseCadence models.CadencedModel) models.CadencedModel {
start := phaseCadence.ActiveFrom

if i.ActiveFromOverrideRelativeToPhaseStart != nil {
start, _ = i.ActiveFromOverrideRelativeToPhaseStart.AddTo(start)
if i.CadenceOverrideRelativeToPhaseStart.ActiveFromOverride != nil {
start, _ = i.CadenceOverrideRelativeToPhaseStart.ActiveFromOverride.AddTo(start)
}

end := phaseCadence.ActiveTo

if i.ActiveToOverrideRelativeToPhaseStart != nil {
iEnd, _ := i.ActiveToOverrideRelativeToPhaseStart.AddTo(start)
if i.CadenceOverrideRelativeToPhaseStart.ActiveToOverride != nil {
iEnd, _ := i.CadenceOverrideRelativeToPhaseStart.ActiveToOverride.AddTo(start)

if end == nil || iEnd.Before(*end) {
end = &iEnd
Expand All @@ -65,8 +62,8 @@ func (i SubscriptionItem) AsEntityInput() CreateSubscriptionItemEntityInput {
},
AnnotatedModel: i.AnnotatedModel,
CadencedModel: i.CadencedModel,
ActiveFromOverrideRelativeToPhaseStart: i.ActiveFromOverrideRelativeToPhaseStart,
ActiveToOverrideRelativeToPhaseStart: i.ActiveToOverrideRelativeToPhaseStart,
ActiveFromOverrideRelativeToPhaseStart: i.CadenceOverrideRelativeToPhaseStart.ActiveFromOverride,
ActiveToOverrideRelativeToPhaseStart: i.CadenceOverrideRelativeToPhaseStart.ActiveToOverride,
PhaseID: i.PhaseId,
Key: i.Key,
RateCard: i.RateCard,
Expand Down
Loading
Loading