billing

package
v1.0.0-beta.214 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 25, 2025 License: Apache-2.0 Imports: 28 Imported by: 0

README

Billing

This package contains the implementation for the billing stack (invoicing, tax and payments).

The package has the following main entities:

BillingProfile

Captures all the billing details, two main information is stored inside:

  • The billing workflow (when to invoice, due periods etc)
  • References to the apps responsible for tax, invoicing and payments (Sandbox or Stripe for now)

Only one default billing profile can exist per namespace.

CustomerOverride

Contains customer specific overrides for billing pruposes. It can reference a billing profile other than the default (e.g. when different apps or lifecycle should be used) and allows to override the billing workflow.

Invoice

Invoices are used to store the data required by tax, invoicing and payment app's master copy at OpenMeter side.

Upon creation all the data required to generate invoices are snapshotted into the invoice entity, so that no updates to entities like Customer, BillingProfile, CustomerOverride change an invoice retrospectively.

Gathering invoices

There are two general kinds of invoices (Invoice.Status) gathering invoices are used to collect upcoming lines that are to be added to future invoices. gathering invocie's state never changes: when upcoming line items become due, they are just assigned to a new invoice, so that we clone the data required afresh.

Each customer can have one gathering issue per currency.

For example, if the customer has upcoming charges in USD and HUF, then there will be one gathering invoice for HUF and one for USD.

If there are no upcoming items, the gathering invoices are (soft) deleted.

Collection

TODO: document when implemented

Invoices

The invoices are governed by the invoice state machine.

Invoices are composed of lines. Each invoice can only have lines from the same currency.

The lines can be of different types:

  • Fee: one time charge
  • UsageBased: usage-based charge (can be used to charge additional usage-based prices without the product catalog features)

Each line has a period (start, end) and an invoiceAt property. The period specifies which period of time the line is referring to (in case of usage-based pricing, the underlying meter will be queried for this time-period). invoiceAt specifies the time when it is expected to create an invoice that contains this line. The invoice's collection settings can defer this.

Invoices are always created by collecting one or more line from the gathering invoices. The /v1/api/billing/invoices/lines endpoint can be used to create new future line items. A new invoice can be created any time. In such case, the gathering items to be invoiced (invoiceAt) are already added to the invoice. Any usage-based line, that we can bill early is also added to the invoice for the period between the period.start of the line and the time of invoice creation.

Line splitting

To achieve the behavior described above, we are using line splitting. By default we would have one line per billing period that would eventually be part of an invoice:

 period.start                                              period.end
Line1 [status=valid] |--------------------------------------------------------|

When the usage-based line can be billed mid-period, we split the line into two:

 period.start              asOf                              period.end
Line1 [status=split]         |--------------------------------------------------------|
SplitLine1 [status=valid]    |------------------|
SplitLine2 [status=valid]                       |-------------------------------------|

As visible:

  • Line1's status changes from valid to split: it will be ignored in any calculation, it becomes a grouping line between invoices
  • SplitLine1 is created with a period between period.start and asof (time of invoicing): it will be addedd to the freshly created invoice
  • SplitLine2 is created with a period between asof and period.end: it will be pushed to the gathering invoice

When creating a new invoice between asof and period.end the same logic continues, but without marking SplitLine2 split, instead the new line is added to the original line's parent line:

 period.start              asOf1          asof2                period.end
Line1 [status=split]         |--------------------------------------------------------|
SplitLine1 [status=valid]    |------------------|
SplitLine2 [status=valid]                       |---------------|
SplitLine3 [status=valid]                                       |---------------------|

This flattening approach allows us not to have to recursively traverse lines in the database.

Usage-based quantity

When a line is created for an invoice, the quantity of the underlying meter is captured into the line's qty field. This information is never updated, so late events will have to create new invoice lines when needed.

Detailed Lines

Each (valid) line can have one or more detailed lines (children). These lines represent the actual sub-charges that are caused by the parent line.

Example:

If a line has:

  • Usage of 200 units
  • Tiered pricing:
  • Tier1: 1 - 50 units cost flat $300
  • Tier2: 51 - 100 units cost flat $400
  • Tier3: 100 - 150 units cost flat $400 + $1/unit
  • Tier4: more than 150 units cost $15/unit

This would yield the following lines:

  • Line with quantity=200
    • Line quantity=1 per_unit_amount=300 total=300 (Tier1)
    • Line quantity=1 per_unit_amount=400 total=400 (Tier2)
    • Line quantity=1 per_unit_amount=400 total=400 (Tier3, flat component)
    • Line quantity=50 per_unit_amount=1 total=50 (Tier3, per unit price)
    • Line quantity=50 per_unit_amount=15 total=759 (Tier4)

Apps can choose to synchronize the original line (if the upstream system understands our pricing model) or can use the sublines to synchronize individual lines without having to understand billing details.

Detailed Lines vs Splitting

When we are dealing with a split line, the calculation of the quantity is by taking the meter's quantity for the whole line period ([parent.period.start, splitline.period.end]) and the amount before the period (parent.period.start, splitline.period.start).

When substracting the two we get the delta for the period (this gets the delta for all supported meter types except of Min and Avg).

We execute the pricing logic (e.g. tiered pricing) for the line qty, while considering the before usage, as it reflects the already billed for items.

Corner cases:

  • Graduating tiered prices cannot be billed mid-billing period (always arrears, as the calculation cannot be split into multiple items)
  • Min, Avg meters are always billed arrears as we cannot calculate the delta.
Detailed line persisting

In order for the calculation logic, to not to have to deal with the contents of the database, it is (mostly) the adapter layer's responsibility to understand what have changed and persist only that data to the database.

In practice the high level rules are the following (see adapter/invoicelinediff_test.go for examples):

  • If an entity has an ID then it will be updated
  • If an entity has changed compared to the database fetch, it will be updated
  • If a child line, discount gets removed, it will be removed from the database (in case of lines with all sub-entities)
  • If an entity doesn't have an ID a new entity will be generated by the database

For idempotent entity sources (detailed lines and discounts for now), we have also added a field called ChildUniqueReferenceID which can be used to detect entities serving the same purpose.

ChildUniqueReferenceID example

Let's say we have an usage-based line whose detailed lines are persisted to the database, but then we would want to change the quantity of the line.

First we load the existing detailed lines from the database, and save the database versions of the entities in memory.

We execute the calculation for the new quantity that yields new detailed lines without database IDs.

The entity's ChildrenWithIDReuse call can be used to facilitate the line reuse by assigning the known IDs to the yielded lines where the ChildUniqueReferenceID is set.

Then the adapter layer will use those IDs to make decisions if they want to persist or recreate the records.

We could do the same logic in the adapter layer, but this approach makes it more flexible on the calculation layer if we want to generate new lines or not. If this becomes a burden we can do the same matching logic as part of the upsert logic in adapter.

Subscription adapter

The subscription adapter is responsible for feeding the billing with line items during the subscription's lifecycle. The generation of items is event-driven, new items are yielded when:

  • A subscription is created
  • A new invoice is created
  • A subscription is modified
  • Upgrade/Downgrade is handled as a subscription create/cancel

Documentation

Index

Constants

View Source
const (
	EntityCustomerOverride = "BillingCustomerOverride"
	EntityCustomer         = "Customer"
	EntityDefaultProfile   = "DefaultBillingProfile"
	EntityInvoice          = "Invoice"
	EntityInvoiceLine      = "InvoiceLine"
)
View Source
const (
	CustomerUsageAttributionTypeVersion = "customer_usage_attribution.v1"
)
View Source
const (
	DefaultMeterResolution = time.Minute
)
View Source
const (
	EventSubsystem metadata.EventSubsystem = "billing"
)
View Source
const (
	ImmutableInvoiceHandlingNotSupportedErrorCode = "immutable_invoice_handling_not_supported"
)
View Source
const (
	// LineMaximumSpendReferenceID is a discount applied due to maximum spend.
	LineMaximumSpendReferenceID = "line_maximum_spend"
)

Variables

View Source
var (
	ErrDefaultProfileNotFound        = NewValidationError("default_profile_not_found", "default profile not found")
	ErrProfileNotFound               = NewValidationError("profile_not_found", "profile not found")
	ErrProfileAlreadyDeleted         = NewValidationError("profile_already_deleted", "profile already deleted")
	ErrProfileReferencedByOverrides  = NewValidationError("profile_referenced", "profile is referenced by customer overrides")
	ErrDefaultProfileCannotBeDeleted = NewValidationError("default_profile_cannot_be_deleted", "default profile cannot be deleted")
	ErrDefaultProfileCannotBeUnset   = NewValidationError("default_profile_cannot_be_unset", "default profile cannot be unset")

	ErrCustomerOverrideNotFound       = NewValidationError("customer_override_not_found", "customer override not found")
	ErrCustomerOverrideAlreadyDeleted = NewValidationError("customer_override_deleted", "customer override already deleted")
	ErrCustomerNotFound               = NewValidationError("customer_not_found", "customer not found")
	ErrCustomerDeleted                = NewValidationError("customer_deleted", "customer has been deleted")

	ErrFieldRequired             = NewValidationError("field_required", "field is required")
	ErrFieldMustBePositive       = NewValidationError("field_must_be_positive", "field must be positive")
	ErrFieldMustBePositiveOrZero = NewValidationError("field_must_be_positive_or_zero", "field must be positive or zero")

	ErrInvoiceCannotAdvance                  = NewValidationError("invoice_cannot_advance", "invoice cannot advance")
	ErrInvoiceCannotBeEdited                 = NewValidationError("invoice_cannot_be_edited", "invoice cannot be edited in the current state")
	ErrInvoiceActionNotAvailable             = NewValidationError("invoice_action_not_available", "invoice action not available")
	ErrInvoiceProgressiveBillingNotSupported = NewValidationError("invoice_progressive_billing_not_supported", "progressive billing is not supported")
	ErrInvoiceLinesNotBillable               = NewValidationError("invoice_lines_not_billable", "invoice lines are not billable")
	ErrInvoiceEmpty                          = NewValidationError("invoice_empty", "invoice is empty")
	ErrInvoiceNotFound                       = NewValidationError("invoice_not_found", "invoice not found")
	ErrInvoiceDeleteFailed                   = NewValidationError("invoice_delete_failed", "invoice delete failed")

	ErrInvoiceLineFeatureHasNoMeters                             = NewValidationError("invoice_line_feature_has_no_meters", "usage based invoice line: feature has no meters")
	ErrInvoiceLineVolumeSplitNotSupported                        = NewValidationError("invoice_line_graduated_split_not_supported", "graduated tiered pricing is not supported for split periods")
	ErrInvoiceLineNoTiers                                        = NewValidationError("invoice_line_no_tiers", "usage based invoice line: no tiers found")
	ErrInvoiceLineMissingOpenEndedTier                           = NewValidationError("invoice_line_missing_open_ended_tier", "usage based invoice line: missing open ended tier")
	ErrInvoiceLineDeleteInvalidStatus                            = NewValidationError("invoice_line_delete_invalid_status", "invoice line cannot be deleted in the current state (only valid lines can be deleted)")
	ErrInvoiceLineNoPeriodChangeForSplitLine                     = NewValidationError("invoice_line_no_period_change_for_split_line", "invoice line period cannot be changed for split lines")
	ErrInvoiceLineProgressiveBillingUsageDiscountUpdateForbidden = NewValidationError("invoice_line_progressive_billing_usage_discount_update_forbidden", "usage discount cannot be updated on a partially invoiced line")
	ErrInvoiceCreateNoLines                                      = NewValidationError("invoice_create_no_lines", "the new invoice would have no lines")
	ErrInvoiceCreateUBPLineCustomerHasNoSubjects                 = NewValidationError("invoice_create_ubp_line_customer_has_no_subjects", "creating an usage based line: customer has no subjects")
	ErrInvoiceCreateUBPLinePeriodIsEmpty                         = NewValidationError("invoice_create_ubp_line_period_is_empty", "creating an usage based line: truncated period is empty")
	ErrInvoiceLineCurrencyMismatch                               = NewValidationError("invoice_line_currency_mismatch", "invoice line currency mismatch")

	ErrInvoiceDiscountInvalidLineReference                  = NewValidationError("invoice_discount_invalid_line_reference", "invoice discount references non-existing line")
	ErrInvoiceDiscountNoWildcardDiscountOnGatheringInvoices = NewValidationError("invoice_discount_no_wildcard_discount_on_gathering_invoices", "wildcard discount on gathering invoices is not allowed")

	ErrNamespaceLocked = NewValidationError("namespace_locked", "namespace is locked")
)
View Source
var (
	GatheringInvoiceSequenceNumber = SequenceDefinition{
		Prefix:         "GATHER",
		SuffixTemplate: "{{.CustomerPrefix}}-{{.Currency}}-{{.NextSequenceNumber}}",
		Scope:          "invoices/gathering",
	}
	DraftInvoiceSequenceNumber = SequenceDefinition{
		Prefix:         "DRAFT",
		SuffixTemplate: "{{.CustomerPrefix}}-{{.NextSequenceNumber}}",
		Scope:          "invoices/draft",
	}
)
View Source
var CustomerOverrideExpandAll = CustomerOverrideExpand{
	Apps:     true,
	Customer: true,
}
View Source
var DefaultWorkflowConfig = WorkflowConfig{
	Collection: CollectionConfig{
		Alignment: AlignmentKindSubscription,
		Interval:  lo.Must(isodate.String("PT1H").Parse()),
	},
	Invoicing: InvoicingConfig{
		AutoAdvance:        true,
		DraftPeriod:        lo.Must(isodate.String("P0D").Parse()),
		DueAfter:           lo.Must(isodate.String("P30D").Parse()),
		ProgressiveBilling: true,
		DefaultTaxConfig:   nil,
	},
	Payment: PaymentConfig{
		CollectionMethod: CollectionMethodChargeAutomatically,
	},
	Tax: WorkflowTaxConfig{

		Enabled: true,

		Enforced: false,
	},
}
View Source
var InvoiceExpandAll = InvoiceExpand{
	Preceding:    true,
	Lines:        true,
	DeletedLines: false,
}
View Source
var ProfileExpandAll = ProfileExpand{
	Apps: true,
}

