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

feat: billing add subscription metadata to lines #1959

Merged
merged 1 commit into from
Dec 13, 2024
Merged
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,462 changes: 744 additions & 718 deletions api/api.gen.go

Large diffs are not rendered by default.

1,482 changes: 754 additions & 728 deletions api/client/go/client.gen.go

Large diffs are not rendered by default.

46 changes: 46 additions & 0 deletions api/openapi.cloud.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10913,6 +10913,19 @@ components:
example: 100
description: The usage in the period
description: Usage Record
IDResource:
type: object
required:
- id
properties:
id:
type: string
example: 01G65Z755AFWAKHE12NY0CQ9FH
pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$
description: A unique identifier for the resource.
title: ID
readOnly: true
description: IDResource is a resouce with an ID.
IngestEventsBody:
anyOf:
- $ref: '#/components/schemas/Event'
Expand Down Expand Up @@ -11335,6 +11348,11 @@ components:
- $ref: '#/components/schemas/InvoiceLineAppExternalIDs'
description: External IDs of the invoice in other apps such as Stripe.
readOnly: true
subscriptions:
allOf:
- $ref: '#/components/schemas/InvoiceLineSubscriptionReference'
description: Subscription are the references to the subscritpions that this line is related to.
readOnly: true
type:
type: string
enum:
Expand Down Expand Up @@ -11601,6 +11619,29 @@ components:
- detail
- split
description: Line status specifies the status of the line.
InvoiceLineSubscriptionReference:
type: object
required:
- subscription
- phase
- item
properties:
subscription:
allOf:
- $ref: '#/components/schemas/IDResource'
description: The subscription.
readOnly: true
phase:
allOf:
- $ref: '#/components/schemas/IDResource'
description: The phase of the subscription.
readOnly: true
item:
allOf:
- $ref: '#/components/schemas/IDResource'
description: The item this line is related to.
readOnly: true
description: InvoiceLineSubscriptionReference contains the references to the subscriptions that this line is related to.
InvoiceLineTaxBehavior:
type: string
enum:
Expand Down Expand Up @@ -11984,6 +12025,11 @@ components:
- $ref: '#/components/schemas/InvoiceLineAppExternalIDs'
description: External IDs of the invoice in other apps such as Stripe.
readOnly: true
subscriptions:
allOf:
- $ref: '#/components/schemas/InvoiceLineSubscriptionReference'
description: Subscription are the references to the subscritpions that this line is related to.
readOnly: true
type:
type: string
enum:
Expand Down
46 changes: 46 additions & 0 deletions api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10603,6 +10603,19 @@ components:
example: 100
description: The usage in the period
description: Usage Record
IDResource:
type: object
required:
- id
properties:
id:
type: string
example: 01G65Z755AFWAKHE12NY0CQ9FH
pattern: ^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$
description: A unique identifier for the resource.
title: ID
readOnly: true
description: IDResource is a resouce with an ID.
IngestEventsBody:
anyOf:
- $ref: '#/components/schemas/Event'
Expand Down Expand Up @@ -11025,6 +11038,11 @@ components:
- $ref: '#/components/schemas/InvoiceLineAppExternalIDs'
description: External IDs of the invoice in other apps such as Stripe.
readOnly: true
subscriptions:
allOf:
- $ref: '#/components/schemas/InvoiceLineSubscriptionReference'
description: Subscription are the references to the subscritpions that this line is related to.
readOnly: true
type:
type: string
enum:
Expand Down Expand Up @@ -11291,6 +11309,29 @@ components:
- detail
- split
description: Line status specifies the status of the line.
InvoiceLineSubscriptionReference:
type: object
required:
- subscription
- phase
- item
properties:
subscription:
allOf:
- $ref: '#/components/schemas/IDResource'
description: The subscription.
readOnly: true
phase:
allOf:
- $ref: '#/components/schemas/IDResource'
description: The phase of the subscription.
readOnly: true
item:
allOf:
- $ref: '#/components/schemas/IDResource'
description: The item this line is related to.
readOnly: true
description: InvoiceLineSubscriptionReference contains the references to the subscriptions that this line is related to.
InvoiceLineTaxBehavior:
type: string
enum:
Expand Down Expand Up @@ -11674,6 +11715,11 @@ components:
- $ref: '#/components/schemas/InvoiceLineAppExternalIDs'
description: External IDs of the invoice in other apps such as Stripe.
readOnly: true
subscriptions:
allOf:
- $ref: '#/components/schemas/InvoiceLineSubscriptionReference'
description: Subscription are the references to the subscritpions that this line is related to.
readOnly: true
type:
type: string
enum:
Expand Down
30 changes: 30 additions & 0 deletions api/spec/src/billing/invoices/invoice.tsp
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,12 @@ model InvoiceLineBase {
*/
@visibility("read")
externalIDs?: InvoiceLineAppExternalIDs;

/**
* Subscription are the references to the subscritpions that this line is related to.
*/
@visibility("read")
subscriptions?: InvoiceLineSubscriptionReference;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be singular? Looks like reference is for one.

}

