openmeter / billing /service /stdinvoice.go
Leon4gr45's picture
Upload folder using huggingface_hub (part 2)
5a22efd verified
Raw
History Blame Contribute Delete
5.92 kB
package billingservice
import (
"context"
"fmt"
"github.com/openmeterio/openmeter/openmeter/billing"
"github.com/openmeterio/openmeter/pkg/slicesx"
)
var _ billing.StandardInvoiceService = (*Service)(nil)
func (s *Service) UpdateStandardInvoice(ctx context.Context, input billing.UpdateStandardInvoiceInput) (billing.StandardInvoice, error) {
if err := input.Validate(); err != nil {
return billing.StandardInvoice{}, billing.ValidationError{
Err: err,
}
}
return s.executeTriggerOnInvoice(
ctx,
input.Invoice,
billing.TriggerUpdated,
ExecuteTriggerWithIncludeDeletedLines(input.IncludeDeletedLines),
ExecuteTriggerWithAllowInStates(billing.StandardInvoiceStatusDraftUpdating),
ExecuteTriggerWithEditCallback(func(ctx context.Context, sm *InvoiceStateMachine) error {
originalInvoice, err := sm.Invoice.Clone()
if err != nil {
return fmt.Errorf("cloning invoice before edit: %w", err)
}
if err := input.EditFn(&sm.Invoice); err != nil {
return fmt.Errorf("editing invoice: %w", err)
}
lineDiff, err := s.diffMutableInvoiceLines(ctx, originalInvoice, sm.Invoice, input.ChangeSource)
if err != nil {
return billing.ValidationError{
Err: fmt.Errorf("collecting mutable invoice line changes: %w", err),
}
}
switch input.ChangeSource {
case billing.ChangeSourceAPIRequest:
invoiceWithLineEngineChanges, err := s.applyAPIInvoiceLineEdits(ctx, applyAPIInvoiceLineEditsInput{
EditedInvoice: sm.Invoice,
LineDiff: lineDiff,
})
if err != nil {
return fmt.Errorf("applying API standard invoice line edits: %w", err)
}
standardInvoice, err := invoiceWithLineEngineChanges.AsInvoice().AsStandardInvoice()
if err != nil {
return fmt.Errorf("converting edited invoice to standard invoice: %w", err)
}
sm.Invoice = standardInvoice
case billing.ChangeSourceSystem:
// System-originated create and update changes are initiated by billing or
// charges, so there is no extra line-engine notification for them here.
// Deletes still need the legacy deleted-by-system notification because
// the charge line updater currently relies on it to clean up realizations.
if err := s.dispatchSystemStandardLineDeletions(ctx, sm.Invoice, lineDiff.Deleted); err != nil {
return fmt.Errorf("dispatching system standard line deletions: %w", err)
}
default:
return fmt.Errorf("unsupported change source: %s", input.ChangeSource)
}
if err := sm.Invoice.Validate(); err != nil {
return billing.ValidationError{
Err: err,
}
}
return nil
}),
)
}
func (s *Service) GetStandardInvoiceById(ctx context.Context, input billing.GetStandardInvoiceByIdInput) (billing.StandardInvoice, error) {
if err := input.Validate(); err != nil {
return billing.StandardInvoice{}, billing.ValidationError{
Err: err,
}
}
invoiceType, err := s.adapter.GetInvoiceType(ctx, input.Invoice)
if err != nil {
return billing.StandardInvoice{}, fmt.Errorf("getting invoice type: %w", err)
}
if invoiceType != billing.InvoiceTypeStandard {
return billing.StandardInvoice{}, billing.ValidationError{
Err: fmt.Errorf("invoice[%s] is not a standard invoice, cannot be fetched via the standard invoice service", input.Invoice.ID),
}
}
invoice, err := s.adapter.GetStandardInvoiceById(ctx, input)
if err != nil {
return billing.StandardInvoice{}, err
}
invoice, err = s.resolveWorkflowApps(ctx, invoice)
if err != nil {
return billing.StandardInvoice{}, fmt.Errorf("error resolving workflow apps for invoice [%s]: %w", input.Invoice.ID, err)
}
invoice, err = s.resolveStatusDetails(ctx, invoice)
if err != nil {
return billing.StandardInvoice{}, fmt.Errorf("error resolving status details for invoice [%s]: %w", input.Invoice.ID, err)
}
return invoice, nil
}
func (s *Service) ListStandardInvoices(ctx context.Context, input billing.ListStandardInvoicesInput) (billing.ListStandardInvoicesResponse, error) {
if err := input.Validate(); err != nil {
return billing.ListStandardInvoicesResponse{}, billing.ValidationError{
Err: err,
}
}
adapterInput := billing.ListInvoicesAdapterInput{
Page: input.Page,
Namespaces: input.Namespaces,
IDs: input.IDs,
Statuses: input.Statuses,
ExtendedStatuses: input.ExtendedStatuses,
HasAvailableAction: input.HasAvailableAction,
ExternalIDs: input.ExternalIDs,
DraftUntilLTE: input.DraftUntilLTE,
CollectionAtLTE: input.CollectionAtLTE,
IncludeDeleted: input.IncludeDeleted,
Expand: billing.InvoiceExpands{}.
SetOrUnsetIf(input.Expand.Has(billing.StandardInvoiceExpandLines), billing.InvoiceExpandLines).
SetOrUnsetIf(input.Expand.Has(billing.StandardInvoiceExpandDeletedLines), billing.InvoiceExpandDeletedLines),
OnlyStandard: true,
}
resp, err := s.adapter.ListInvoices(ctx, adapterInput)
if err != nil {
return billing.ListStandardInvoicesResponse{}, fmt.Errorf("listing invoices: %w", err)
}
stdInvoices, err := slicesx.MapWithErr(resp.Items, func(item billing.Invoice) (billing.StandardInvoice, error) {
return item.AsStandardInvoice()
})
if err != nil {
return billing.ListStandardInvoicesResponse{}, fmt.Errorf("mapping invoices to standard invoices: %w", err)
}
return billing.ListStandardInvoicesResponse{
Items: stdInvoices,
Page: resp.Page,
TotalCount: resp.TotalCount,
}, nil
}
func (s *Service) ListStandardInvoicesPendingAdvancement(ctx context.Context, input billing.ListStandardInvoicesPendingAdvancementInput) ([]billing.StandardInvoice, error) {
if err := input.Validate(); err != nil {
return nil, billing.ValidationError{Err: err}
}
invoices, err := s.adapter.ListStandardInvoicesPendingAdvancement(ctx, input)
if err != nil {
return nil, fmt.Errorf("listing standard invoices pending advancement: %w", err)
}
return invoices, nil
}