Skip to content

Commit 316f782

Browse files
committed
refactor: disambiguate lines vs detailed lines
1 parent daa356d commit 316f782

35 files changed

+2974
-3221
lines changed

api/api.gen.go

Lines changed: 1165 additions & 1157 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/client/go/client.gen.go

Lines changed: 1131 additions & 1123 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/client/javascript/src/client/schemas.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5720,11 +5720,6 @@ export interface components {
57205720
* External calls always create valid lines, other line types are managed by the
57215721
* billing engine of OpenMeter. */
57225722
readonly status: components['schemas']['InvoiceLineStatus']
5723-
/** @description Discounts detailes applied to this line.
5724-
*
5725-
* New discounts can be added via the invoice's discounts API, to facilitate
5726-
* discounts that are affecting multiple lines. */
5727-
readonly discounts?: components['schemas']['InvoiceLineDiscounts']
57285723
/** @description The invoice this item belongs to. */
57295724
invoice?: components['schemas']['InvoiceReference']
57305725
/** @description The currency of this line. */
@@ -5781,13 +5776,25 @@ export interface components {
57815776
* @default regular
57825777
*/
57835778
readonly category?: components['schemas']['InvoiceDetailedLineCostCategory']
5779+
/** @description Discounts detailes applied to this line.
5780+
*
5781+
* New discounts can be added via the invoice's discounts API, to facilitate
5782+
* discounts that are affecting multiple lines. */
5783+
readonly discounts?: components['schemas']['InvoiceDetailedLineDiscounts']
57845784
}
57855785
/**
57865786
* @description InvoiceDetailedLineCostCategory determines if the flat fee is a regular fee due to use due to a
57875787
* commitment.
57885788
* @enum {string}
57895789
*/
57905790
InvoiceDetailedLineCostCategory: 'regular' | 'commitment'
5791+
/** @description InvoiceLineDiscounts represents the discounts applied to the invoice line by type. */
5792+
InvoiceDetailedLineDiscounts: {
5793+
/** @description Amount based discounts applied to the line.
5794+
*
5795+
* Amount based discounts are deduced from the total price of the line. */
5796+
amount?: components['schemas']['InvoiceLineAmountDiscount'][]
5797+
}
57915798
/** @description InvoiceDetailedLineRateCard represents the rate card (intent) for a flat fee line. */
57925799
InvoiceDetailedLineRateCard: {
57935800
/**
@@ -6083,7 +6090,7 @@ export interface components {
60836090
* @description Line status specifies the status of the line.
60846091
* @enum {string}
60856092
*/
6086-
InvoiceLineStatus: 'valid' | 'detail' | 'split'
6093+
InvoiceLineStatus: 'valid' | 'detailed' | 'split'
60876094
/** @description InvoiceLineSubscriptionReference contains the references to the subscription that this line is related to. */
60886095
InvoiceLineSubscriptionReference: {
60896096
/** @description The subscription. */
@@ -10940,6 +10947,8 @@ export type InvoiceAvailableActions =
1094010947
export type InvoiceDetailedLine = components['schemas']['InvoiceDetailedLine']
1094110948
export type InvoiceDetailedLineCostCategory =
1094210949
components['schemas']['InvoiceDetailedLineCostCategory']
10950+
export type InvoiceDetailedLineDiscounts =
10951+
components['schemas']['InvoiceDetailedLineDiscounts']
1094310952
export type InvoiceDetailedLineRateCard =
1094410953
components['schemas']['InvoiceDetailedLineRateCard']
1094510954
export type InvoiceDocumentRef = components['schemas']['InvoiceDocumentRef']

api/openapi.cloud.yaml

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16814,15 +16814,6 @@ components:
1681416814
External calls always create valid lines, other line types are managed by the
1681516815
billing engine of OpenMeter.
1681616816
readOnly: true
16817-
discounts:
16818-
allOf:
16819-
- $ref: '#/components/schemas/InvoiceLineDiscounts'
16820-
description: |-
16821-
Discounts detailes applied to this line.
16822-
16823-
New discounts can be added via the invoice's discounts API, to facilitate
16824-
discounts that are affecting multiple lines.
16825-
readOnly: true
1682616817
invoice:
1682716818
allOf:
1682816819
- $ref: '#/components/schemas/InvoiceReference'
@@ -16902,6 +16893,15 @@ components:
1690216893
description: Category of the flat fee.
1690316894
default: regular
1690416895
readOnly: true
16896+
discounts:
16897+
allOf:
16898+
- $ref: '#/components/schemas/InvoiceDetailedLineDiscounts'
16899+
description: |-
16900+
Discounts detailes applied to this line.
16901+
16902+
New discounts can be added via the invoice's discounts API, to facilitate
16903+
discounts that are affecting multiple lines.
16904+
readOnly: true
1690516905
description: InvoiceDetailedLine represents a line item that is sold to the customer as a manually added fee.
1690616906
InvoiceDetailedLineCostCategory:
1690716907
type: string
@@ -16911,6 +16911,18 @@ components:
1691116911
description: |-
1691216912
InvoiceDetailedLineCostCategory determines if the flat fee is a regular fee due to use due to a
1691316913
commitment.
16914+
InvoiceDetailedLineDiscounts:
16915+
type: object
16916+
properties:
16917+
amount:
16918+
type: array
16919+
items:
16920+
$ref: '#/components/schemas/InvoiceLineAmountDiscount'
16921+
description: |-
16922+
Amount based discounts applied to the line.
16923+
16924+
Amount based discounts are deduced from the total price of the line.
16925+
description: InvoiceLineDiscounts represents the discounts applied to the invoice line by type.
1691416926
InvoiceDetailedLineRateCard:
1691516927
type: object
1691616928
required:
@@ -17351,7 +17363,7 @@ components:
1735117363
type: string
1735217364
enum:
1735317365
- valid
17354-
- detail
17366+
- detailed
1735517367
- split
1735617368
description: Line status specifies the status of the line.
1735717369
InvoiceLineSubscriptionReference:

api/openapi.yaml

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17174,15 +17174,6 @@ components:
1717417174
External calls always create valid lines, other line types are managed by the
1717517175
billing engine of OpenMeter.
1717617176
readOnly: true
17177-
discounts:
17178-
allOf:
17179-
- $ref: '#/components/schemas/InvoiceLineDiscounts'
17180-
description: |-
17181-
Discounts detailes applied to this line.
17182-
17183-
New discounts can be added via the invoice's discounts API, to facilitate
17184-
discounts that are affecting multiple lines.
17185-
readOnly: true
1718617177
invoice:
1718717178
allOf:
1718817179
- $ref: '#/components/schemas/InvoiceReference'
@@ -17262,6 +17253,15 @@ components:
1726217253
description: Category of the flat fee.
1726317254
default: regular
1726417255
readOnly: true
17256+
discounts:
17257+
allOf:
17258+
- $ref: '#/components/schemas/InvoiceDetailedLineDiscounts'
17259+
description: |-
17260+
Discounts detailes applied to this line.
17261+
17262+
New discounts can be added via the invoice's discounts API, to facilitate
17263+
discounts that are affecting multiple lines.
17264+
readOnly: true
1726517265
description: InvoiceDetailedLine represents a line item that is sold to the customer as a manually added fee.
1726617266
InvoiceDetailedLineCostCategory:
1726717267
type: string
@@ -17271,6 +17271,18 @@ components:
1727117271
description: |-
1727217272
InvoiceDetailedLineCostCategory determines if the flat fee is a regular fee due to use due to a
1727317273
commitment.
17274+
InvoiceDetailedLineDiscounts:
17275+
type: object
17276+
properties:
17277+
amount:
17278+
type: array
17279+
items:
17280+
$ref: '#/components/schemas/InvoiceLineAmountDiscount'
17281+
description: |-
17282+
Amount based discounts applied to the line.
17283+
17284+
Amount based discounts are deduced from the total price of the line.
17285+
description: InvoiceLineDiscounts represents the discounts applied to the invoice line by type.
1727417286
InvoiceDetailedLineRateCard:
1727517287
type: object
1727617288
required:
@@ -17902,7 +17914,7 @@ components:
1790217914
type: string
1790317915
enum:
1790417916
- valid
17905-
- detail
17917+
- detailed
1790617918
- split
1790717919
description: Line status specifies the status of the line.
1790817920
InvoiceLineSubscriptionReference:

api/spec/src/billing/invoices/invoice.tsp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,7 @@ enum InvoiceLineTypes {
463463
/**
464464
* Line status specifies the status of the line.
465465
*/
466+
// TODO[v2]: Deprecate this type altogether
466467
@friendlyName("InvoiceLineStatus")
467468
enum InvoiceLineStatus {
468469
/**
@@ -474,7 +475,7 @@ enum InvoiceLineStatus {
474475
* The line is a detail line which is used to detail the individual
475476
* charges and discounts of a valid line.
476477
*/
477-
detail: "detail",
478+
detailed: "detailed",
478479

479480
/**
480481
* The line has been split into multiple valid lines due to progressive
@@ -762,7 +763,7 @@ model InvoiceDetailedLineRateCard {
762763
*/
763764
@friendlyName("InvoiceDetailedLine")
764765
model InvoiceDetailedLine {
765-
...OmitProperties<InvoiceLineBase, "type">;
766+
...OmitProperties<InvoiceLineBase, "type" | "discounts">;
766767

767768
/**
768769
* Type of the line.
@@ -804,6 +805,28 @@ model InvoiceDetailedLine {
804805
*/
805806
@visibility(Lifecycle.Read)
806807
category?: InvoiceDetailedLineCostCategory = InvoiceDetailedLineCostCategory.regular;
808+
809+
/**
810+
* Discounts detailes applied to this line.
811+
*
812+
* New discounts can be added via the invoice's discounts API, to facilitate
813+
* discounts that are affecting multiple lines.
814+
*/
815+
@visibility(Lifecycle.Read)
816+
discounts?: InvoiceDetailedLineDiscounts;
817+
}
818+
819+
/**
820+
* InvoiceLineDiscounts represents the discounts applied to the invoice line by type.
821+
*/
822+
@friendlyName("InvoiceDetailedLineDiscounts")
823+
model InvoiceDetailedLineDiscounts {
824+
/**
825+
* Amount based discounts applied to the line.
826+
*
827+
* Amount based discounts are deduced from the total price of the line.
828+
*/
829+
amount?: InvoiceLineAmountDiscount[];
807830
}
808831

809832
/**

openmeter/app/stripe/entity/app/invoice.go

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -205,12 +205,12 @@ func (a App) createInvoice(ctx context.Context, invoice billing.Invoice) (*billi
205205
// Add lines to the Stripe invoice
206206
var stripeLineAdd []*stripe.InvoiceItemParams
207207

208-
leafLines := invoice.GetLeafLinesWithConsolidatedTaxBehavior()
208+
leafLines := invoice.GetDetailedLinesWithConsolidatedTaxBehavior()
209209

210210
// Iterate over the leaf lines
211211
for _, line := range leafLines {
212212
// Add discounts for line if any
213-
for _, discount := range line.Discounts.Amount {
213+
for _, discount := range line.AmountDiscounts {
214214
stripeLineAdd = append(stripeLineAdd, getDiscountStripeAddInvoiceItemParams(calculator, line, discount, stripeCustomerData.StripeCustomerID))
215215
}
216216

@@ -304,7 +304,7 @@ func (a App) updateInvoice(ctx context.Context, invoice billing.Invoice) (*billi
304304
stripeLinesRemove []string
305305
)
306306

307-
leafLines := invoice.GetLeafLinesWithConsolidatedTaxBehavior()
307+
leafLines := invoice.GetDetailedLinesWithConsolidatedTaxBehavior()
308308

309309
// Helper to get a Stripe line item by ID
310310
stripeLinesByID := make(map[string]*stripe.InvoiceLineItem)
@@ -319,7 +319,7 @@ func (a App) updateInvoice(ctx context.Context, invoice billing.Invoice) (*billi
319319

320320
// Iterate over the leaf lines
321321
for _, line := range leafLines {
322-
amountDiscountsById, err := line.Discounts.Amount.GetByID()
322+
amountDiscountsById, err := line.AmountDiscounts.GetByID()
323323
if err != nil {
324324
return nil, fmt.Errorf("failed to get amount discounts by ID: %w", err)
325325
}
@@ -452,7 +452,7 @@ func sortInvoiceLines[K StripeInvoiceLineOperationParams](stripeLineAdd []*K) {
452452
// getDiscountStripeUpdateInvoiceItemParams returns the Stripe line item for a discount
453453
func getDiscountStripeUpdateInvoiceItemParams(
454454
calculator StripeCalculator,
455-
line *billing.Line,
455+
line billing.DetailedLine,
456456
discount billing.AmountLineDiscountManaged,
457457
stripeLine *stripe.InvoiceLineItem,
458458
) *stripeclient.StripeInvoiceItemWithID {
@@ -463,7 +463,7 @@ func getDiscountStripeUpdateInvoiceItemParams(
463463
}
464464

465465
// getDiscountStripeInvoiceItemParams returns the Stripe line item for a discount
466-
func getDiscountStripeInvoiceItemParams(calculator StripeCalculator, line *billing.Line, discount billing.AmountLineDiscountManaged) *stripe.InvoiceItemParams {
466+
func getDiscountStripeInvoiceItemParams(calculator StripeCalculator, line billing.DetailedLine, discount billing.AmountLineDiscountManaged) *stripe.InvoiceItemParams {
467467
name := getDiscountLineName(line, discount)
468468
period := getPeriod(line)
469469

@@ -480,14 +480,14 @@ func getDiscountStripeInvoiceItemParams(calculator StripeCalculator, line *billi
480480
return applyTaxSettingsToInvoiceItem(addParams, line)
481481
}
482482

483-
func getDiscountStripeAddInvoiceItemParams(calculator StripeCalculator, line *billing.Line, discount billing.AmountLineDiscountManaged, stripeCustomerID string) *stripe.InvoiceItemParams {
483+
func getDiscountStripeAddInvoiceItemParams(calculator StripeCalculator, line billing.DetailedLine, discount billing.AmountLineDiscountManaged, stripeCustomerID string) *stripe.InvoiceItemParams {
484484
params := getDiscountStripeInvoiceItemParams(calculator, line, discount)
485485
// Customer is required for adds
486486
params.Customer = stripe.String(stripeCustomerID)
487487
return params
488488
}
489489

490-
func applyTaxSettingsToInvoiceItem(add *stripe.InvoiceItemParams, line *billing.Line) *stripe.InvoiceItemParams {
490+
func applyTaxSettingsToInvoiceItem(add *stripe.InvoiceItemParams, line billing.DetailedLine) *stripe.InvoiceItemParams {
491491
if line.TaxConfig != nil && !lo.IsEmpty(line.TaxConfig) {
492492
if line.TaxConfig.Behavior != nil {
493493
add.TaxBehavior = getStripeTaxBehavior(line.TaxConfig.Behavior)
@@ -504,7 +504,7 @@ func applyTaxSettingsToInvoiceItem(add *stripe.InvoiceItemParams, line *billing.
504504
// getStripeUpdateInvoiceItemParams returns the Stripe update line params
505505
func getStripeUpdateInvoiceItemParams(
506506
calculator StripeCalculator,
507-
line *billing.Line,
507+
line billing.DetailedLine,
508508
stripeLine *stripe.InvoiceLineItem,
509509
) *stripeclient.StripeInvoiceItemWithID {
510510
return &stripeclient.StripeInvoiceItemWithID{
@@ -514,7 +514,7 @@ func getStripeUpdateInvoiceItemParams(
514514
}
515515

516516
// getStripeAddLinesLineParams returns the Stripe line item
517-
func getStripeInvoiceItemParams(line *billing.Line, calculator StripeCalculator) *stripe.InvoiceItemParams {
517+
func getStripeInvoiceItemParams(line billing.DetailedLine, calculator StripeCalculator) *stripe.InvoiceItemParams {
518518
description := getLineName(line)
519519
period := getPeriod(line)
520520
amount := line.Totals.Amount
@@ -551,22 +551,22 @@ func getStripeInvoiceItemParams(line *billing.Line, calculator StripeCalculator)
551551
}
552552

553553
// getStripeAddInvoiceItemParams returns the Stripe line item
554-
func getStripeAddInvoiceItemParams(line *billing.Line, calculator StripeCalculator, stripeCustomerID string) *stripe.InvoiceItemParams {
554+
func getStripeAddInvoiceItemParams(line billing.DetailedLine, calculator StripeCalculator, stripeCustomerID string) *stripe.InvoiceItemParams {
555555
params := getStripeInvoiceItemParams(line, calculator)
556556
params.Customer = stripe.String(stripeCustomerID)
557557
return params
558558
}
559559

560560
// getPeriod returns the period
561-
func getPeriod(line *billing.Line) *stripe.InvoiceItemPeriodParams {
561+
func getPeriod(line billing.DetailedLine) *stripe.InvoiceItemPeriodParams {
562562
return &stripe.InvoiceItemPeriodParams{
563563
Start: lo.ToPtr(line.Period.Start.Unix()),
564564
End: lo.ToPtr(line.Period.End.Unix()),
565565
}
566566
}
567567

568568
// getDiscountLineName returns the line name
569-
func getDiscountLineName(line *billing.Line, discount billing.AmountLineDiscountManaged) string {
569+
func getDiscountLineName(line billing.DetailedLine, discount billing.AmountLineDiscountManaged) string {
570570
name := line.Name
571571
if discount.Description != nil {
572572
name = fmt.Sprintf("%s (%s)", name, *discount.Description)
@@ -576,7 +576,7 @@ func getDiscountLineName(line *billing.Line, discount billing.AmountLineDiscount
576576
}
577577

578578
// getLineName returns the line name
579-
func getLineName(line *billing.Line) string {
579+
func getLineName(line billing.DetailedLine) string {
580580
name := line.Name
581581
if line.Description != nil {
582582
name = fmt.Sprintf("%s (%s)", name, *line.Description)

openmeter/billing/adapter/invoicelines.go

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ func (a *adapter) UpsertInvoiceLines(ctx context.Context, inputIn billing.Upsert
8080
SetNillableSplitLineGroupID(line.SplitLineGroupID).
8181
SetNillableDeletedAt(line.DeletedAt).
8282
SetInvoiceAt(line.InvoiceAt.In(time.UTC)).
83-
SetStatus(line.Status).
83+
SetStatus(billing.InvoiceLineStatusValid).
8484
SetManagedBy(line.ManagedBy).
85-
SetType(line.Type).
85+
SetType(billing.InvoiceLineTypeUsageBased).
8686
SetName(line.Name).
8787
SetNillableDescription(line.Description).
8888
SetCurrency(line.Currency).
@@ -288,9 +288,9 @@ func (a *adapter) UpsertInvoiceLines(ctx context.Context, inputIn billing.Upsert
288288
})
289289
}
290290

291-
func (a *adapter) upsertFeeLineConfig(ctx context.Context, in diff[*billing.Line]) error {
292-
return upsertWithOptions(ctx, a.db, in, upsertInput[*billing.Line, *db.BillingInvoiceFlatFeeLineConfigCreate]{
293-
Create: func(tx *db.Client, line *billing.Line) (*db.BillingInvoiceFlatFeeLineConfigCreate, error) {
291+
func (a *adapter) upsertFeeLineConfig(ctx context.Context, in diff[*billing.DetailedLine]) error {
292+
return upsertWithOptions(ctx, a.db, in, upsertInput[*billing.DetailedLine, *db.BillingInvoiceFlatFeeLineConfigCreate]{
293+
Create: func(tx *db.Client, line *billing.DetailedLine) (*db.BillingInvoiceFlatFeeLineConfigCreate, error) {
294294
if line.FlatFee.ConfigID == "" {
295295
line.FlatFee.ConfigID = ulid.Make().String()
296296
}
@@ -302,10 +302,7 @@ func (a *adapter) upsertFeeLineConfig(ctx context.Context, in diff[*billing.Line
302302
SetPaymentTerm(line.FlatFee.PaymentTerm).
303303
SetID(line.FlatFee.ConfigID)
304304

305-
if line.Status == billing.InvoiceLineStatusDetailed {
306-
// TODO[later]: Detailed lines must be a separate entity, so that we don't need these hacks (like line config or type specific sets)
307-
create = create.SetNillableIndex(line.FlatFee.Index)
308-
}
305+
create = create.SetNillableIndex(line.FlatFee.Index)
309306

310307
return create, nil
311308
},

0 commit comments

Comments
 (0)