/**
Expand Down Expand Up @@ -890,3 +896,27 @@ model InvoiceLineAppExternalIDs {
@visibility("read")
Tax?: string;
}

/**
* InvoiceLineSubscriptionReference contains the references to the subscriptions that this line is related to.
*/
@friendlyName("InvoiceLineSubscriptionReference")
model InvoiceLineSubscriptionReference {
/**
* The subscription.
*/
@visibility("read")
subscription: IDResource;

/**
* The phase of the subscription.
*/
@visibility("read")
phase: IDResource;

/**
* The item this line is related to.
*/
@visibility("read")
item: IDResource;
}
16 changes: 16 additions & 0 deletions api/spec/src/types.tsp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,22 @@ model UniqueResource {
key: Key;
}

/**
* IDResource is a resouce with an ID.
*/
// NOTE: this can be used to have a type, that we can later replace with the expanded type if needed without
// breaking api compatibility
@friendlyName("IDResource")
model IDResource {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the value of doing IDResource? Is the resource type changing for the fields where it's used?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This btw reminds me of GraphQL's global IDs where every resource's ID is globally unique. Usually it's a concatenation of the type and ID .

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just an API compatibility issue. This allows the response to be like this:

{
   "subscription": {
      "subscription": {
         "id": ...
      },
      "phase": {
          "id": ...
      }
...
}

This way if we want to extend the API with extending the objects later, we can do that without needing to break the API.

/**
* A unique identifier for the resource.
*/
@visibility("read")
@example("01G65Z755AFWAKHE12NY0CQ9FH")
@summary("ID")
id: ULID;
}

/**
* Represents common fields of resources.
*/
Expand Down
8 changes: 8 additions & 0 deletions openmeter/billing/adapter/invoicelinemapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,14 @@ func (a *adapter) mapInvoiceLineWithoutReferences(dbLine *db.BillingInvoiceLine)
},
}

if dbLine.SubscriptionID != nil && dbLine.SubscriptionPhaseID != nil && dbLine.SubscriptionItemID != nil {
invoiceLine.Subscription = &billing.SubscriptionReference{
SubscriptionID: *dbLine.SubscriptionID,
PhaseID: *dbLine.SubscriptionPhaseID,
ItemID: *dbLine.SubscriptionItemID,
}
}

switch dbLine.Type {
case billing.InvoiceLineTypeFee:
invoiceLine.FlatFee = billing.FlatFeeLine{
Expand Down
6 changes: 6 additions & 0 deletions openmeter/billing/adapter/invoicelines.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ func (a *adapter) UpsertInvoiceLines(ctx context.Context, inputIn billing.Upsert
// ExternalIDs
SetNillableInvoicingAppExternalID(lo.EmptyableToPtr(line.ExternalIDs.Invoicing))

if line.Subscription != nil {
create = create.SetSubscriptionID(line.Subscription.ItemID).
SetSubscriptionPhaseID(line.Subscription.PhaseID).
SetSubscriptionItemID(line.Subscription.ItemID)
}

if line.TaxConfig != nil {
create = create.SetTaxConfig(*line.TaxConfig)
}
Expand Down
20 changes: 20 additions & 0 deletions openmeter/billing/httpdriver/invoiceline.go
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,7 @@ func mapFeeLineToAPI(line *billing.Line) (api.InvoiceLine, error) {
ExternalIDs: &api.InvoiceLineAppExternalIDs{
Invoicing: lo.EmptyableToPtr(line.ExternalIDs.Invoicing),
},
Subscriptions: mapSubscriptionReferencesToAPI(line.Subscription),
}

out := api.InvoiceLine{}
Expand Down Expand Up @@ -564,6 +565,7 @@ func mapUsageBasedLineToAPI(line *billing.Line) (api.InvoiceLine, error) {
ExternalIDs: lo.EmptyableToPtr(api.InvoiceLineAppExternalIDs{
Invoicing: lo.EmptyableToPtr(line.ExternalIDs.Invoicing),
}),
Subscriptions: mapSubscriptionReferencesToAPI(line.Subscription),
}

out := api.InvoiceLine{}
Expand All @@ -575,6 +577,24 @@ func mapUsageBasedLineToAPI(line *billing.Line) (api.InvoiceLine, error) {
return out, nil
}

func mapSubscriptionReferencesToAPI(optSub *billing.SubscriptionReference) *api.InvoiceLineSubscriptionReference {
if optSub == nil {
return nil
}

return &api.InvoiceLineSubscriptionReference{
Item: api.IDResource{
Id: optSub.SubscriptionID,
},
Phase: api.IDResource{
Id: optSub.PhaseID,
},
Subscription: api.IDResource{
Id: optSub.ItemID,
},
}
}

func mapDiscountsToAPI(optDiscounts billing.LineDiscounts) *[]api.InvoiceLineDiscount {
if optDiscounts.IsAbsent() {
return nil
Expand Down
9 changes: 8 additions & 1 deletion openmeter/billing/invoiceline.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ type LineBase struct {

TaxConfig *TaxConfig `json:"taxOverrides,omitempty"`

ExternalIDs LineExternalIDs `json:"externalIDs,omitempty"`
ExternalIDs LineExternalIDs `json:"externalIDs,omitempty"`
Subscription *SubscriptionReference `json:"subscription,omitempty"`

Totals Totals `json:"totals"`
}
Expand Down Expand Up @@ -188,6 +189,12 @@ func (i LineBase) Clone(line *Line) LineBase {
return out
}

type SubscriptionReference struct {
SubscriptionID string `json:"subscriptionID"`
PhaseID string `json:"phaseID"`
ItemID string `json:"itemID"`
}

type LineExternalIDs struct {
Invoicing string `json:"invoicing,omitempty"`
}
Expand Down
Loading
Loading