Functions

func EncodeValidationIssues

func EncodeValidationIssues[T error](err T) map[string]interface{}

func ReuseIDsFrom

func ReuseIDsFrom[T entityWithReusableIDs[T]](currentItems []T, dbExistingItems []T) ([]T, error)

ReuseIDsFrom reuses the IDs of the existing discounts by child unique reference ID.

func ValidationWithComponent

func ValidationWithComponent(component ComponentName, err error) error

ValidationWithComponent wraps an error with a component name, if error is nil, it returns nil This can be used to add context to an error when we are crossing service boundaries.

func ValidationWithFieldPrefix

func ValidationWithFieldPrefix(prefix string, err error) error

ValidationWithFieldPrefix wraps an error with a field prefix, if error is nil, it returns nil This can be used to delegate validation duties to a sub-entity. (e.g. lines don't need to know about the path in the invoice they are residing at)

func WithFeatureKey

func WithFeatureKey(fk string) usageBasedLineOption

Types

type AdapterGetProfileResponse

type AdapterGetProfileResponse struct {
	BaseProfile

	WorkflowConfigID string `json:"workflowConfigId"`
}

func (*AdapterGetProfileResponse) BaseProfileOrEmpty

func (r *AdapterGetProfileResponse) BaseProfileOrEmpty() *BaseProfile

type AdvanceInvoiceEvent

type AdvanceInvoiceEvent struct {
	Invoice    InvoiceID `json:"invoice"`
	CustomerID string    `json:"customer_id"`
}

func (AdvanceInvoiceEvent) EventMetadata

func (e AdvanceInvoiceEvent) EventMetadata() metadata.EventMetadata

func (AdvanceInvoiceEvent) EventName

func (e AdvanceInvoiceEvent) EventName() string

func (AdvanceInvoiceEvent) Validate

func (e AdvanceInvoiceEvent) Validate() error

type AdvanceInvoiceInput

type AdvanceInvoiceInput = InvoiceID

type AdvancementStrategy

type AdvancementStrategy string
const (
	// ForgegroundAdvancementStrategy is the strategy where the invoice is advanced immediately as part
	// of the same transaction. Should be used in workers as advancement might take long time and we don't want
	// to block a HTTP request for that long.
	ForegroundAdvancementStrategy AdvancementStrategy = "foreground"
	// QueuedAdvancementStrategy is the strategy where the invoice is advanced in a separate worker (billing-worker).
	// This is useful for cases where the advancement might take a long time and we don't want to block the current
	// HTTP request.
	QueuedAdvancementStrategy AdvancementStrategy = "queued"
)

func (AdvancementStrategy) Validate

func (s AdvancementStrategy) Validate() error

type AlignmentKind

type AlignmentKind string

AlignmentKind specifies what governs when an invoice is issued

const (
	// AlignmentKindSubscription specifies that the invoice is issued based on the subscription period (
	// e.g. whenever a due line item is added, it will trigger an invoice generation after the collection period)
	AlignmentKindSubscription AlignmentKind = "subscription"
)

func (AlignmentKind) Values

func (k AlignmentKind) Values() []string

type AmountLineDiscount

type AmountLineDiscount struct {
	LineDiscountBase `json:",inline"`

	Amount alpacadecimal.Decimal `json:"amount"`

	// RoundingAmount is a correction value, to ensure that if multiple discounts are applied,
	// then sum of discount amounts equals the total * sum(discount percentages).
	RoundingAmount alpacadecimal.Decimal `json:"roundingAmount"`
}

func (AmountLineDiscount) Clone

func (AmountLineDiscount) Equal

func (AmountLineDiscount) Validate

func (i AmountLineDiscount) Validate() error

type AmountLineDiscountManaged

type AmountLineDiscountManaged struct {
	models.ManagedModelWithID `json:",inline"`
	AmountLineDiscount        `json:",inline"`
}

func (AmountLineDiscountManaged) Clone

func (AmountLineDiscountManaged) ContentsEqual

func (AmountLineDiscountManaged) Equal

func (AmountLineDiscountManaged) GetManagedFieldsWithID

func (i AmountLineDiscountManaged) GetManagedFieldsWithID() models.ManagedModelWithID

func (AmountLineDiscountManaged) Validate

func (i AmountLineDiscountManaged) Validate() error

func (AmountLineDiscountManaged) WithManagedFieldsWithID

type AmountLineDiscountsManaged

type AmountLineDiscountsManaged []AmountLineDiscountManaged

func (AmountLineDiscountsManaged) Clone

func (AmountLineDiscountsManaged) GetByID

func (AmountLineDiscountsManaged) GetDiscountByChildUniqueReferenceID

func (i AmountLineDiscountsManaged) GetDiscountByChildUniqueReferenceID(childUniqueReferenceID string) (AmountLineDiscountManaged, bool)

func (AmountLineDiscountsManaged) Mutate

func (AmountLineDiscountsManaged) SumAmount

type AppError

type AppError struct {
	AppID   app.AppID
	AppType app.AppType
	Err     error
}

func (AppError) Error

func (e AppError) Error() string

type ApproveInvoiceInput

type ApproveInvoiceInput = InvoiceID

type AssociateLinesToInvoiceAdapterInput

type AssociateLinesToInvoiceAdapterInput struct {
	Invoice InvoiceID

	LineIDs []string
}

func (AssociateLinesToInvoiceAdapterInput) Validate

type AssociatedLineCountsAdapterInput

type AssociatedLineCountsAdapterInput = genericMultiInvoiceInput

type AssociatedLineCountsAdapterResponse

type AssociatedLineCountsAdapterResponse struct {
	Counts map[InvoiceID]int64
}

type BaseProfile

type BaseProfile struct {
	ID        string `json:"id"`
	Namespace string `json:"namespace"`

	Name        string  `json:"name"`
	Description *string `json:"description,omitempty"`

	CreatedAt time.Time  `json:"createdAt"`
	UpdatedAt time.Time  `json:"updatedAt"`
	DeletedAt *time.Time `json:"deletedAt,omitempty"`

	WorkflowConfig WorkflowConfig `json:"workflow"`

	Supplier SupplierContact `json:"supplier"`

	Default  bool     `json:"default"`
	Metadata Metadata `json:"metadata"`

	AppReferences *ProfileAppReferences `json:"appReferences,omitempty"`
}

func (BaseProfile) ProfileID

func (p BaseProfile) ProfileID() ProfileID

func (BaseProfile) Validate

func (p BaseProfile) Validate() error

type BulkAssignCustomersToProfileInput

type BulkAssignCustomersToProfileInput struct {
	ProfileID   ProfileID
	CustomerIDs []customer.CustomerID
}

func (BulkAssignCustomersToProfileInput) Validate

type CollectionConfig

type CollectionConfig struct {
	Alignment AlignmentKind  `json:"alignment"`
	Interval  isodate.Period `json:"period,omitempty"`
}

CollectionConfig groups fields related to item collection.

func (*CollectionConfig) Validate

func (c *CollectionConfig) Validate() error

type CollectionMethod

type CollectionMethod string
const (
	// CollectionMethodChargeAutomatically charges the customer automatically based on previously saved card data
	CollectionMethodChargeAutomatically CollectionMethod = "charge_automatically"
	// CollectionMethodSendInvoice sends an invoice to the customer along with the payment instructions/links
	CollectionMethodSendInvoice CollectionMethod = "send_invoice"
)

func (CollectionMethod) Values

func (c CollectionMethod) Values() []string

type CollectionOverrideConfig

type CollectionOverrideConfig struct {
	Alignment *AlignmentKind  `json:"alignment,omitempty"`
	Interval  *isodate.Period `json:"interval,omitempty"`
}

func (*CollectionOverrideConfig) Validate

func (c *CollectionOverrideConfig) Validate() error

type ComponentName

type ComponentName string

func AppTypeCapabilityToComponent

func AppTypeCapabilityToComponent(appType app.AppType, cap app.CapabilityType, op InvoiceOperation) ComponentName

type ConfigService

type ConfigService interface {
	GetAdvancementStrategy() AdvancementStrategy
	WithAdvancementStrategy(strategy AdvancementStrategy) Service
	WithLockedNamespaces(namespaces []string) Service
}

type CreateCustomerOverrideAdapterInput

type CreateCustomerOverrideAdapterInput = UpdateCustomerOverrideAdapterInput

type CreateInvoiceAdapterInput

type CreateInvoiceAdapterInput struct {
	Namespace string
	Customer  customer.Customer
	Profile   Profile
	Number    string
	Currency  currencyx.Code
	Status    InvoiceStatus
	Metadata  map[string]string
	IssuedAt  time.Time

	Type        InvoiceType
	Description *string
	DueAt       *time.Time

	Totals Totals
}

func (CreateInvoiceAdapterInput) Validate

func (c CreateInvoiceAdapterInput) Validate() error

type CreateInvoiceAdapterRespone

type CreateInvoiceAdapterRespone = Invoice

type CreatePendingInvoiceLinesInput

type CreatePendingInvoiceLinesInput struct {
	Customer customer.CustomerID
	Currency currencyx.Code

	Lines []*Line
}

func (CreatePendingInvoiceLinesInput) Validate

type CreatePendingInvoiceLinesResult

type CreatePendingInvoiceLinesResult struct {
	Lines        []*Line
	Invoice      Invoice
	IsInvoiceNew bool
}

type CreateProfileAppsInput

type CreateProfileAppsInput = ProfileAppReferences

type CreateProfileInput

type CreateProfileInput struct {
	Namespace   string            `json:"namespace"`
	Name        string            `json:"name"`
	Description *string           `json:"description,omitempty"`
	Metadata    map[string]string `json:"metadata"`
	Supplier    SupplierContact   `json:"supplier"`
	Default     bool              `json:"default"`

	WorkflowConfig WorkflowConfig         `json:"workflowConfig"`
	Apps           CreateProfileAppsInput `json:"apps"`
}

func (CreateProfileInput) Validate

func (i CreateProfileInput) Validate() error

type CreateSplitLineGroupAdapterInput

type CreateSplitLineGroupAdapterInput = SplitLineGroupCreate

Adapter

type CreateWorkflowConfigInput

type CreateWorkflowConfigInput struct {
	WorkflowConfig
}

type CustomerMetadata

type CustomerMetadata struct {
	Name string `json:"name"`
}

type CustomerOverride

type CustomerOverride struct {
	Namespace string `json:"namespace"`
	ID        string `json:"id"`

	CreatedAt time.Time  `json:"createdAt"`
	UpdatedAt time.Time  `json:"updatedAt"`
	DeletedAt *time.Time `json:"deletedAt,omitempty"`

	CustomerID string   `json:"customerID"`
	Profile    *Profile `json:"billingProfile,omitempty"`

	Collection CollectionOverrideConfig `json:"collection"`
	Invoicing  InvoicingOverrideConfig  `json:"invoicing"`
	Payment    PaymentOverrideConfig    `json:"payment"`
}

func (CustomerOverride) Validate

func (c CustomerOverride) Validate() error

type CustomerOverrideAdapter

type CustomerOverrideAdapter interface {
	CreateCustomerOverride(ctx context.Context, input UpdateCustomerOverrideAdapterInput) (*CustomerOverride, error)
	GetCustomerOverride(ctx context.Context, input GetCustomerOverrideAdapterInput) (*CustomerOverride, error)
	UpdateCustomerOverride(ctx context.Context, input UpdateCustomerOverrideAdapterInput) (*CustomerOverride, error)
	DeleteCustomerOverride(ctx context.Context, input DeleteCustomerOverrideInput) error
	ListCustomerOverrides(ctx context.Context, input ListCustomerOverridesInput) (ListCustomerOverridesAdapterResult, error)

	BulkAssignCustomersToProfile(ctx context.Context, input BulkAssignCustomersToProfileInput) error

	GetCustomerOverrideReferencingProfile(ctx context.Context, input HasCustomerOverrideReferencingProfileAdapterInput) ([]customer.CustomerID, error)
}

type CustomerOverrideExpand

type CustomerOverrideExpand struct {
	// Apps specifies if the merged profile should include the apps
	Apps bool `json:"apps,omitempty"`

	// Customer specifies if the customer should be included in the response
	Customer bool `json:"customer,omitempty"`
}

type CustomerOverrideOrderBy

type CustomerOverrideOrderBy string
const (
	CustomerOverrideOrderByCustomerID           CustomerOverrideOrderBy = "customerId"
	CustomerOverrideOrderByCustomerName         CustomerOverrideOrderBy = "customerName"
	CustomerOverrideOrderByCustomerKey          CustomerOverrideOrderBy = "customerKey"
	CustomerOverrideOrderByCustomerPrimaryEmail CustomerOverrideOrderBy = "customerPrimaryEmail"
	CustomerOverrideOrderByCustomerCreatedAt    CustomerOverrideOrderBy = "customerCreatedAt"

	DefaultCustomerOverrideOrderBy CustomerOverrideOrderBy = CustomerOverrideOrderByCustomerID
)

func (CustomerOverrideOrderBy) Validate

func (o CustomerOverrideOrderBy) Validate() error

type CustomerOverrideService

type CustomerOverrideService interface {
	UpsertCustomerOverride(ctx context.Context, input UpsertCustomerOverrideInput) (CustomerOverrideWithDetails, error)
	DeleteCustomerOverride(ctx context.Context, input DeleteCustomerOverrideInput) error

	GetCustomerOverride(ctx context.Context, input GetCustomerOverrideInput) (CustomerOverrideWithDetails, error)
	ListCustomerOverrides(ctx context.Context, input ListCustomerOverridesInput) (ListCustomerOverridesResult, error)
}

type CustomerOverrideWithAdapterProfile

type CustomerOverrideWithAdapterProfile struct {
	CustomerOverride `json:",inline"`

	DefaultProfile *AdapterGetProfileResponse `json:"billingProfile,omitempty"`
}

type CustomerOverrideWithCustomerID

type CustomerOverrideWithCustomerID struct {
	*CustomerOverride `json:",inline"`

	CustomerID customer.CustomerID `json:"customerID,omitempty"`
}

type CustomerOverrideWithDetails

type CustomerOverrideWithDetails struct {
	CustomerOverride *CustomerOverride `json:",inline"`
	MergedProfile    Profile           `json:"mergedProfile,omitempty"`

	// Expanded fields
	Expand   CustomerOverrideExpand `json:"expand,omitempty"`
	Customer *customer.Customer     `json:"customer,omitempty"`
}

type CustomerSynchronizationAdapter

type CustomerSynchronizationAdapter interface {
	// UpsertCustomerOverride upserts a customer override ignoring the transactional context, the override
	// will be empty.
	UpsertCustomerOverride(ctx context.Context, input UpsertCustomerOverrideAdapterInput) error
	LockCustomerForUpdate(ctx context.Context, input LockCustomerForUpdateAdapterInput) error
}

type CustomerUsageAttribution

type CustomerUsageAttribution = customer.CustomerUsageAttribution

type DeleteCustomerOverrideInput

type DeleteCustomerOverrideInput struct {
	Customer customer.CustomerID
}

func (DeleteCustomerOverrideInput) Validate

func (d DeleteCustomerOverrideInput) Validate() error

type DeleteGatheringInvoicesInput

type DeleteGatheringInvoicesInput = genericMultiInvoiceInput

type DeleteInvoiceInput

type DeleteInvoiceInput = InvoiceID

type DeleteInvoiceLineInput

type DeleteInvoiceLineInput = LineID

type DeleteProfileInput

type DeleteProfileInput = ProfileID

type DeleteSplitLineGroupInput

type DeleteSplitLineGroupInput = models.NamespacedID

Adapter

type DiscountReason

type DiscountReason struct {
	// contains filtered or unexported fields
}

func (*DiscountReason) AsMaximumSpend

func (d *DiscountReason) AsMaximumSpend() (MaximumSpendDiscount, error)

func (*DiscountReason) AsRatecardPercentage

func (d *DiscountReason) AsRatecardPercentage() (PercentageDiscount, error)

func (*DiscountReason) AsRatecardUsage

func (d *DiscountReason) AsRatecardUsage() (UsageDiscount, error)

func (*DiscountReason) MarshalJSON

func (d *DiscountReason) MarshalJSON() ([]byte, error)

func (*DiscountReason) Type

func (*DiscountReason) UnmarshalJSON

func (d *DiscountReason) UnmarshalJSON(bytes []byte) error

func (*DiscountReason) Validate

func (d *DiscountReason) Validate() error

type DiscountReasonType

type DiscountReasonType string
const (
	MaximumSpendDiscountReason       DiscountReasonType = "maximum_spend"
	RatecardPercentageDiscountReason DiscountReasonType = "ratecard_percentage"
	RatecardUsageDiscountReason      DiscountReasonType = "ratecard_usage"
)

func (DiscountReasonType) Values

func (DiscountReasonType) Values() []string

type Discounts

type Discounts struct {
	Percentage *PercentageDiscount `json:"percentage"`
	Usage      *UsageDiscount      `json:"usage"`
}

func (Discounts) Clone

func (d Discounts) Clone() Discounts

func (Discounts) IsEmpty

func (d Discounts) IsEmpty() bool

func (Discounts) ValidateForPrice

func (d Discounts) ValidateForPrice(price *productcatalog.Price) error

type EventInvoice

type EventInvoice struct {
	Invoice Invoice     `json:"invoice"`
	Apps    InvoiceApps `json:"apps,omitempty"`
}

func NewEventInvoice

func NewEventInvoice(invoice Invoice) (EventInvoice, error)

func (EventInvoice) Validate

func (e EventInvoice) Validate() error

type ExternalIDType

type ExternalIDType string
const (
	InvoicingExternalIDType ExternalIDType = "invoicing"
	PaymentExternalIDType   ExternalIDType = "payment"
	TaxExternalIDType       ExternalIDType = "tax"
)

func (ExternalIDType) Validate

func (t ExternalIDType) Validate() error

type FinalizeInvoiceResult

type FinalizeInvoiceResult struct {
	// contains filtered or unexported fields
}

func NewFinalizeInvoiceResult

func NewFinalizeInvoiceResult() *FinalizeInvoiceResult

func (*FinalizeInvoiceResult) GetInvoiceNumber

func (u *FinalizeInvoiceResult) GetInvoiceNumber() (string, bool)

func (*FinalizeInvoiceResult) GetPaymentExternalID

func (f *FinalizeInvoiceResult) GetPaymentExternalID() (string, bool)

func (*FinalizeInvoiceResult) GetSentToCustomerAt

func (f *FinalizeInvoiceResult) GetSentToCustomerAt() (time.Time, bool)

func (*FinalizeInvoiceResult) MergeIntoInvoice

func (f *FinalizeInvoiceResult) MergeIntoInvoice(invoice *Invoice) error

func (*FinalizeInvoiceResult) SetInvoiceNumber

func (f *FinalizeInvoiceResult) SetInvoiceNumber(invoiceNumber string) *FinalizeInvoiceResult

func (*FinalizeInvoiceResult) SetPaymentExternalID

func (f *FinalizeInvoiceResult) SetPaymentExternalID(paymentExternalID string) *FinalizeInvoiceResult

func (*FinalizeInvoiceResult) SetSentToCustomerAt

func (f *FinalizeInvoiceResult) SetSentToCustomerAt(sentToCustomerAt time.Time) *FinalizeInvoiceResult

type FlatFeeCategory

type FlatFeeCategory string
const (
	// FlatFeeCategoryRegular is a regular flat fee, that is based on the usage or a subscription.
	FlatFeeCategoryRegular FlatFeeCategory = "regular"
	// FlatFeeCategoryCommitment is a flat fee that is based on a commitment such as min spend.
	FlatFeeCategoryCommitment FlatFeeCategory = "commitment"
)

func (FlatFeeCategory) Values

func (FlatFeeCategory) Values() []string

type FlatFeeLine

type FlatFeeLine struct {
	ConfigID      string                         `json:"configId"`
	PerUnitAmount alpacadecimal.Decimal          `json:"perUnitAmount"`
	PaymentTerm   productcatalog.PaymentTermType `json:"paymentTerm"`
	Category      FlatFeeCategory                `json:"category"`

	Quantity alpacadecimal.Decimal `json:"quantity"`
	// Index is the index of the line in the invoice. Only valid for detailed lines. Used for sorting the lines in the invoice.
	Index *int `json:"index,omitempty"`
}

func (FlatFeeLine) Clone

func (i FlatFeeLine) Clone() *FlatFeeLine

func (FlatFeeLine) Equal

func (i FlatFeeLine) Equal(other *FlatFeeLine) bool

type ForEachChildInput

type ForEachChildInput struct {
	PeriodEndLTE time.Time
	Callback     func(child LineWithInvoiceHeader) error
}

type GetCustomerOverrideAdapterInput

type GetCustomerOverrideAdapterInput struct {
	Customer customer.CustomerID

	IncludeDeleted bool
}

func (GetCustomerOverrideAdapterInput) Validate

type GetCustomerOverrideInput

type GetCustomerOverrideInput struct {
	Customer customer.CustomerID    `json:"customerID"`
	Expand   CustomerOverrideExpand `json:"expand,omitempty"`
}

func (GetCustomerOverrideInput) Validate

func (g GetCustomerOverrideInput) Validate() error

type GetDefaultProfileInput

type GetDefaultProfileInput struct {
	Namespace string
}

func (GetDefaultProfileInput) Validate

func (i GetDefaultProfileInput) Validate() error

type GetInvoiceByIdInput

type GetInvoiceByIdInput struct {
	Invoice InvoiceID
	Expand  InvoiceExpand
}

func (GetInvoiceByIdInput) Validate

func (i GetInvoiceByIdInput) Validate() error

type GetInvoiceLineAdapterInput

type GetInvoiceLineAdapterInput = LineID

type GetInvoiceLineInput

type GetInvoiceLineInput = LineID

type GetInvoiceLineOwnershipAdapterInput

type GetInvoiceLineOwnershipAdapterInput = LineID

type GetInvoiceOwnershipAdapterInput

type GetInvoiceOwnershipAdapterInput = InvoiceID

type GetLinesForSubscriptionInput

type GetLinesForSubscriptionInput struct {
	Namespace      string
	SubscriptionID string
}

func (GetLinesForSubscriptionInput) Validate

func (i GetLinesForSubscriptionInput) Validate() error

type GetOwnershipAdapterResponse

type GetOwnershipAdapterResponse struct {
	Namespace  string
	InvoiceID  string
	CustomerID string
}

type GetProfileInput

type GetProfileInput struct {
	Profile ProfileID
	Expand  ProfileExpand
}

func (GetProfileInput) Validate

func (i GetProfileInput) Validate() error

type GetProfileWithCustomerOverrideInput

type GetProfileWithCustomerOverrideInput struct {
	Customer customer.CustomerID
}

func (GetProfileWithCustomerOverrideInput) Validate

type GetSplitLineGroupInput

type GetSplitLineGroupInput = models.NamespacedID

Adapter

type GetUnpinnedCustomerIDsWithPaidSubscriptionInput

type GetUnpinnedCustomerIDsWithPaidSubscriptionInput struct {
	Namespace string
}

func (GetUnpinnedCustomerIDsWithPaidSubscriptionInput) Validate

type GranularityResolution

type GranularityResolution string
const (
	// GranularityResolutionDay provides line items for metered data per day
	GranularityResolutionDay GranularityResolution = "day"
	// GranularityResolutionPeriod provides one line item per period
	GranularityResolutionPeriod GranularityResolution = "period"
)

func (GranularityResolution) Values

func (r GranularityResolution) Values() []string

type HasCustomerOverrideReferencingProfileAdapterInput

type HasCustomerOverrideReferencingProfileAdapterInput = ProfileID

type Invoice

type Invoice struct {
	InvoiceBase `json:",inline"`

	// Entities external to the invoice itself
	Lines            LineChildren     `json:"lines,omitempty"`
	ValidationIssues ValidationIssues `json:"validationIssues,omitempty"`

	Totals Totals `json:"totals"`

	// private fields required by the service
	ExpandedFields InvoiceExpand `json:"-"`
}

func (Invoice) Clone

func (i Invoice) Clone() Invoice

func (Invoice) CustomerID

func (i Invoice) CustomerID() customer.CustomerID

func (*Invoice) FlattenLinesByID

func (i *Invoice) FlattenLinesByID() map[string]*Line

func (*Invoice) GetLeafLinesWithConsolidatedTaxBehavior

func (i *Invoice) GetLeafLinesWithConsolidatedTaxBehavior() []*Line

GetLeafLinesWithConsolidatedTaxBehavior returns the leaf lines with the tax behavior set to the invoice's tax behavior unless the line already has a tax behavior set.

func (*Invoice) HasCriticalValidationIssues

func (i *Invoice) HasCriticalValidationIssues() bool

func (Invoice) InvoiceID

func (i Invoice) InvoiceID() InvoiceID

func (*Invoice) MergeValidationIssues

func (i *Invoice) MergeValidationIssues(errIn error, reportingComponent ComponentName) error

func (Invoice) RemoveCircularReferences

func (i Invoice) RemoveCircularReferences() Invoice

func (Invoice) RemoveMetaForCompare

func (i Invoice) RemoveMetaForCompare() Invoice

RemoveMetaForCompare returns a copy of the invoice without the fields that are not relevant for higher level tests that compare invoices. What gets removed: - Line's DB state - Line's dependencies are marked as resolved - Parent pointers are removed

func (*Invoice) SortLines

func (i *Invoice) SortLines()

func (Invoice) Validate

func (i Invoice) Validate() error

type InvoiceAppAdapter

type InvoiceAppAdapter interface {
	UpdateInvoiceFields(ctx context.Context, input UpdateInvoiceFieldsInput) error
}

type InvoiceAppService

type InvoiceAppService interface {
	// TriggerInvoice triggers the invoice state machine to start processing the invoice
	TriggerInvoice(ctx context.Context, input InvoiceTriggerServiceInput) error

	// UpdateInvoiceFields updates the fields of an invoice which are not managed by the state machine
	// These are usually metadata fields settable after the invoice has been finalized
	UpdateInvoiceFields(ctx context.Context, input UpdateInvoiceFieldsInput) error

	// Async sync support
	SyncDraftInvoice(ctx context.Context, input SyncDraftInvoiceInput) (Invoice, error)
	SyncIssuingInvoice(ctx context.Context, input SyncIssuingInvoiceInput) (Invoice, error)
}

type InvoiceApps

type InvoiceApps struct {
	Tax       app.EventApp `json:"tax"`
	Payment   app.EventApp `json:"payment"`
	Invoicing app.EventApp `json:"invoicing"`
}

func (InvoiceApps) Validate

func (a InvoiceApps) Validate() error

type InvoiceAvailableActionDetails

type InvoiceAvailableActionDetails struct {
	ResultingState InvoiceStatus `json:"resultingState"`
}

type InvoiceAvailableActionInvoiceDetails

type InvoiceAvailableActionInvoiceDetails struct{}

type InvoiceAvailableActions

type InvoiceAvailableActions struct {
	Advance            *InvoiceAvailableActionDetails `json:"advance,omitempty"`
	Approve            *InvoiceAvailableActionDetails `json:"approve,omitempty"`
	Delete             *InvoiceAvailableActionDetails `json:"delete,omitempty"`
	Retry              *InvoiceAvailableActionDetails `json:"retry,omitempty"`
	Void               *InvoiceAvailableActionDetails `json:"void,omitempty"`
	SnapshotQuantities *InvoiceAvailableActionDetails `json:"snapshotQuantities,omitempty"`

	Invoice *InvoiceAvailableActionInvoiceDetails `json:"invoice,omitempty"`
}

type InvoiceAvailableActionsFilter

type InvoiceAvailableActionsFilter string
const (
	InvoiceAvailableActionsFilterAdvance InvoiceAvailableActionsFilter = "advance"
	InvoiceAvailableActionsFilterApprove InvoiceAvailableActionsFilter = "approve"
)

func (InvoiceAvailableActionsFilter) Validate

func (f InvoiceAvailableActionsFilter) Validate() error

func (InvoiceAvailableActionsFilter) Values

type InvoiceBase

type InvoiceBase struct {
	Namespace string `json:"namespace"`
	ID        string `json:"id"`

	Number      string  `json:"number"`
	Description *string `json:"description,omitempty"`

	Type InvoiceType `json:"type"`

	Metadata map[string]string `json:"metadata"`

	Currency      currencyx.Code       `json:"currency,omitempty"`
	Status        InvoiceStatus        `json:"status"`
	StatusDetails InvoiceStatusDetails `json:"statusDetail,omitempty"`

	Period *Period `json:"period,omitempty"`

	DueAt *time.Time `json:"dueDate,omitempty"`

	CreatedAt            time.Time  `json:"createdAt"`
	UpdatedAt            time.Time  `json:"updatedAt"`
	VoidedAt             *time.Time `json:"voidedAt,omitempty"`
	DraftUntil           *time.Time `json:"draftUntil,omitempty"`
	IssuedAt             *time.Time `json:"issuedAt,omitempty"`
	DeletedAt            *time.Time `json:"deletedAt,omitempty"`
	SentToCustomerAt     *time.Time `json:"sentToCustomerAt,omitempty"`
	QuantitySnapshotedAt *time.Time `json:"quantitySnapshotedAt,omitempty"`

	CollectionAt *time.Time `json:"collectionAt,omitempty"`

	// Customer is either a snapshot of the contact information of the customer at the time of invoice being sent
	// or the data from the customer entity (draft state)
	// This is required so that we are not modifying the invoice after it has been sent to the customer.
	Customer InvoiceCustomer `json:"customer"`
	Supplier SupplierContact `json:"supplier"`
	Workflow InvoiceWorkflow `json:"workflow,omitempty"`

	ExternalIDs InvoiceExternalIDs `json:"externalIds,omitempty"`
}

func (InvoiceBase) Validate

func (i InvoiceBase) Validate() error

type InvoiceCreatedEvent

type InvoiceCreatedEvent struct {
	EventInvoice `json:",inline"`
}

func NewInvoiceCreatedEvent

func NewInvoiceCreatedEvent(invoice Invoice) (InvoiceCreatedEvent, error)

func (InvoiceCreatedEvent) EventMetadata

func (e InvoiceCreatedEvent) EventMetadata() metadata.EventMetadata

func (InvoiceCreatedEvent) EventName

func (e InvoiceCreatedEvent) EventName() string

func (InvoiceCreatedEvent) Validate

func (e InvoiceCreatedEvent) Validate() error

type InvoiceCustomer

type InvoiceCustomer struct {
	CustomerID string `json:"customerId,omitempty"`

	Name             string                   `json:"name"`
	BillingAddress   *models.Address          `json:"billingAddress,omitempty"`
	UsageAttribution CustomerUsageAttribution `json:"usageAttribution"`
}

func (*InvoiceCustomer) Validate

func (i *InvoiceCustomer) Validate() error

type InvoiceExpand

type InvoiceExpand struct {
	Preceding bool

	Lines        bool
	DeletedLines bool

	// RecalculateGatheringInvoice is used to calculate the totals and status details of the invoice when gathering,
	// this is temporary until we implement the full progressive billing stack, including gathering invoice recalculations.
	RecalculateGatheringInvoice bool
}

func (InvoiceExpand) SetDeletedLines

func (e InvoiceExpand) SetDeletedLines(v bool) InvoiceExpand

func (InvoiceExpand) SetLines

func (e InvoiceExpand) SetLines(v bool) InvoiceExpand

func (InvoiceExpand) SetRecalculateGatheringInvoice

func (e InvoiceExpand) SetRecalculateGatheringInvoice(v bool) InvoiceExpand

func (InvoiceExpand) Validate

func (e InvoiceExpand) Validate() error

type InvoiceExternalIDs

type InvoiceExternalIDs struct {
	Invoicing string `json:"invoicing,omitempty"`
	Payment   string `json:"payment,omitempty"`
}

func (*InvoiceExternalIDs) GetInvoicingOrEmpty

func (i *InvoiceExternalIDs) GetInvoicingOrEmpty() string

type InvoiceID

type InvoiceID models.NamespacedID

func (InvoiceID) Validate

func (i InvoiceID) Validate() error

type InvoiceLineAdapter

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) ([]LineOrHierarchy, error)
}

