Skip to content
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
10 changes: 9 additions & 1 deletion openmeter/billing/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type Adapter interface {
ProfileAdapter
CustomerOverrideAdapter
InvoiceLineAdapter
InvoiceSplitLineGroupAdapter
InvoiceAdapter
SequenceAdapter
InvoiceAppAdapter
Expand Down Expand Up @@ -59,7 +60,7 @@ type InvoiceLineAdapter interface {
UpsertInvoiceLines(ctx context.Context, input UpsertInvoiceLinesAdapterInput) ([]*Line, error)
ListInvoiceLines(ctx context.Context, input ListInvoiceLinesAdapterInput) ([]*Line, error)
AssociateLinesToInvoice(ctx context.Context, input AssociateLinesToInvoiceAdapterInput) ([]*Line, error)
GetLinesForSubscription(ctx context.Context, input GetLinesForSubscriptionInput) ([]*Line, error)
GetLinesForSubscription(ctx context.Context, input GetLinesForSubscriptionInput) ([]LineOrHierarchy, error)
}

type InvoiceAdapter interface {
Expand All @@ -73,6 +74,13 @@ type InvoiceAdapter interface {
GetInvoiceOwnership(ctx context.Context, input GetInvoiceOwnershipAdapterInput) (GetOwnershipAdapterResponse, error)
}

type InvoiceSplitLineGroupAdapter interface {
CreateSplitLineGroup(ctx context.Context, input CreateSplitLineGroupAdapterInput) (SplitLineGroup, error)
UpdateSplitLineGroup(ctx context.Context, input UpdateSplitLineGroupInput) (SplitLineGroup, error)
DeleteSplitLineGroup(ctx context.Context, input DeleteSplitLineGroupInput) error
GetSplitLineGroup(ctx context.Context, input GetSplitLineGroupInput) (SplitLineHierarchy, error)
}

type SequenceAdapter interface {
NextSequenceNumber(ctx context.Context, input NextSequenceNumberInput) (alpacadecimal.Decimal, error)
}
Expand Down
5 changes: 1 addition & 4 deletions openmeter/billing/adapter/invoice.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,6 @@ func (a *adapter) expandInvoiceLineItems(query *db.BillingInvoiceQuery, expand b
}

requestedStatuses := []billing.InvoiceLineStatus{billing.InvoiceLineStatusValid}
if expand.SplitLines {
requestedStatuses = append(requestedStatuses, billing.InvoiceLineStatusSplit)
}

q = q.Where(
// Detailed lines are sub-lines of a line and should not be included in the top-level invoice
Expand Down Expand Up @@ -747,7 +744,7 @@ func (a *adapter) mapInvoiceFromDB(ctx context.Context, invoice *db.BillingInvoi
return billing.Invoice{}, err
}

mappedLines, err = a.expandProgressiveLineHierarchy(ctx, invoice.Namespace, mappedLines)
mappedLines, err = a.expandSplitLineHierarchy(ctx, invoice.Namespace, mappedLines)
if err != nil {
return billing.Invoice{}, err
}
Expand Down
1 change: 1 addition & 0 deletions openmeter/billing/adapter/invoicelinemapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ func (a *adapter) mapInvoiceLineWithoutReferences(dbLine *db.BillingInvoiceLine)
},

ParentLineID: dbLine.ParentLineID,
SplitLineGroupID: dbLine.SplitLineGroupID,
ChildUniqueReferenceID: dbLine.ChildUniqueReferenceID,

InvoiceAt: dbLine.InvoiceAt.In(time.UTC),
Expand Down
153 changes: 0 additions & 153 deletions openmeter/billing/adapter/invoicelineprogressive.go

This file was deleted.

108 changes: 96 additions & 12 deletions openmeter/billing/adapter/invoicelines.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/openmeterio/openmeter/openmeter/ent/db/billinginvoiceline"
"github.com/openmeterio/openmeter/openmeter/ent/db/billinginvoicelinediscount"
"github.com/openmeterio/openmeter/openmeter/ent/db/billinginvoicelineusagediscount"
"github.com/openmeterio/openmeter/openmeter/ent/db/billinginvoicesplitlinegroup"
"github.com/openmeterio/openmeter/openmeter/ent/db/billinginvoiceusagebasedlineconfig"
"github.com/openmeterio/openmeter/pkg/clock"
"github.com/openmeterio/openmeter/pkg/framework/entutils"
Expand All @@ -37,14 +38,6 @@ func (a *adapter) UpsertInvoiceLines(ctx context.Context, inputIn billing.Upsert
// Validate for missing functionality (this is put here, as we should remove them from here,
// once we have the functionality)

// TODO[OM-1015]: Updating split line's children is not supported (yet)
for _, line := range inputIn.Lines {
if line.Status == billing.InvoiceLineStatusSplit &&
line.Children.IsPresent() {
return nil, fmt.Errorf("updating split line's detailed lines is not supported")
}
}

input := &billing.UpsertInvoiceLinesAdapterInput{
Namespace: inputIn.Namespace,
Lines: lo.Map(inputIn.Lines, func(line *billing.Line, _ int) *billing.Line {
Expand Down Expand Up @@ -84,6 +77,7 @@ func (a *adapter) UpsertInvoiceLines(ctx context.Context, inputIn billing.Upsert
SetPeriodStart(line.Period.Start.In(time.UTC)).
SetPeriodEnd(line.Period.End.In(time.UTC)).
SetNillableParentLineID(line.ParentLineID).
SetNillableSplitLineGroupID(line.SplitLineGroupID).
SetNillableDeletedAt(line.DeletedAt).
SetInvoiceAt(line.InvoiceAt.In(time.UTC)).
SetStatus(line.Status).
Expand Down Expand Up @@ -144,7 +138,9 @@ func (a *adapter) UpsertInvoiceLines(ctx context.Context, inputIn billing.Upsert
sql.ResolveWith(func(u *sql.UpdateSet) {
u.SetIgnore(billinginvoiceline.FieldCreatedAt)
})).
// TODO[OM-1416]: all nillable fileds must be listed explicitly
UpdateQuantity().
UpdateChildUniqueReferenceID().
Exec(ctx)
},
MarkDeleted: func(ctx context.Context, line *billing.Line) (*billing.Line, error) {
Expand Down Expand Up @@ -512,22 +508,22 @@ func (a *adapter) fetchLines(ctx context.Context, ns string, lineIDs []string) (
}

// Let's expand the line hierarchy so that we can have a full view of the invoice during the upcoming calculations
linesWithHierarchy, err := a.expandProgressiveLineHierarchy(ctx, ns, lines)
linesWithHierarchy, err := a.expandSplitLineHierarchy(ctx, ns, lines)
if err != nil {
return nil, err
}

return linesWithHierarchy, nil
}

func (a *adapter) GetLinesForSubscription(ctx context.Context, in billing.GetLinesForSubscriptionInput) ([]*billing.Line, error) {
func (a *adapter) GetLinesForSubscription(ctx context.Context, in billing.GetLinesForSubscriptionInput) ([]billing.LineOrHierarchy, error) {
if err := in.Validate(); err != nil {
return nil, billing.ValidationError{
Err: err,
}
}

return entutils.TransactingRepo(ctx, a, func(ctx context.Context, tx *adapter) ([]*billing.Line, error) {
return entutils.TransactingRepo(ctx, a, func(ctx context.Context, tx *adapter) ([]billing.LineOrHierarchy, error) {
query := tx.db.BillingInvoiceLine.Query().
Where(billinginvoiceline.Namespace(in.Namespace)).
Where(billinginvoiceline.SubscriptionID(in.SubscriptionID)).
Expand All @@ -540,9 +536,97 @@ func (a *adapter) GetLinesForSubscription(ctx context.Context, in billing.GetLin
return nil, fmt.Errorf("fetching lines: %w", err)
}

return tx.mapInvoiceLineFromDB(ctx, mapInvoiceLineFromDBInput{
lines, err := tx.mapInvoiceLineFromDB(ctx, mapInvoiceLineFromDBInput{
lines: dbLines,
includeDeleted: true,
})
if err != nil {
return nil, fmt.Errorf("mapping lines: %w", err)
}

dbGroups, err := tx.db.BillingInvoiceSplitLineGroup.Query().
Where(billinginvoicesplitlinegroup.Namespace(in.Namespace)).
Where(billinginvoicesplitlinegroup.SubscriptionID(in.SubscriptionID)).
WithBillingInvoiceLines(func(q *db.BillingInvoiceLineQuery) {
tx.expandLineItems(q)
q.WithBillingInvoice()
}).All(ctx)
if err != nil {
return nil, fmt.Errorf("fetching split line groups: %w", err)
}

groups, err := slicesx.MapWithErr(dbGroups, func(dbGroup *db.BillingInvoiceSplitLineGroup) (billing.SplitLineHierarchy, error) {
group, err := tx.mapSplitLineGroupFromDB(dbGroup)
if err != nil {
return billing.SplitLineHierarchy{}, err
}

lines, err := slicesx.MapWithErr(dbGroup.Edges.BillingInvoiceLines, func(dbLine *db.BillingInvoiceLine) (billing.LineWithInvoiceHeader, error) {
line, err := tx.mapInvoiceLineWithoutReferences(dbLine)
if err != nil {
return billing.LineWithInvoiceHeader{}, err
}

return billing.LineWithInvoiceHeader{
Line: &line,
Invoice: tx.mapInvoiceBaseFromDB(ctx, dbLine.Edges.BillingInvoice),
}, nil
})
if err != nil {
return billing.SplitLineHierarchy{}, err
}

return billing.SplitLineHierarchy{
Group: group,
Lines: lines,
}, nil
})
if err != nil {
return nil, fmt.Errorf("mapping groups: %w", err)
}

// Sanity check: let's make sure that there are no items with overlapping childUniqueReferenceID
groupUniqueReferenceIDs := lo.Map(
lo.Filter(
groups,
func(group billing.SplitLineHierarchy, _ int) bool {
return group.Group.UniqueReferenceID != nil
},
),
func(group billing.SplitLineHierarchy, _ int) string {
return lo.FromPtr(group.Group.UniqueReferenceID)
},
)

lineChildUniqueReferenceIDs := lo.Map(
lo.Filter( // Lines can have a nil childUniqueReferenceID, when they are part of a split line group (e.g. the group has the unique reference id)
lines,
func(line *billing.Line, _ int) bool {
return line.ChildUniqueReferenceID != nil
},
),
func(line *billing.Line, _ int) string {
return lo.FromPtr(line.ChildUniqueReferenceID)
},
)

overlappingChildUniqueReferenceIDs := lo.Intersect(groupUniqueReferenceIDs, lineChildUniqueReferenceIDs)

if len(overlappingChildUniqueReferenceIDs) > 0 {
return nil, fmt.Errorf("overlapping childUniqueReferenceID: %v", overlappingChildUniqueReferenceIDs)
}

// Let's map to the union type
out := make([]billing.LineOrHierarchy, 0, len(groups)+len(lines))

out = append(out, lo.Map(groups, func(h billing.SplitLineHierarchy, _ int) billing.LineOrHierarchy {
return billing.NewLineOrHierarchy(&h)
})...)

out = append(out, lo.Map(lines, func(line *billing.Line, _ int) billing.LineOrHierarchy {
return billing.NewLineOrHierarchy(line)
})...)

return out, nil
})
}
Loading
Loading