| package creditvoid |
|
|
| import ( |
| "context" |
| "errors" |
| "fmt" |
| "time" |
|
|
| "github.com/alpacahq/alpacadecimal" |
|
|
| "github.com/openmeterio/openmeter/openmeter/customer" |
| "github.com/openmeterio/openmeter/openmeter/ledger" |
| "github.com/openmeterio/openmeter/pkg/currencyx" |
| "github.com/openmeterio/openmeter/pkg/models" |
| ) |
|
|
| type Record struct { |
| ID models.NamespacedID |
| Amount alpacadecimal.Decimal |
| CreatedAt time.Time |
| UpdatedAt time.Time |
| DeletedAt *time.Time |
|
|
| CustomerID customer.CustomerID |
| Currency currencyx.Code |
| VoidedAt time.Time |
|
|
| SourceChargeID string |
|
|
| VoidTransactionGroupID string |
| VoidTransactionID string |
|
|
| FBOSubAccountID string |
| ReceivableSubAccountID string |
|
|
| Annotations models.Annotations |
| } |
|
|
| |
| |
| type pendingVoidRecord struct { |
| ID models.NamespacedID |
| Amount alpacadecimal.Decimal |
| CustomerID customer.CustomerID |
| Currency currencyx.Code |
| VoidedAt time.Time |
|
|
| SourceChargeID string |
|
|
| FBOSubAccountID string |
| ReceivableSubAccountID string |
| } |
|
|
| func (r pendingVoidRecord) committed(groupID, transactionID string, annotations models.Annotations) Record { |
| return Record{ |
| ID: r.ID, |
| Amount: r.Amount, |
| CustomerID: r.CustomerID, |
| Currency: r.Currency, |
| VoidedAt: r.VoidedAt, |
| SourceChargeID: r.SourceChargeID, |
| VoidTransactionGroupID: groupID, |
| VoidTransactionID: transactionID, |
| FBOSubAccountID: r.FBOSubAccountID, |
| ReceivableSubAccountID: r.ReceivableSubAccountID, |
| Annotations: annotations, |
| } |
| } |
|
|
| type CreateRecordsInput struct { |
| Records []Record |
| } |
|
|
| func (i CreateRecordsInput) Validate() error { |
| for idx, record := range i.Records { |
| if err := record.Validate(); err != nil { |
| return fmt.Errorf("records[%d]: %w", idx, err) |
| } |
| } |
|
|
| return nil |
| } |
|
|
| func (r Record) Validate() error { |
| var errs []error |
|
|
| if err := r.ID.Validate(); err != nil { |
| errs = append(errs, fmt.Errorf("id: %w", err)) |
| } |
| if !r.Amount.IsPositive() { |
| errs = append(errs, errors.New("amount must be positive")) |
| } |
| if err := r.CustomerID.Validate(); err != nil { |
| errs = append(errs, fmt.Errorf("customer id: %w", err)) |
| } |
| if err := r.Currency.Validate(); err != nil { |
| errs = append(errs, fmt.Errorf("currency: %w", err)) |
| } |
| if r.VoidedAt.IsZero() { |
| errs = append(errs, errors.New("voided at is required")) |
| } |
| if r.SourceChargeID == "" { |
| errs = append(errs, errors.New("source charge id is required")) |
| } |
| if r.VoidTransactionGroupID == "" { |
| errs = append(errs, errors.New("void transaction group id is required")) |
| } |
| if r.VoidTransactionID == "" { |
| errs = append(errs, errors.New("void transaction id is required")) |
| } |
| if r.FBOSubAccountID == "" { |
| errs = append(errs, errors.New("FBO sub-account id is required")) |
| } |
| if r.ReceivableSubAccountID == "" { |
| errs = append(errs, errors.New("receivable sub-account id is required")) |
| } |
|
|
| return errors.Join(errs...) |
| } |
|
|
| type ListRecordsInput struct { |
| CustomerID customer.CustomerID |
| Currency *currencyx.Code |
| AsOf time.Time |
| Route ledger.RouteFilter |
| } |
|
|
| type Adapter interface { |
| CreateRecords(ctx context.Context, input CreateRecordsInput) error |
| ListRecords(ctx context.Context, input ListRecordsInput) ([]Record, error) |
| } |
|
|