type InvoiceLineManagedBy

type InvoiceLineManagedBy string
const (
	// SubscriptionManagedLine is a line that is managed by a subscription.
	SubscriptionManagedLine InvoiceLineManagedBy = "subscription"
	// SystemManagedLine is a line that is managed by the system (non editable, detailed lines)
	SystemManagedLine InvoiceLineManagedBy = "system"
	// ManuallyManagedLine is a line that is managed manually (e.g. overridden by our API users)
	ManuallyManagedLine InvoiceLineManagedBy = "manual"
)

func (InvoiceLineManagedBy) Values

func (InvoiceLineManagedBy) Values() []string

type InvoiceLineService

type InvoiceLineService interface {
	// CreatePendingInvoiceLines creates pending invoice lines for a customer, if the lines are zero valued, the response is nil
	CreatePendingInvoiceLines(ctx context.Context, input CreatePendingInvoiceLinesInput) (*CreatePendingInvoiceLinesResult, error)
	GetLinesForSubscription(ctx context.Context, input GetLinesForSubscriptionInput) ([]LineOrHierarchy, error)
	// SnapshotLineQuantity returns an updated line with the quantity snapshoted from meters
	// the invoice is used as contextual information to the call.
	SnapshotLineQuantity(ctx context.Context, input SnapshotLineQuantityInput) (*Line, error)
}

type InvoiceLineStatus

type InvoiceLineStatus string
const (
	// InvoiceLineStatusValid is a valid invoice line.
	InvoiceLineStatusValid InvoiceLineStatus = "valid"
	// InvoiceLineStatusDetailed is a detailed invoice line.
	InvoiceLineStatusDetailed InvoiceLineStatus = "detailed"
)

func (InvoiceLineStatus) Values

func (InvoiceLineStatus) Values() []string

type InvoiceLineType

type InvoiceLineType string
const (
	// InvoiceLineTypeFee is an item that represents a single charge without meter backing.
	InvoiceLineTypeFee InvoiceLineType = "flat_fee"
	// InvoiceLineTypeUsageBased is an item that is added to the invoice and is usage based.
	InvoiceLineTypeUsageBased InvoiceLineType = "usage_based"
)

func (InvoiceLineType) Values

func (InvoiceLineType) Values() []string

type InvoiceOperation

type InvoiceOperation string
const (
	InvoiceOpValidate        InvoiceOperation = "validate"
	InvoiceOpSync            InvoiceOperation = "sync"
	InvoiceOpDelete          InvoiceOperation = "delete"
	InvoiceOpFinalize        InvoiceOperation = "finalize"
	InvoiceOpInitiatePayment InvoiceOperation = "initiate_payment"

	InvoiceOpPostAdvanceHook InvoiceOperation = "post_advance_hook"
	InvoiceOpTriggerInvoice  InvoiceOperation = "trigger_invoice"
)

func (InvoiceOperation) Validate

func (o InvoiceOperation) Validate() error

type InvoicePendingLinesInput

type InvoicePendingLinesInput struct {
	Customer customer.CustomerID

	IncludePendingLines mo.Option[[]string]
	AsOf                *time.Time

	// ProgressiveBillingOverride allows to override the progressive billing setting of the customer.
	// This is used to make sure that system collection does not use progressive billing.
	ProgressiveBillingOverride *bool
}

func (InvoicePendingLinesInput) Validate

func (i InvoicePendingLinesInput) Validate() error

type InvoiceService

type InvoiceService interface {
	ListInvoices(ctx context.Context, input ListInvoicesInput) (ListInvoicesResponse, error)
	GetInvoiceByID(ctx context.Context, input GetInvoiceByIdInput) (Invoice, error)
	InvoicePendingLines(ctx context.Context, input InvoicePendingLinesInput) ([]Invoice, error)
	// AdvanceInvoice advances the invoice to the next stage, the advancement is stopped until:
	// - an error is occurred
	// - the invoice is in a state that cannot be advanced (e.g. waiting for draft period to expire)
	// - the invoice is advanced to the final state
	AdvanceInvoice(ctx context.Context, input AdvanceInvoiceInput) (Invoice, error)
	SnapshotQuantities(ctx context.Context, input SnapshotQuantitiesInput) (Invoice, error)
	ApproveInvoice(ctx context.Context, input ApproveInvoiceInput) (Invoice, error)
	RetryInvoice(ctx context.Context, input RetryInvoiceInput) (Invoice, error)
	DeleteInvoice(ctx context.Context, input DeleteInvoiceInput) error
	// UpdateInvoice updates an invoice as a whole
	UpdateInvoice(ctx context.Context, input UpdateInvoiceInput) (Invoice, error)

	// SimulateInvoice generates an invoice based on the provided input, but does not persist it
	// can be used to execute the invoice generation logic without actually creating an invoice in the database
	SimulateInvoice(ctx context.Context, input SimulateInvoiceInput) (Invoice, error)
	// UpsertValidationIssues upserts validation errors to the invoice bypassing the state machine, can only be
	// used on invoices in immutable state.
	UpsertValidationIssues(ctx context.Context, input UpsertValidationIssuesInput) error

	// RecalculateGatheringInvoices recalculates the gathering invoices for a given customer, updating the
	// collection_at attribute and deleting the gathering invoice if it has no lines.
	RecalculateGatheringInvoices(ctx context.Context, input RecalculateGatheringInvoicesInput) error
}

type InvoiceSplitLineGroupAdapter

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 InvoiceStatus

type InvoiceStatus string
const (
	// InvoiceStatusGathering is the status of an invoice that is gathering the items to be invoiced.
	InvoiceStatusGathering InvoiceStatus = "gathering"

	InvoiceStatusDraftCreated InvoiceStatus = "draft.created"
	// InvoiceStatusDraftWaitingForCollection is the status of an invoice that is waiting for the collection to be possible (e.g. collection period has passed)
	InvoiceStatusDraftWaitingForCollection InvoiceStatus = "draft.waiting_for_collection"
	// InvoiceStatusDraftCollecting is the status of an invoice that is collecting the items to be invoiced.
	InvoiceStatusDraftCollecting           InvoiceStatus = "draft.collecting"
	InvoiceStatusDraftUpdating             InvoiceStatus = "draft.updating"
	InvoiceStatusDraftManualApprovalNeeded InvoiceStatus = "draft.manual_approval_needed"
	InvoiceStatusDraftValidating           InvoiceStatus = "draft.validating"
	InvoiceStatusDraftInvalid              InvoiceStatus = "draft.invalid"
	InvoiceStatusDraftSyncing              InvoiceStatus = "draft.syncing"
	InvoiceStatusDraftSyncFailed           InvoiceStatus = "draft.sync_failed"
	InvoiceStatusDraftWaitingAutoApproval  InvoiceStatus = "draft.waiting_auto_approval"
	InvoiceStatusDraftReadyToIssue         InvoiceStatus = "draft.ready_to_issue"

	InvoiceStatusDeleteInProgress InvoiceStatus = "delete.in_progress"
	InvoiceStatusDeleteSyncing    InvoiceStatus = "delete.syncing"
	InvoiceStatusDeleteFailed     InvoiceStatus = "delete.failed"
	InvoiceStatusDeleted          InvoiceStatus = "deleted"

	InvoiceStatusIssuingSyncing    InvoiceStatus = "issuing.syncing"
	InvoiceStatusIssuingSyncFailed InvoiceStatus = "issuing.failed"

	InvoiceStatusIssued InvoiceStatus = "issued"

	InvoiceStatusPaymentProcessingPending        InvoiceStatus = "payment_processing.pending"
	InvoiceStatusPaymentProcessingFailed         InvoiceStatus = "payment_processing.failed"
	InvoiceStatusPaymentProcessingActionRequired InvoiceStatus = "payment_processing.action_required"

	InvoiceStatusOverdue InvoiceStatus = "overdue"

	InvoiceStatusPaid InvoiceStatus = "paid"

	InvoiceStatusUncollectible InvoiceStatus = "uncollectible"

	InvoiceStatusVoided InvoiceStatus = "voided"
)

func (InvoiceStatus) IsFailed

func (s InvoiceStatus) IsFailed() bool

func (InvoiceStatus) IsFinal

func (s InvoiceStatus) IsFinal() bool

func (InvoiceStatus) Matches

func (s InvoiceStatus) Matches(statuses ...InvoiceStatusMatcher) bool

func (InvoiceStatus) MatchesInvoiceStatus

func (s InvoiceStatus) MatchesInvoiceStatus(status InvoiceStatus) bool

func (InvoiceStatus) ShortStatus

func (s InvoiceStatus) ShortStatus() string

func (InvoiceStatus) Validate

func (s InvoiceStatus) Validate() error

func (InvoiceStatus) Values

func (s InvoiceStatus) Values() []string

type InvoiceStatusCategory

type InvoiceStatusCategory string
const (
	InvoiceStatusCategoryGathering         InvoiceStatusCategory = "gathering"
	InvoiceStatusCategoryDraft             InvoiceStatusCategory = "draft"
	InvoiceStatusCategoryDelete            InvoiceStatusCategory = "delete"
	InvoiceStatusCategoryDeleted           InvoiceStatusCategory = "deleted"
	InvoiceStatusCategoryIssuing           InvoiceStatusCategory = "issuing"
	InvoiceStatusCategoryIssued            InvoiceStatusCategory = "issued"
	InvoiceStatusCategoryPaymentProcessing InvoiceStatusCategory = "payment_processing"
	InvoiceStatusCategoryOverdue           InvoiceStatusCategory = "overdue"
	InvoiceStatusCategoryPaid              InvoiceStatusCategory = "paid"
	InvoiceStatusCategoryUncollectible     InvoiceStatusCategory = "uncollectible"
	InvoiceStatusCategoryVoided            InvoiceStatusCategory = "voided"
)

func (InvoiceStatusCategory) MatchesInvoiceStatus

func (s InvoiceStatusCategory) MatchesInvoiceStatus(status InvoiceStatus) bool

type InvoiceStatusDetails

type InvoiceStatusDetails struct {
	Immutable        bool                    `json:"immutable"`
	Failed           bool                    `json:"failed"`
	AvailableActions InvoiceAvailableActions `json:"availableActions"`
}

type InvoiceStatusMatcher

type InvoiceStatusMatcher interface {
	MatchesInvoiceStatus(InvoiceStatus) bool
}

type InvoiceTrigger

type InvoiceTrigger = stateless.Trigger
var (
	// TriggerRetry is used to retry a state transition that failed, used by the end user to invoke it manually
	TriggerRetry InvoiceTrigger = "trigger_retry"
	// TriggerApprove is used to approve a state manually
	TriggerApprove InvoiceTrigger = "trigger_approve"
	// TriggerNext is used to advance the invoice to the next state if automatically possible
	TriggerNext InvoiceTrigger = "trigger_next"
	// TriggerFailed is used to trigger the failure state transition associated with the current state
	TriggerFailed InvoiceTrigger = "trigger_failed"
	// TriggerUpdated is used to trigger a change in the invoice (we are using this to calculate the immutable states
	// and trigger re-validation)
	TriggerUpdated InvoiceTrigger = "trigger_updated"
	// TriggerSnapshotQuantities is used to snapshot the quantities for usage based line items
	TriggerSnapshotQuantities InvoiceTrigger = "trigger_snapshot_quantities"
	// triggerDelete is used to delete the invoice
	TriggerDelete InvoiceTrigger = "trigger_delete"

	// TriggerPaid is used to signify that the invoice has been paid
	TriggerPaid InvoiceTrigger = "trigger_paid"
	// TriggerActionRequired is used to signify that the invoice requires action
	TriggerActionRequired InvoiceTrigger = "trigger_action_required"

	// TriggerPaymentUncollectible is used to signify that the invoice is uncollectible
	TriggerPaymentUncollectible InvoiceTrigger = "trigger_payment_uncollectible"
	// TriggerPaymentOverdue is used to signify that the invoice is overdue
	TriggerPaymentOverdue InvoiceTrigger = "trigger_payment_overdue"

	// TriggerVoid is used to signify that the invoice has been voided (e.g. created by mistake)
	TriggerVoid InvoiceTrigger = "trigger_void"
)

type InvoiceTriggerInput

type InvoiceTriggerInput struct {
	Invoice InvoiceID
	// Trigger specifies the trigger that caused the invoice to be changed, only triggerPaid and triggerPayment* are allowed
	Trigger InvoiceTrigger

	ValidationErrors *InvoiceTriggerValidationInput
}

func (InvoiceTriggerInput) Validate

func (i InvoiceTriggerInput) Validate() error

type InvoiceTriggerServiceInput

type InvoiceTriggerServiceInput struct {
	InvoiceTriggerInput

	// AppType is the type of the app that triggered the invoice
	AppType app.AppType
	// Capability is the capability of the app that was processing this trigger
	Capability app.CapabilityType
}

func (InvoiceTriggerServiceInput) Validate

func (i InvoiceTriggerServiceInput) Validate() error

type InvoiceTriggerValidationInput

type InvoiceTriggerValidationInput struct {
	// Operation specifies the operation that yielded the validation errors
	// previous validation errors from this operation will be replaced by this one
	Operation InvoiceOperation
	Errors    []error
}

func (InvoiceTriggerValidationInput) Validate

func (i InvoiceTriggerValidationInput) Validate() error

type InvoiceType

type InvoiceType string
const (
	InvoiceTypeStandard   InvoiceType = InvoiceType(bill.InvoiceTypeStandard)
	InvoiceTypeCreditNote InvoiceType = InvoiceType(bill.InvoiceTypeCreditNote)
)

func (InvoiceType) Validate

func (t InvoiceType) Validate() error

func (InvoiceType) Values

func (t InvoiceType) Values() []string

type InvoiceUpdatedEvent

type InvoiceUpdatedEvent struct {
	Old EventInvoice `json:"old"`
	New EventInvoice `json:"new"`
}

func NewInvoiceUpdatedEvent

func NewInvoiceUpdatedEvent(new Invoice, old EventInvoice) (InvoiceUpdatedEvent, error)

func (InvoiceUpdatedEvent) EventMetadata

func (e InvoiceUpdatedEvent) EventMetadata() metadata.EventMetadata

func (InvoiceUpdatedEvent) EventName

func (e InvoiceUpdatedEvent) EventName() string

func (InvoiceUpdatedEvent) Validate

func (e InvoiceUpdatedEvent) Validate() error

type InvoiceWorkflow

type InvoiceWorkflow struct {
	AppReferences          ProfileAppReferences `json:"appReferences"`
	Apps                   *ProfileApps         `json:"apps,omitempty"`
	SourceBillingProfileID string               `json:"sourceBillingProfileId,omitempty"`
	Config                 WorkflowConfig       `json:"config"`
}

type InvoicingApp

type InvoicingApp interface {
	// ValidateInvoice validates if the app can run for the given invoice
	ValidateInvoice(ctx context.Context, invoice Invoice) error

	// UpsertInvoice upserts the invoice on the remote system, the invoice is read-only, the app should not modify it
	// the recommended behavior is that the invoices FlattenLinesByID is used to get all lines, then the app should
	// synchronize all the fee lines and store the external IDs in the result.
	UpsertInvoice(ctx context.Context, invoice Invoice) (*UpsertInvoiceResult, error)

	// FinalizeInvoice finalizes the invoice on the remote system, starts the payment flow. It is safe to assume
	// that the state machine have already performed an upsert as part of this state transition.
	//
	// If the payment is handled by a decoupled implementation (different app or app has strict separation of concerns)
	// then the payment app will be called with FinalizePayment and that should return the external ID of the payment. (later)
	FinalizeInvoice(ctx context.Context, invoice Invoice) (*FinalizeInvoiceResult, error)

	// DeleteInvoice deletes the invoice on the remote system, the invoice is read-only, the app should not modify it
	// the invoice deletion is only invoked for non-finalized invoices.
	DeleteInvoice(ctx context.Context, invoice Invoice) error
}

Warning: The received invoice is

  • read-only (e.g. any changes made to it are lost to prevent manipulation of the invoice state)
  • reflects the current in memory state of the invoice, thus if you fetched from the db an earlier version of the invoice will be passed, thus do not call any billingService methods from these callbacks.

func GetApp

func GetApp(app app.App) (InvoicingApp, error)

GetApp returns the app from the app entity

type InvoicingAppAsyncSyncer

type InvoicingAppAsyncSyncer interface {
	CanDraftSyncAdvance(invoice Invoice) (bool, error)
	CanIssuingSyncAdvance(invoice Invoice) (bool, error)
}

InvoicingAppAsyncSyncer is an optional interface that can be implemented by the app to support asynchronous syncing of the invoice (e.g. when we are receiving the payload such as with custominvoicing app)

type InvoicingAppPostAdvanceHook

type InvoicingAppPostAdvanceHook interface {
	// PostAdvanceInvoiceHook is called after the invoice has been advanced to the next stable state
	// (e.g. no next trigger is available)
	//
	// Can be used by the app to perform additional actions in case there are some post-processing steps
	// required on the invoice.
	PostAdvanceInvoiceHook(ctx context.Context, invoice Invoice) (*PostAdvanceHookResult, error)
}

type InvoicingConfig

type InvoicingConfig struct {
	AutoAdvance        bool                      `json:"autoAdvance,omitempty"`
	DraftPeriod        isodate.Period            `json:"draftPeriod,omitempty"`
	DueAfter           isodate.Period            `json:"dueAfter,omitempty"`
	ProgressiveBilling bool                      `json:"progressiveBilling,omitempty"`
	DefaultTaxConfig   *productcatalog.TaxConfig `json:"defaultTaxConfig,omitempty"`
}

InvoiceConfig groups fields related to invoice settings.

func (*InvoicingConfig) Validate

func (c *InvoicingConfig) Validate() error

type InvoicingOverrideConfig

type InvoicingOverrideConfig struct {
	AutoAdvance        *bool                     `json:"autoAdvance,omitempty"`
	DraftPeriod        *isodate.Period           `json:"draftPeriod,omitempty"`
	DueAfter           *isodate.Period           `json:"dueAfter,omitempty"`
	ProgressiveBilling *bool                     `json:"progressiveBilling,omitempty"`
	DefaultTaxConfig   *productcatalog.TaxConfig `json:"defaultTaxConfig,omitempty"`
}

func (*InvoicingOverrideConfig) Validate

func (c *InvoicingOverrideConfig) Validate() error

type Line

type Line struct {
	LineBase `json:",inline"`

	// TODO[OM-1060]: Make it a proper union type instead of having both fields as public
	FlatFee    *FlatFeeLine    `json:"flatFee,omitempty"`
	UsageBased *UsageBasedLine `json:"usageBased,omitempty"`

	Children           LineChildren        `json:"children,omitempty"`
	ParentLine         *Line               `json:"parent,omitempty"`
	SplitLineHierarchy *SplitLineHierarchy `json:"progressiveLineHierarchy,omitempty"`

	Discounts LineDiscounts `json:"discounts,omitempty"`

	DBState *Line `json:"-"`
}

func NewFlatFeeLine

func NewFlatFeeLine(input NewFlatFeeLineInput) *Line

func NewUsageBasedFlatFeeLine

func NewUsageBasedFlatFeeLine(input NewFlatFeeLineInput, opts ...usageBasedLineOption) *Line

NewUsageBasedFlatFeeLine creates a new usage based flat fee line (which is semantically equivalent to the line returned by NewFlatFeeLine, but based on the usage based line semantic).

Note: this is temporary in it's current form until we validate the usage based flat fee schema

func (Line) ChildrenWithIDReuse

func (c Line) ChildrenWithIDReuse(l []*Line) (LineChildren, error)

ChildrenWithIDReuse returns a new LineChildren instance with the given lines. If the line has a child with a unique reference ID, it will try to retain the database ID of the existing child to avoid a delete/create.

func (Line) Clone

func (i Line) Clone() *Line

func (Line) CloneWithoutChildren

func (i Line) CloneWithoutChildren() *Line

func (Line) CloneWithoutDependencies

func (i Line) CloneWithoutDependencies() *Line

CloneWithoutDependencies returns a clone of the line without any external dependencies. Could be used for creating a new line without any references to the parent or children (or config IDs).

func (Line) DependsOnMeteredQuantity

func (i Line) DependsOnMeteredQuantity() bool

func (*Line) DisassociateChildren

func (i *Line) DisassociateChildren()

DissacociateChildren removes the Children both from the DBState and the current line, so that the line can be safely persisted/managed without the children.

The childrens receive DBState objects, so that they can be safely persisted/managed without the parent.

func (Line) LineID

func (i Line) LineID() LineID

func (Line) RemoveCircularReferences

func (i Line) RemoveCircularReferences() *Line

func (Line) RemoveMetaForCompare

func (i Line) RemoveMetaForCompare() *Line

RemoveMetaForCompare returns a copy of the invoice without the fields that are not relevant for higher level tests that compare invoices. What gets removed: - Line's DB state - Line's dependencies are marked as resolved - Parent pointers are removed

func (*Line) SaveDBSnapshot

func (i *Line) SaveDBSnapshot()

func (Line) Validate

func (i Line) Validate() error

func (Line) ValidateFee

func (i Line) ValidateFee() error

func (Line) ValidateUsageBased

func (i Line) ValidateUsageBased() error

func (Line) WithoutDBState

func (i Line) WithoutDBState() *Line

func (Line) WithoutSplitLineHierarchy

func (i Line) WithoutSplitLineHierarchy() *Line

type LineBase

type LineBase struct {
	Namespace string `json:"namespace"`
	ID        string `json:"id"`

	CreatedAt time.Time  `json:"createdAt"`
	UpdatedAt time.Time  `json:"updatedAt"`
	DeletedAt *time.Time `json:"deletedAt,omitempty"`

	Metadata    map[string]string    `json:"metadata"`
	Name        string               `json:"name"`
	Type        InvoiceLineType      `json:"type"`
	ManagedBy   InvoiceLineManagedBy `json:"managedBy"`
	Description *string              `json:"description,omitempty"`

	InvoiceID string         `json:"invoiceID,omitempty"`
	Currency  currencyx.Code `json:"currency"`

	// Lifecycle
	Period    Period    `json:"period"`
	InvoiceAt time.Time `json:"invoiceAt"`

	// Relationships
	ParentLineID     *string `json:"parentLine,omitempty"`
	SplitLineGroupID *string `json:"splitLineGroupId,omitempty"`

	Status                 InvoiceLineStatus `json:"status"`
	ChildUniqueReferenceID *string           `json:"childUniqueReferenceID,omitempty"`

	TaxConfig         *productcatalog.TaxConfig `json:"taxOverrides,omitempty"`
	RateCardDiscounts Discounts                 `json:"rateCardDiscounts,omitempty"`

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

	Totals Totals `json:"totals"`
}

LineBase represents the common fields for an invoice item.

func (LineBase) Clone

func (i LineBase) Clone() LineBase

func (LineBase) Equal

func (i LineBase) Equal(other LineBase) bool

func (LineBase) Validate

func (i LineBase) Validate() error

type LineChildren

type LineChildren struct {
	mo.Option[[]*Line]
}

TODO[OM-1016]: For events we need a json marshaler

func NewLineChildren

func NewLineChildren(children []*Line) LineChildren

func (*LineChildren) Append

func (c *LineChildren) Append(l ...*Line)

func (LineChildren) Clone

func (c LineChildren) Clone() LineChildren

func (LineChildren) GetByID

func (c LineChildren) GetByID(id string) *Line

func (LineChildren) Map

func (c LineChildren) Map(fn func(*Line) *Line) LineChildren

func (LineChildren) NonDeletedLineCount

func (c LineChildren) NonDeletedLineCount() int

NonDeletedLineCount returns the number of lines that are not deleted and have a valid status (e.g. we are ignoring split lines)

func (*LineChildren) RemoveByID

func (c *LineChildren) RemoveByID(id string) bool

func (*LineChildren) ReplaceByID

func (c *LineChildren) ReplaceByID(id string, newLine *Line) bool

func (LineChildren) Validate

func (c LineChildren) Validate() error

type LineDiscountBase

type LineDiscountBase struct {
	Description            *string         `json:"description,omitempty"`
	ChildUniqueReferenceID *string         `json:"childUniqueReferenceId,omitempty"`
	ExternalIDs            LineExternalIDs `json:"externalIDs,omitempty"`
	Reason                 DiscountReason  `json:"reason,omitempty"`
}

func (LineDiscountBase) Clone

func (LineDiscountBase) Equal

func (i LineDiscountBase) Equal(other LineDiscountBase) bool

func (LineDiscountBase) GetChildUniqueReferenceID

func (i LineDiscountBase) GetChildUniqueReferenceID() *string

func (LineDiscountBase) Validate

func (i LineDiscountBase) Validate() error

type LineDiscountBaseManaged

type LineDiscountBaseManaged struct {
	models.ManagedModelWithID `json:",inline"`
	LineDiscountBase          `json:",inline"`
}

type LineDiscounts

type LineDiscounts struct {
	Amount AmountLineDiscountsManaged
	Usage  UsageLineDiscountsManaged
}

func (LineDiscounts) Clone

func (i LineDiscounts) Clone() LineDiscounts

func (LineDiscounts) IsEmpty

func (i LineDiscounts) IsEmpty() bool

func (LineDiscounts) ReuseIDsFrom

func (i LineDiscounts) ReuseIDsFrom(existingItems LineDiscounts) (LineDiscounts, error)

func (LineDiscounts) Validate

func (i LineDiscounts) Validate() error

type LineExternalIDs

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

func (LineExternalIDs) Equal

func (i LineExternalIDs) Equal(other LineExternalIDs) bool

type LineID

type LineID models.NamespacedID

func (LineID) Validate

func (i LineID) Validate() error

type LineOrHierarchy

type LineOrHierarchy struct {
	// contains filtered or unexported fields
}

func NewLineOrHierarchy

func NewLineOrHierarchy[T Line | SplitLineHierarchy](line *T) LineOrHierarchy

func (LineOrHierarchy) AsHierarchy

func (i LineOrHierarchy) AsHierarchy() (*SplitLineHierarchy, error)

func (LineOrHierarchy) AsLine

func (i LineOrHierarchy) AsLine() (*Line, error)

func (LineOrHierarchy) ChildUniqueReferenceID

func (i LineOrHierarchy) ChildUniqueReferenceID() *string

func (LineOrHierarchy) Type

type LineOrHierarchyType

type LineOrHierarchyType string
const (
	LineOrHierarchyTypeLine      LineOrHierarchyType = "line"
	LineOrHierarchyTypeHierarchy LineOrHierarchyType = "hierarchy"
)

type LineWithInvoiceHeader

type LineWithInvoiceHeader struct {
	Line    *Line
	Invoice InvoiceBase
}

func (LineWithInvoiceHeader) Clone

type ListCustomerOverridesInput

type ListCustomerOverridesInput struct {
	pagination.Page

	// Warning: We only support a single namespace for now as the default profile handling
	// complicates things. If we need multiple namespace support, I would recommend a different
	// endpoint that doesn't take default namespace into account.
	Namespace       string                 `json:"namespace"`
	BillingProfiles []string               `json:"billingProfile,omitempty"`
	Expand          CustomerOverrideExpand `json:"expand,omitempty"`

	IncludeAllCustomers  bool     `json:"includeAllCustomers,omitempty"`
	CustomerIDs          []string `json:"customerID,omitempty"`
	CustomerName         string   `json:"customerName,omitempty"`
	CustomerKey          string   `json:"customerKey,omitempty"`
	CustomerPrimaryEmail string   `json:"customerPrimaryEmail,omitempty"`

	OrderBy CustomerOverrideOrderBy
	Order   sortx.Order
}

func (ListCustomerOverridesInput) Validate

func (l ListCustomerOverridesInput) Validate() error

type ListInvoiceLinesAdapterInput

type ListInvoiceLinesAdapterInput struct {
	Namespace string

	CustomerID                 string
	InvoiceIDs                 []string
	InvoiceStatuses            []InvoiceStatus
	InvoiceAtBefore            *time.Time
	IncludeDeleted             bool
	ParentLineIDs              []string
	ParentLineIDsIncludeParent bool
	Statuses                   []InvoiceLineStatus

	LineIDs []string
}

func (ListInvoiceLinesAdapterInput) Validate

func (g ListInvoiceLinesAdapterInput) Validate() error

type ListInvoicesExternalIDFilter

type ListInvoicesExternalIDFilter struct {
	Type ExternalIDType
	IDs  []string
}

func (ListInvoicesExternalIDFilter) Validate

func (f ListInvoicesExternalIDFilter) Validate() error

type ListInvoicesInput

type ListInvoicesInput struct {
	pagination.Page

	Namespaces []string
	IDs        []string
	Customers  []string
	// Statuses searches by short InvoiceStatus (e.g. draft, issued)
	Statuses []string

	HasAvailableAction []InvoiceAvailableActionsFilter

	// ExtendedStatuses searches by exact InvoiceStatus
	ExtendedStatuses []InvoiceStatus
	Currencies       []currencyx.Code

	IssuedAfter  *time.Time
	IssuedBefore *time.Time

	PeriodStartAfter  *time.Time
	PeriodStartBefore *time.Time

	// Filter by invoice creation time
	CreatedAfter  *time.Time
	CreatedBefore *time.Time

	IncludeDeleted bool

	// DraftUtil allows to filter invoices which have their draft state expired based on the provided time.
	// Invoice is expired if the time defined by Invoice.DraftUntil is in the past compared to ListInvoicesInput.DraftUntil.
	DraftUntil *time.Time

	// CollectionAt allows to filter invoices which have their collection_at attribute is in the past compared
	// to the time provided in CollectionAt parameter.
	CollectionAt *time.Time

	Expand InvoiceExpand

	ExternalIDs *ListInvoicesExternalIDFilter

	OrderBy api.InvoiceOrderBy
	Order   sortx.Order
}

func (ListInvoicesInput) Validate

func (i ListInvoicesInput) Validate() error

type ListInvoicesResponse

type ListInvoicesResponse = pagination.PagedResponse[Invoice]

type ListProfilesInput

type ListProfilesInput struct {
	pagination.Page

	Expand ProfileExpand

	Namespace       string
	IncludeArchived bool
	OrderBy         api.BillingProfileOrderBy
	Order           sortx.Order
}

func (ListProfilesInput) Validate

func (i ListProfilesInput) Validate() error

type ListProfilesResult

type ListProfilesResult = pagination.PagedResponse[Profile]

type LockCustomerForUpdateAdapterInput

type LockCustomerForUpdateAdapterInput = customer.CustomerID

type LockInvoicesForUpdateInput

type LockInvoicesForUpdateInput = genericMultiInvoiceInput

type LockableService

type LockableService interface {
	WithLock(ctx context.Context, customerID customer.CustomerID, fn func(ctx context.Context) error) error
}

type MaximumSpendDiscount

type MaximumSpendDiscount struct{}

MaximumSpendDiscount contains information about the maximum spend induced discounts

type Metadata

type Metadata map[string]string

type NewFlatFeeLineInput

type NewFlatFeeLineInput struct {
	ID        string
	CreatedAt time.Time
	UpdatedAt time.Time

	Namespace string
	Period    Period
	InvoiceAt time.Time

	InvoiceID string

	Name        string
	Metadata    map[string]string
	Description *string

	Currency currencyx.Code

	ManagedBy InvoiceLineManagedBy

	PerUnitAmount alpacadecimal.Decimal
	PaymentTerm   productcatalog.PaymentTermType

	RateCardDiscounts Discounts
}

helper functions for generating new lines

type NextSequenceNumberInput

type NextSequenceNumberInput struct {
	Namespace string
	Scope     string
}

func (NextSequenceNumberInput) Validate

func (n NextSequenceNumberInput) Validate() error

type NotFoundError

type NotFoundError struct {
	ID     string
	Entity string
	Err    error
}

func (NotFoundError) Error

func (e NotFoundError) Error() string

func (NotFoundError) Unwrap

func (e NotFoundError) Unwrap() error

type PaymentConfig

type PaymentConfig struct {
	CollectionMethod CollectionMethod `json:"collectionMethod"`
}

func (*PaymentConfig) Validate

func (c *PaymentConfig) Validate() error

type PaymentOverrideConfig

type PaymentOverrideConfig struct {
	CollectionMethod *CollectionMethod
}

func (*PaymentOverrideConfig) Validate

func (c *PaymentOverrideConfig) Validate() error

type PercentageDiscount

type PercentageDiscount struct {
	productcatalog.PercentageDiscount `json:",inline"`

	CorrelationID string `json:"correlationID"`
}

func (PercentageDiscount) Clone

func (PercentageDiscount) Equal

type Period

type Period struct {
	Start time.Time `json:"start"`
	End   time.Time `json:"end"`
}

Period represents a time period, in billing the time period is always interpreted as [from, to) (i.e. from is inclusive, to is exclusive). TODO: Lets merge this with recurrence.Period

func (Period) Contains

func (p Period) Contains(t time.Time) bool

func (Period) Duration

func (p Period) Duration() time.Duration

func (Period) Equal

func (p Period) Equal(other Period) bool

func (Period) IsEmpty

func (p Period) IsEmpty() bool

func (Period) Truncate

func (p Period) Truncate(resolution time.Duration) Period

func (Period) Validate

func (p Period) Validate() error

type PostAdvanceHookResult

type PostAdvanceHookResult struct {
	// contains filtered or unexported fields
}

func NewPostAdvanceHookResult

func NewPostAdvanceHookResult() *PostAdvanceHookResult

func (*PostAdvanceHookResult) GetTriggerToInvoke

func (p *PostAdvanceHookResult) GetTriggerToInvoke() *InvoiceTriggerInput

func (*PostAdvanceHookResult) InvokeTrigger

type Profile

type Profile struct {
	BaseProfile

	// Optionaly expanded fields
	Apps *ProfileApps `json:"-"`
}

func (Profile) Merge

func (p Profile) Merge(o *CustomerOverride) Profile

func (Profile) Validate

func (p Profile) Validate() error

type ProfileAdapter

type ProfileAdapter interface {
	CreateProfile(ctx context.Context, input CreateProfileInput) (*BaseProfile, error)
	ListProfiles(ctx context.Context, input ListProfilesInput) (pagination.PagedResponse[BaseProfile], error)
	GetProfile(ctx context.Context, input GetProfileInput) (*AdapterGetProfileResponse, error)
	GetDefaultProfile(ctx context.Context, input GetDefaultProfileInput) (*AdapterGetProfileResponse, error)
	DeleteProfile(ctx context.Context, input DeleteProfileInput) error
	UpdateProfile(ctx context.Context, input UpdateProfileAdapterInput) (*BaseProfile, error)

	IsAppUsed(ctx context.Context, appID app.AppID) error

	GetUnpinnedCustomerIDsWithPaidSubscription(ctx context.Context, input GetUnpinnedCustomerIDsWithPaidSubscriptionInput) ([]customer.CustomerID, error)
}

type ProfileAppReferences

type ProfileAppReferences struct {
	Tax       app.AppID `json:"tax"`
	Invoicing app.AppID `json:"invoicing"`
	Payment   app.AppID `json:"payment"`
}

func (ProfileAppReferences) Validate

func (i ProfileAppReferences) Validate() error

type ProfileApps

type ProfileApps struct {
	Tax       app.App `json:"tax"`
	Invoicing app.App `json:"invoicing"`
	Payment   app.App `json:"payment"`
}

type ProfileExpand

type ProfileExpand struct {
	Apps bool
}

func (ProfileExpand) Validate

func (e ProfileExpand) Validate() error

type ProfileID

type ProfileID models.NamespacedID

func (ProfileID) Validate

func (p ProfileID) Validate() error

type ProfileService

type ProfileService interface {
	CreateProfile(ctx context.Context, param CreateProfileInput) (*Profile, error)
	GetDefaultProfile(ctx context.Context, input GetDefaultProfileInput) (*Profile, error)
	GetProfile(ctx context.Context, input GetProfileInput) (*Profile, error)
	ListProfiles(ctx context.Context, input ListProfilesInput) (ListProfilesResult, error)
	DeleteProfile(ctx context.Context, input DeleteProfileInput) error
	UpdateProfile(ctx context.Context, input UpdateProfileInput) (*Profile, error)
	ProvisionDefaultBillingProfile(ctx context.Context, namespace string) error
	IsAppUsed(ctx context.Context, appID app.AppID) error
}

type RecalculateGatheringInvoicesInput

type RecalculateGatheringInvoicesInput = customer.CustomerID

type RetryInvoiceInput

type RetryInvoiceInput = InvoiceID

type SequenceAdapter

type SequenceAdapter interface {
	NextSequenceNumber(ctx context.Context, input NextSequenceNumberInput) (alpacadecimal.Decimal, error)
}

type SequenceDefinition

type SequenceDefinition struct {
	Prefix         string
	SuffixTemplate string
	Scope          string
}

func (SequenceDefinition) PrefixMatches

func (d SequenceDefinition) PrefixMatches(s string) bool

func (SequenceDefinition) Validate

func (d SequenceDefinition) Validate() error

type SequenceGenerationInput

type SequenceGenerationInput struct {
	Namespace    string
	CustomerName string
	Currency     currencyx.Code
}

func (SequenceGenerationInput) Validate

func (i SequenceGenerationInput) Validate() error

type SequenceService

type SequenceService interface {
	GenerateInvoiceSequenceNumber(ctx context.Context, in SequenceGenerationInput, def SequenceDefinition) (string, error)
}

type SimulateInvoiceInput

type SimulateInvoiceInput struct {
	Namespace  string
	CustomerID *string
	Customer   *customer.Customer

	Number   *string
	Currency currencyx.Code
	Lines    LineChildren
}

func (SimulateInvoiceInput) Validate

func (i SimulateInvoiceInput) Validate() error

type SnapshotLineQuantityInput

type SnapshotLineQuantityInput struct {
	Invoice *Invoice
	Line    *Line
}

func (SnapshotLineQuantityInput) Validate

func (i SnapshotLineQuantityInput) Validate() error

type SnapshotQuantitiesInput

type SnapshotQuantitiesInput = InvoiceID

type SplitLineGroup

type SplitLineGroup struct {
	models.ManagedModel         `json:",inline"`
	models.NamespacedID         `json:",inline"`
	SplitLineGroupMutableFields `json:",inline"`

	Price             *productcatalog.Price  `json:"price"`
	FeatureKey        *string                `json:"featureKey,omitempty"`
	Subscription      *SubscriptionReference `json:"subscription,omitempty"`
	Currency          currencyx.Code         `json:"currency"`
	UniqueReferenceID *string                `json:"childUniqueReferenceId,omitempty"`
}

func (SplitLineGroup) Clone

func (i SplitLineGroup) Clone() SplitLineGroup

func (SplitLineGroup) ToUpdate

func (i SplitLineGroup) ToUpdate() SplitLineGroupUpdate

func (SplitLineGroup) Validate

func (i SplitLineGroup) Validate() error

type SplitLineGroupCreate

type SplitLineGroupCreate struct {
	Namespace string `json:"namespace"`

	SplitLineGroupMutableFields `json:",inline"`

	Price             *productcatalog.Price  `json:"price"`
	FeatureKey        *string                `json:"featureKey,omitempty"`
	Subscription      *SubscriptionReference `json:"subscription,omitempty"`
	Currency          currencyx.Code         `json:"currency"`
	UniqueReferenceID *string                `json:"childUniqueReferenceId,omitempty"`
}

func (SplitLineGroupCreate) Validate

func (i SplitLineGroupCreate) Validate() error

type SplitLineGroupMutableFields

type SplitLineGroupMutableFields struct {
	Name        string          `json:"name"`
	Description *string         `json:"description,omitempty"`
	Metadata    models.Metadata `json:"metadata,omitempty"`

	ServicePeriod Period `json:"period"`

	RatecardDiscounts Discounts                 `json:"ratecardDiscounts"`
	TaxConfig         *productcatalog.TaxConfig `json:"taxConfig,omitempty"`
}

func (SplitLineGroupMutableFields) Clone

func (SplitLineGroupMutableFields) ValidateForPrice

func (i SplitLineGroupMutableFields) ValidateForPrice(price *productcatalog.Price) error

type SplitLineGroupService

type SplitLineGroupService interface {
	DeleteSplitLineGroup(ctx context.Context, input DeleteSplitLineGroupInput) error
	UpdateSplitLineGroup(ctx context.Context, input UpdateSplitLineGroupInput) (SplitLineGroup, error)
}

type SplitLineGroupUpdate

type SplitLineGroupUpdate struct {
	models.NamespacedID `json:",inline"`

	SplitLineGroupMutableFields `json:",inline"`
}

func (SplitLineGroupUpdate) ValidateWithPrice

func (i SplitLineGroupUpdate) ValidateWithPrice(price *productcatalog.Price) error

type SplitLineHierarchy

type SplitLineHierarchy struct {
	Group SplitLineGroup
	Lines []LineWithInvoiceHeader
}

func (*SplitLineHierarchy) Clone

func (*SplitLineHierarchy) ForEachChild

func (h *SplitLineHierarchy) ForEachChild(in ForEachChildInput) error

func (*SplitLineHierarchy) SumNetAmount

SumNetAmount returns the sum of the net amount (pre-tax) of the progressive billed line and its children containing the values for all lines whose period's end is <= in.UpTo and are not deleted or not part of an invoice that has been deleted.

type SubscriptionReference

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

func (SubscriptionReference) Validate

func (i SubscriptionReference) Validate() error

type SumNetAmountInput

type SumNetAmountInput struct {
	PeriodEndLTE   time.Time
	IncludeCharges bool
}

type SupplierContact

type SupplierContact struct {
	ID      string         `json:"id"`
	Name    string         `json:"name"`
	Address models.Address `json:"address"`
	TaxCode *string        `json:"taxCode,omitempty"`
}

func (SupplierContact) Validate

func (c SupplierContact) Validate() error

Validate checks if the supplier contact is valid for invoice generation (e.g. Country is required)

type SyncDraftInvoiceInput

type SyncDraftInvoiceInput struct {
	InvoiceID            InvoiceID
	UpsertInvoiceResults *UpsertInvoiceResult
	AdditionalMetadata   map[string]string
	InvoiceValidator     func(invoice Invoice) error
}

func (SyncDraftInvoiceInput) GetAdditionalMetadata

func (i SyncDraftInvoiceInput) GetAdditionalMetadata() map[string]string

func (SyncDraftInvoiceInput) GetInvoiceID

func (i SyncDraftInvoiceInput) GetInvoiceID() InvoiceID

func (SyncDraftInvoiceInput) MergeIntoInvoice

func (i SyncDraftInvoiceInput) MergeIntoInvoice(invoice *Invoice) error

func (SyncDraftInvoiceInput) Validate

func (i SyncDraftInvoiceInput) Validate() error

func (SyncDraftInvoiceInput) ValidateWithInvoice

func (i SyncDraftInvoiceInput) ValidateWithInvoice(invoice Invoice) error

type SyncInput

type SyncInput interface {
	models.Validator

	ValidateWithInvoice(invoice Invoice) error
	MergeIntoInvoice(invoice *Invoice) error
	GetAdditionalMetadata() map[string]string
	GetInvoiceID() InvoiceID
}

type SyncIssuingInvoiceInput

type SyncIssuingInvoiceInput struct {
	InvoiceID             InvoiceID
	FinalizeInvoiceResult *FinalizeInvoiceResult
	AdditionalMetadata    map[string]string
	InvoiceValidator      func(invoice Invoice) error
}

func (SyncIssuingInvoiceInput) GetAdditionalMetadata

func (i SyncIssuingInvoiceInput) GetAdditionalMetadata() map[string]string

func (SyncIssuingInvoiceInput) GetInvoiceID

func (i SyncIssuingInvoiceInput) GetInvoiceID() InvoiceID

func (SyncIssuingInvoiceInput) MergeIntoInvoice

func (i SyncIssuingInvoiceInput) MergeIntoInvoice(invoice *Invoice) error

func (SyncIssuingInvoiceInput) Validate

func (i SyncIssuingInvoiceInput) Validate() error

func (SyncIssuingInvoiceInput) ValidateWithInvoice

func (i SyncIssuingInvoiceInput) ValidateWithInvoice(invoice Invoice) error

type Totals

type Totals struct {
	// Amount is the total amount value of the line before taxes, discounts and commitments
	Amount alpacadecimal.Decimal `json:"amount"`
	// ChargesTotal is the amount of value of the line that are due to additional charges
	ChargesTotal alpacadecimal.Decimal `json:"chargesTotal"`
	// DiscountsTotal is the amount of value of the line that are due to discounts
	DiscountsTotal alpacadecimal.Decimal `json:"discountsTotal"`

	// TaxesInclusiveTotal is the total amount of taxes that are included in the line
	TaxesInclusiveTotal alpacadecimal.Decimal `json:"taxesInclusiveTotal"`
	// TaxesExclusiveTotal is the total amount of taxes that are excluded from the line
	TaxesExclusiveTotal alpacadecimal.Decimal `json:"taxesExclusiveTotal"`
	// TaxesTotal is the total amount of taxes that are included in the line
	TaxesTotal alpacadecimal.Decimal `json:"taxesTotal"`

	// Total is the total amount value of the line after taxes, discounts and commitments
	Total alpacadecimal.Decimal `json:"total"`
}

func (Totals) Add

func (t Totals) Add(others ...Totals) Totals

func (Totals) CalculateTotal

func (t Totals) CalculateTotal() alpacadecimal.Decimal

func (Totals) Validate

func (t Totals) Validate() error

type UpdateAfterDeleteError

type UpdateAfterDeleteError genericError

func (UpdateAfterDeleteError) Error

func (e UpdateAfterDeleteError) Error() string

func (UpdateAfterDeleteError) Unwrap

func (e UpdateAfterDeleteError) Unwrap() error

type UpdateCustomerOverrideAdapterInput

type UpdateCustomerOverrideAdapterInput = UpsertCustomerOverrideInput

type UpdateInvoiceAdapterInput

type UpdateInvoiceAdapterInput = Invoice

type UpdateInvoiceFieldsInput

type UpdateInvoiceFieldsInput struct {
	Invoice          InvoiceID
	SentToCustomerAt mo.Option[*time.Time]
}

func (UpdateInvoiceFieldsInput) Validate

func (i UpdateInvoiceFieldsInput) Validate() error

type UpdateInvoiceInput

type UpdateInvoiceInput struct {
	Invoice InvoiceID
	EditFn  func(*Invoice) error
	// IncludeDeletedLines signals the update to populate the deleted lines into the lines field, for the edit function
	IncludeDeletedLines bool
}

func (UpdateInvoiceInput) Validate

func (i UpdateInvoiceInput) Validate() error

type UpdateInvoiceLineAdapterInput

type UpdateInvoiceLineAdapterInput Line

type UpdateInvoiceLineBaseInput

type UpdateInvoiceLineBaseInput struct {
	InvoiceAt mo.Option[time.Time]

	Metadata  mo.Option[map[string]string]
	Name      mo.Option[string]
	ManagedBy mo.Option[InvoiceLineManagedBy]
	Period    mo.Option[Period]
	TaxConfig mo.Option[*productcatalog.TaxConfig]
}

func (UpdateInvoiceLineBaseInput) Apply

func (UpdateInvoiceLineBaseInput) Validate

func (u UpdateInvoiceLineBaseInput) Validate() error

type UpdateInvoiceLineFlatFeeInput

type UpdateInvoiceLineFlatFeeInput struct {
	PerUnitAmount mo.Option[alpacadecimal.Decimal]
	Quantity      mo.Option[alpacadecimal.Decimal]
	PaymentTerm   mo.Option[productcatalog.PaymentTermType]
}

func (UpdateInvoiceLineFlatFeeInput) Apply

func (UpdateInvoiceLineFlatFeeInput) Validate

func (u UpdateInvoiceLineFlatFeeInput) Validate() error

type UpdateInvoiceLineInput

type UpdateInvoiceLineInput struct {
	// Mandatory fields for update
	Line LineID
	Type InvoiceLineType

	LineBase   UpdateInvoiceLineBaseInput
	UsageBased UpdateInvoiceLineUsageBasedInput
	FlatFee    UpdateInvoiceLineFlatFeeInput
}

func (UpdateInvoiceLineInput) Apply

func (u UpdateInvoiceLineInput) Apply(l *Line) (*Line, error)

func (UpdateInvoiceLineInput) Validate

func (u UpdateInvoiceLineInput) Validate() error

type UpdateInvoiceLineUsageBasedInput

type UpdateInvoiceLineUsageBasedInput struct {
	Price *productcatalog.Price
}

func (UpdateInvoiceLineUsageBasedInput) Apply

func (UpdateInvoiceLineUsageBasedInput) Validate

type UpdateInvoiceLinesInternalInput

type UpdateInvoiceLinesInternalInput struct {
	Namespace  string
	CustomerID string
	Lines      []*Line
}

func (UpdateInvoiceLinesInternalInput) Validate

type UpdateProfileAdapterInput

type UpdateProfileAdapterInput struct {
	TargetState      BaseProfile
	WorkflowConfigID string
}

func (UpdateProfileAdapterInput) Validate

func (i UpdateProfileAdapterInput) Validate() error

type UpdateProfileInput

type UpdateProfileInput BaseProfile

func (UpdateProfileInput) ProfileID

func (i UpdateProfileInput) ProfileID() ProfileID

func (UpdateProfileInput) Validate

func (i UpdateProfileInput) Validate() error

type UpdateSplitLineGroupInput

type UpdateSplitLineGroupInput = SplitLineGroupUpdate

Adapter

type UpsertCustomerOverrideAdapterInput

type UpsertCustomerOverrideAdapterInput = customer.CustomerID

type UpsertCustomerOverrideInput

type UpsertCustomerOverrideInput struct {
	Namespace  string `json:"namespace"`
	CustomerID string `json:"customerID"`

	ProfileID string `json:"billingProfileID"`

	Collection CollectionOverrideConfig `json:"collection"`
	Invoicing  InvoicingOverrideConfig  `json:"invoicing"`
	Payment    PaymentOverrideConfig    `json:"payment"`
}

func (UpsertCustomerOverrideInput) Validate

func (u UpsertCustomerOverrideInput) Validate() error

type UpsertInvoiceLinesAdapterInput

type UpsertInvoiceLinesAdapterInput struct {
	Namespace string
	Lines     []*Line
}

func (UpsertInvoiceLinesAdapterInput) Validate

type UpsertInvoiceResult

type UpsertInvoiceResult = UpsertResults

func NewUpsertInvoiceResult

func NewUpsertInvoiceResult() *UpsertInvoiceResult

func (UpsertInvoiceResult) MergeIntoInvoice

func (r UpsertInvoiceResult) MergeIntoInvoice(invoice *Invoice) error

MergeIntoInvoice merges the upsert invoice result into the invoice.

type UpsertResults

type UpsertResults struct {
	// contains filtered or unexported fields
}

func NewUpsertResults

func NewUpsertResults() *UpsertResults

func (*UpsertResults) AddLineDiscountExternalID

func (u *UpsertResults) AddLineDiscountExternalID(lineDiscountID string, externalID string) *UpsertResults

func (*UpsertResults) AddLineExternalID

func (u *UpsertResults) AddLineExternalID(lineID string, externalID string) *UpsertResults

func (*UpsertResults) GetExternalID

func (u *UpsertResults) GetExternalID() (string, bool)

func (*UpsertResults) GetInvoiceNumber

func (u *UpsertResults) GetInvoiceNumber() (string, bool)

func (*UpsertResults) GetLineDiscountExternalID

func (u *UpsertResults) GetLineDiscountExternalID(lineDiscountID string) (string, bool)

func (*UpsertResults) GetLineDiscountExternalIDs

func (u *UpsertResults) GetLineDiscountExternalIDs() map[string]string

func (*UpsertResults) GetLineExternalID

func (u *UpsertResults) GetLineExternalID(lineID string) (string, bool)

func (*UpsertResults) GetLineExternalIDs

func (u *UpsertResults) GetLineExternalIDs() map[string]string

func (*UpsertResults) SetExternalID

func (u *UpsertResults) SetExternalID(externalID string) *UpsertResults

func (*UpsertResults) SetInvoiceNumber

func (u *UpsertResults) SetInvoiceNumber(invoiceNumber string) *UpsertResults

type UpsertValidationIssuesInput

type UpsertValidationIssuesInput struct {
	Invoice InvoiceID
	Issues  ValidationIssues
}

func (UpsertValidationIssuesInput) Validate

func (i UpsertValidationIssuesInput) Validate() error

type UsageBasedLine

type UsageBasedLine struct {
	ConfigID string `json:"configId"`

	// Price is the price of the usage based line. Note: this should be a pointer or marshaling will fail for
	// empty prices.
	Price      *productcatalog.Price `json:"price"`
	FeatureKey string                `json:"featureKey"`

	Quantity        *alpacadecimal.Decimal `json:"quantity"`
	MeteredQuantity *alpacadecimal.Decimal `json:"meteredQuantity,omitempty"`

	PreLinePeriodQuantity        *alpacadecimal.Decimal `json:"preLinePeriodQuantity,omitempty"`
	MeteredPreLinePeriodQuantity *alpacadecimal.Decimal `json:"meteredPreLinePeriodQuantity,omitempty"`
}

func (UsageBasedLine) Clone

func (i UsageBasedLine) Clone() *UsageBasedLine

func (UsageBasedLine) Equal

func (i UsageBasedLine) Equal(other *UsageBasedLine) bool

func (UsageBasedLine) Validate

func (i UsageBasedLine) Validate() error

type UsageDiscount

type UsageDiscount struct {
	productcatalog.UsageDiscount `json:",inline"`

	CorrelationID string `json:"correlationID"`
}

func (UsageDiscount) Clone

func (d UsageDiscount) Clone() UsageDiscount

func (UsageDiscount) Equal

func (d UsageDiscount) Equal(other UsageDiscount) bool

type UsageLineDiscount

type UsageLineDiscount struct {
	LineDiscountBase `json:",inline"`

	Quantity              alpacadecimal.Decimal  `json:"quantity"`
	PreLinePeriodQuantity *alpacadecimal.Decimal `json:"preLinePeriodQuantity"`
}

func (UsageLineDiscount) Clone

func (UsageLineDiscount) Equal

func (i UsageLineDiscount) Equal(other UsageLineDiscount) bool

func (UsageLineDiscount) Validate

func (i UsageLineDiscount) Validate() error

type UsageLineDiscountManaged

type UsageLineDiscountManaged struct {
	models.ManagedModelWithID `json:",inline"`
	UsageLineDiscount         `json:",inline"`
}

func (UsageLineDiscountManaged) Clone

func (UsageLineDiscountManaged) ContentsEqual

func (UsageLineDiscountManaged) Equal

func (UsageLineDiscountManaged) GetManagedFieldsWithID

func (i UsageLineDiscountManaged) GetManagedFieldsWithID() models.ManagedModelWithID

func (UsageLineDiscountManaged) Validate

func (i UsageLineDiscountManaged) Validate() error

func (UsageLineDiscountManaged) WithManagedFieldsWithID

type UsageLineDiscountsManaged

type UsageLineDiscountsManaged []UsageLineDiscountManaged

func (UsageLineDiscountsManaged) Clone

func (UsageLineDiscountsManaged) MergeDiscountsByChildUniqueReferenceID

func (d UsageLineDiscountsManaged) MergeDiscountsByChildUniqueReferenceID(newDiscount UsageLineDiscountManaged) UsageLineDiscountsManaged

type ValidationError

type ValidationError genericError

func (ValidationError) Error

func (e ValidationError) Error() string

func (ValidationError) Unwrap

func (e ValidationError) Unwrap() error

type ValidationIssue

type ValidationIssue struct {
	ID        string     `json:"id,omitempty"`
	CreatedAt time.Time  `json:"createdAt,omitempty"`
	UpdatedAt time.Time  `json:"updatedAt,omitempty"`
	DeletedAt *time.Time `json:"deletedAt,omitempty"`

	Severity  ValidationIssueSeverity `json:"severity"`
	Message   string                  `json:"message"`
	Code      string                  `json:"code,omitempty"`
	Component ComponentName           `json:"component,omitempty"`
	Path      string                  `json:"path,omitempty"`
}

func NewValidationError

func NewValidationError(code, message string) ValidationIssue

func NewValidationWarning

func NewValidationWarning(code, message string) ValidationIssue

func (ValidationIssue) EncodeAsErrorExtension

func (i ValidationIssue) EncodeAsErrorExtension() map[string]interface{}

func (ValidationIssue) Error

func (i ValidationIssue) Error() string

type ValidationIssueSeverity

type ValidationIssueSeverity string
const (
	ValidationIssueSeverityCritical ValidationIssueSeverity = "critical"
	ValidationIssueSeverityWarning  ValidationIssueSeverity = "warning"

	ValidationComponentOpenMeter = "openmeter"
)

func (ValidationIssueSeverity) Values

func (ValidationIssueSeverity) Values() []string

type ValidationIssues

type ValidationIssues []ValidationIssue

func ToValidationIssues

func ToValidationIssues(errIn error) (ValidationIssues, error)

ToValidationIssues converts an error into a list of validation issues If the error is nil, it returns nil If any error in the error tree is not wrapped in ValidationWithComponent or ValidationWithFieldPrefix and not an instance of ValidationIssue, it will return an error. This behavior allows us to have critical errors that are not validation issues.

func (ValidationIssues) AsError

func (v ValidationIssues) AsError() error

func (ValidationIssues) Clone

func (ValidationIssues) Map

func (ValidationIssues) RemoveMetaForCompare

func (v ValidationIssues) RemoveMetaForCompare() ValidationIssues

type VersionedCustomerUsageAttribution

type VersionedCustomerUsageAttribution struct {
	CustomerUsageAttribution `json:",inline"`
	Type                     string `json:"type"`
}

type WorkflowConfig

type WorkflowConfig struct {
	Collection CollectionConfig  `json:"collection"`
	Invoicing  InvoicingConfig   `json:"invoicing"`
	Payment    PaymentConfig     `json:"payment"`
	Tax        WorkflowTaxConfig `json:"tax"`
}

func (WorkflowConfig) Validate

func (c WorkflowConfig) Validate() error

type WorkflowTaxConfig

type WorkflowTaxConfig struct {
	// Enable automatic tax calculation when tax is supported by the app.
	// For example, with Stripe Invoicing when enabled, tax is calculated via Stripe Tax.
	Enabled bool `json:"enabled"`

	// Enforce tax calculation when tax is supported by the app.
	// When enabled, OpenMeter will not allow to create an invoice without tax calculation.
	// Enforcement is different per apps, for example, Stripe app requires customer
	// to have a tax location when starting a paid subscription.
	Enforced bool `json:"enforced"`
}

WorkflowTaxConfig groups fields related to tax settings.

func (*WorkflowTaxConfig) Validate

func (c *WorkflowTaxConfig) Validate() error

Validate validates the tax config.

Directories

Path Synopsis
lineservice
lineservice package contains the implementation of the LineAdapter interface which acts as a adapter between the specific line types and the billing service.
lineservice package contains the implementation of the LineAdapter interface which acts as a adapter between the specific line types and the billing service.
validators

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL