Documentation
¶
Index ¶
- Constants
- Variables
- func ChargeAnnotations(chargeID models.NamespacedID) models.Annotations
- func ChargeTransactionAnnotations(input ChargeTransactionAnnotationsInput) models.Annotations
- func SortedFeatures(features []string) []string
- func TransactionAnnotations(templateCode string, direction TransactionDirection) models.Annotations
- func TransactionTemplateCodeFromAnnotations(annotations models.Annotations) (string, error)
- func ValidateAddress(ctx context.Context, address PostingAddress) error
- func ValidateCostBasis(value alpacadecimal.Decimal) error
- func ValidateCreditPriority(value int) error
- func ValidateCurrency(value currencyx.Code) error
- func ValidateEntryInput(ctx context.Context, entry EntryInput) error
- func ValidateInvariance(ctx context.Context, entries []EntryInput) error
- func ValidateRouting(ctx context.Context, entries []EntryInput) error
- func ValidateTransactionAmount(value alpacadecimal.Decimal) error
- func ValidateTransactionInput(ctx context.Context, transaction TransactionInput) error
- func ValidateTransactionInputWith(ctx context.Context, transaction TransactionInput, ...) error
- type Account
- type AccountCatalog
- type AccountLocker
- type AccountProvisioner
- type AccountReader
- type AccountResolver
- type AccountType
- type Balance
- type BalanceQuerier
- type BusinessAccount
- type BusinessAccounts
- type BusinessRouteParams
- type ChargeTransactionAnnotationsInput
- type CreateAccountInput
- type CreateSubAccountInput
- type CustomerAccount
- type CustomerAccounts
- type CustomerAccruedAccount
- type CustomerAccruedRouteParams
- type CustomerFBOAccount
- type CustomerFBORouteParams
- type CustomerReceivableAccount
- type CustomerReceivableRouteParams
- type Entry
- type EntryInput
- type Filters
- type Ledger
- type ListAccountsInput
- type ListSubAccountsInput
- type ListTransactionsCreditMovement
- type ListTransactionsInput
- type ListTransactionsResult
- type PostingAddress
- type Query
- type QuerySummedResult
- type Route
- type RouteFilter
- type RoutingKey
- type RoutingKeyVersion
- type RoutingValidator
- type SubAccount
- type SubAccountRoute
- type Transaction
- type TransactionAuthorizationStatus
- type TransactionCursor
- type TransactionDirection
- type TransactionGroup
- type TransactionGroupInput
- type TransactionInput
Constants ¶
const ( AnnotationChargeNamespace = "ledger.charge.namespace" AnnotationChargeID = "ledger.charge.id" AnnotationSubscriptionID = "ledger.subscription.id" AnnotationSubscriptionPhaseID = "ledger.subscription.phase.id" AnnotationSubscriptionItemID = "ledger.subscription.item.id" AnnotationFeatureID = "ledger.feature.id" AnnotationTransactionTemplateCode = "ledger.transaction.template_code" AnnotationTransactionDirection = "ledger.transaction.direction" )
const DefaultCustomerFBOPriority = 100
const ErrCodeAddressInvalid models.ErrorCode = "ledger_address_invalid"
const ErrCodeBusinessAccountMissing models.ErrorCode = "ledger_business_account_missing"
const ErrCodeCostBasisInvalid models.ErrorCode = "ledger_cost_basis_invalid"
const ErrCodeCreditPriorityInvalid models.ErrorCode = "ledger_credit_priority_invalid"
const ErrCodeCurrencyInvalid models.ErrorCode = "ledger_currency_invalid"
const ErrCodeCustomerAccountMissing models.ErrorCode = "ledger_customer_account_missing"
const ErrCodeEntryInvalid models.ErrorCode = "ledger_entry_invalid"
const ErrCodeInvalidTransactionTotal models.ErrorCode = "invalid_transaction_total"
const ErrCodeListTransactionsInputInvalid models.ErrorCode = "ledger_list_transactions_input_invalid"
const ErrCodeResolutionScopeInvalid models.ErrorCode = "ledger_resolution_scope_invalid"
const ErrCodeResolutionTemplateUnknown models.ErrorCode = "ledger_resolution_template_unknown"
const ErrCodeRoutingKeyVersionInvalid models.ErrorCode = "ledger_routing_key_version_invalid"
const ErrCodeRoutingKeyVersionUnsupported models.ErrorCode = "ledger_routing_key_version_unsupported"
const ErrCodeRoutingRuleViolated models.ErrorCode = "ledger_routing_rule_violated"
const ErrCodeTransactionAmountInvalid models.ErrorCode = "ledger_transaction_amount_invalid"
const ErrCodeTransactionAuthorizationStatusInvalid models.ErrorCode = "ledger_transaction_authorization_status_invalid"
const ErrCodeTransactionGroupEmpty models.ErrorCode = "ledger_transaction_group_empty"
const ErrCodeTransactionInputRequired models.ErrorCode = "ledger_transaction_input_required"
Variables ¶
var BusinessAccountTypes = []AccountType{ AccountTypeWash, AccountTypeEarnings, AccountTypeBrokerage, }
var CustomerAccountTypes = []AccountType{ AccountTypeCustomerFBO, AccountTypeCustomerReceivable, AccountTypeCustomerAccrued, }
var ErrAddressInvalid = models.NewValidationIssue( ErrCodeAddressInvalid, "ledger posting address is invalid", )
var ErrBusinessAccountMissing = models.NewValidationIssue( ErrCodeBusinessAccountMissing, "required business ledger account is missing", )
var ErrCodeLedgerQueryInvalid models.ErrorCode = "ledger_query_invalid"
var ErrCostBasisInvalid = models.NewValidationIssue( ErrCodeCostBasisInvalid, "ledger cost basis is invalid", )
var ErrCreditPriorityInvalid = models.NewValidationIssue( ErrCodeCreditPriorityInvalid, "ledger credit priority is invalid", )
var ErrCurrencyInvalid = models.NewValidationIssue( ErrCodeCurrencyInvalid, "ledger currency is invalid", )
var ErrCustomerAccountMissing = models.NewValidationIssue( ErrCodeCustomerAccountMissing, "required customer ledger account is missing", )
var ErrEntryInvalid = models.NewValidationIssue( ErrCodeEntryInvalid, "ledger entry is invalid", )
var ErrInvalidTransactionTotal = models.NewValidationIssue( ErrCodeInvalidTransactionTotal, "transaction total is invalid, credits and debits must sum to 0", )
var ErrLedgerQueryInvalid = models.NewValidationIssue( ErrCodeLedgerQueryInvalid, "ledger query is invalid", )
var ErrListTransactionsInputInvalid = models.NewValidationIssue( ErrCodeListTransactionsInputInvalid, "ledger list transactions input is invalid", )
var ErrResolutionScopeInvalid = models.NewValidationIssue( ErrCodeResolutionScopeInvalid, "ledger resolution scope is invalid", )
var ErrResolutionTemplateUnknown = models.NewValidationIssue( ErrCodeResolutionTemplateUnknown, "ledger transaction template type is unknown", )
var ErrRoutingKeyVersionInvalid = models.NewValidationIssue( ErrCodeRoutingKeyVersionInvalid, "ledger routing key version is invalid", )
var ErrRoutingKeyVersionUnsupported = models.NewValidationIssue( ErrCodeRoutingKeyVersionUnsupported, "ledger routing key version is unsupported", )
var ErrRoutingRuleViolated = models.NewValidationIssue( ErrCodeRoutingRuleViolated, "ledger routing rule violated", )
var ErrTransactionAmountInvalid = models.NewValidationIssue( ErrCodeTransactionAmountInvalid, "ledger transaction amount is invalid", )
var ErrTransactionAuthorizationStatusInvalid = models.NewValidationIssue( ErrCodeTransactionAuthorizationStatusInvalid, "ledger transaction authorization status is invalid", )
var ErrTransactionGroupEmpty = models.NewValidationIssue( ErrCodeTransactionGroupEmpty, "ledger transaction group must contain at least one transaction", )
var ErrTransactionInputRequired = models.NewValidationIssue( ErrCodeTransactionInputRequired, "transaction input is required", )
Functions ¶
func ChargeAnnotations ¶
func ChargeAnnotations(chargeID models.NamespacedID) models.Annotations
func ChargeTransactionAnnotations ¶
func ChargeTransactionAnnotations(input ChargeTransactionAnnotationsInput) models.Annotations
func SortedFeatures ¶
SortedFeatures returns a sorted copy of features for canonical storage. Returns nil if empty.
func TransactionAnnotations ¶
func TransactionAnnotations(templateCode string, direction TransactionDirection) models.Annotations
func TransactionTemplateCodeFromAnnotations ¶
func TransactionTemplateCodeFromAnnotations(annotations models.Annotations) (string, error)
func ValidateAddress ¶
func ValidateAddress(ctx context.Context, address PostingAddress) error
func ValidateCostBasis ¶
func ValidateCostBasis(value alpacadecimal.Decimal) error
func ValidateCreditPriority ¶
ValidateCreditPriority validates a credit priority integer value.
func ValidateCurrency ¶
ValidateCurrency validates a currency value.
func ValidateEntryInput ¶
func ValidateEntryInput(ctx context.Context, entry EntryInput) error
func ValidateInvariance ¶
func ValidateInvariance(ctx context.Context, entries []EntryInput) error
ValidateInvariance validates that Debit - Credit = 0 for the given entries.
func ValidateRouting ¶
func ValidateRouting(ctx context.Context, entries []EntryInput) error
func ValidateTransactionAmount ¶
func ValidateTransactionAmount(value alpacadecimal.Decimal) error
func ValidateTransactionInput ¶
func ValidateTransactionInput(ctx context.Context, transaction TransactionInput) error
func ValidateTransactionInputWith ¶
func ValidateTransactionInputWith(ctx context.Context, transaction TransactionInput, routingValidator RoutingValidator) error
Types ¶
type Account ¶
type Account interface {
ID() models.NamespacedID
Type() AccountType
}
Account represents a ledger account tying together multiple sub-accounts. Accounts describe ownership and purpose while SubAccounts parameterize the actual posting address.
type AccountCatalog ¶
type AccountCatalog interface {
AccountReader
AccountProvisioner
}
type AccountLocker ¶
type AccountProvisioner ¶
type AccountProvisioner interface {
CreateAccount(ctx context.Context, input CreateAccountInput) (Account, error)
EnsureSubAccount(ctx context.Context, input CreateSubAccountInput) (SubAccount, error)
}
type AccountReader ¶
type AccountReader interface {
GetAccountByID(ctx context.Context, id models.NamespacedID) (Account, error)
GetSubAccountByID(ctx context.Context, id models.NamespacedID) (SubAccount, error)
ListSubAccounts(ctx context.Context, input ListSubAccountsInput) ([]SubAccount, error)
ListAccounts(ctx context.Context, input ListAccountsInput) ([]Account, error)
}
type AccountResolver ¶
type AccountResolver interface {
GetCustomerAccounts(ctx context.Context, customerID customer.CustomerID) (CustomerAccounts, error)
EnsureBusinessAccounts(ctx context.Context, namespace string) (BusinessAccounts, error)
GetBusinessAccounts(ctx context.Context, namespace string) (BusinessAccounts, error)
}
type AccountType ¶
type AccountType string
const ( AccountTypeCustomerFBO AccountType = "customer_fbo" // is this the right name? AccountTypeCustomerReceivable AccountType = "customer_receivable" AccountTypeCustomerAccrued AccountType = "customer_accrued" )
Customer Accounts
const ( AccountTypeWash AccountType = "wash" AccountTypeEarnings AccountType = "earnings" AccountTypeBrokerage AccountType = "brokerage" )
Shared Business Accounts
func (AccountType) Validate ¶
func (t AccountType) Validate() error
type Balance ¶
type Balance interface {
Settled() alpacadecimal.Decimal
Pending() alpacadecimal.Decimal
}
type BalanceQuerier ¶
type BalanceQuerier interface {
GetAccountBalance(ctx context.Context, account Account, query RouteFilter, after *TransactionCursor) (Balance, error)
GetSubAccountBalance(ctx context.Context, subAccount SubAccount, after *TransactionCursor) (Balance, error)
}
type BusinessAccount ¶
type BusinessAccount interface {
Account
GetSubAccountForRoute(ctx context.Context, route BusinessRouteParams) (SubAccount, error)
}
BusinessAccount is a business account.
type BusinessAccounts ¶
type BusinessAccounts struct {
WashAccount BusinessAccount
EarningsAccount BusinessAccount
BrokerageAccount BusinessAccount
}
type BusinessRouteParams ¶
type BusinessRouteParams struct {
Currency currencyx.Code
CostBasis *alpacadecimal.Decimal
}
func (BusinessRouteParams) Route ¶
func (p BusinessRouteParams) Route() Route
func (BusinessRouteParams) Validate ¶
func (p BusinessRouteParams) Validate() error
type CreateAccountInput ¶
type CreateAccountInput struct {
Namespace string
Type AccountType
Annotations models.Annotations
}
func (CreateAccountInput) Validate ¶
func (c CreateAccountInput) Validate() error
type CreateSubAccountInput ¶
type CreateSubAccountInput struct {
Namespace string
AccountID string
Annotations models.Annotations
Route Route
}
func (CreateSubAccountInput) Validate ¶
func (c CreateSubAccountInput) Validate() error
type CustomerAccount ¶
type CustomerAccount interface {
Account
}
CustomerAccount is a Customer specific account
type CustomerAccounts ¶
type CustomerAccounts struct {
FBOAccount CustomerFBOAccount
ReceivableAccount CustomerReceivableAccount
AccruedAccount CustomerAccruedAccount
}
type CustomerAccruedAccount ¶
type CustomerAccruedAccount interface {
CustomerAccount
GetSubAccountForRoute(ctx context.Context, route CustomerAccruedRouteParams) (SubAccount, error)
}
CustomerAccruedAccount is a customer accrued account used as a staging area for usage that has been acknowledged but not yet recognized as earnings.
type CustomerAccruedRouteParams ¶
type CustomerAccruedRouteParams struct {
Currency currencyx.Code
CostBasis *alpacadecimal.Decimal
}
CustomerAccruedRouteParams are routing parameters specific to customer accrued sub-accounts. Routed by currency only for now.
func (CustomerAccruedRouteParams) Route ¶
func (p CustomerAccruedRouteParams) Route() Route
func (CustomerAccruedRouteParams) Validate ¶
func (p CustomerAccruedRouteParams) Validate() error
type CustomerFBOAccount ¶
type CustomerFBOAccount interface {
CustomerAccount
GetSubAccountForRoute(ctx context.Context, route CustomerFBORouteParams) (SubAccount, error)
}
CustomerFBOAccount is a customer FBO account.
type CustomerFBORouteParams ¶
type CustomerFBORouteParams struct {
Currency currencyx.Code
CreditPriority int
TaxCode *string
Features []string
CostBasis *alpacadecimal.Decimal
}
CustomerFBORouteParams are routing parameters specific to customer FBO sub-accounts. CreditPriority is required (non-pointer) — the type system enforces its presence.
func (CustomerFBORouteParams) Route ¶
func (p CustomerFBORouteParams) Route() Route
func (CustomerFBORouteParams) Validate ¶
func (p CustomerFBORouteParams) Validate() error
type CustomerReceivableAccount ¶
type CustomerReceivableAccount interface {
CustomerAccount
GetSubAccountForRoute(ctx context.Context, route CustomerReceivableRouteParams) (SubAccount, error)
}
CustomerReceivableAccount is a customer receivable account.
type CustomerReceivableRouteParams ¶
type CustomerReceivableRouteParams struct {
Currency currencyx.Code
CostBasis *alpacadecimal.Decimal
TransactionAuthorizationStatus TransactionAuthorizationStatus
}
CustomerReceivableRouteParams are routing parameters specific to customer receivable sub-accounts. TransactionAuthorizationStatus is required; callers must explicitly select the open or authorized route.
func (CustomerReceivableRouteParams) Route ¶
func (p CustomerReceivableRouteParams) Route() Route
func (CustomerReceivableRouteParams) Validate ¶
func (p CustomerReceivableRouteParams) Validate() error
type Entry ¶
type Entry interface {
EntryInput
TransactionID() models.NamespacedID
}
type EntryInput ¶
type EntryInput interface {
PostingAddress() PostingAddress
Amount() alpacadecimal.Decimal
}
type Filters ¶
type Filters struct {
// BookedAtPeriod is inclusive-exclusive... should it be? Maybe finally add period inclusivity params?
BookedAtPeriod *timeutil.OpenPeriod
After *TransactionCursor
TransactionID *string
// AccountID narrows the query to a single account via its sub-accounts.
AccountID *string
Route RouteFilter
}
type Ledger ¶
type Ledger interface {
// CommitGroup commits a list of transactions on the Ledger atomically
CommitGroup(ctx context.Context, group TransactionGroupInput) (TransactionGroup, error)
// GetTransactionGroup loads a previously committed transaction group including its transactions.
GetTransactionGroup(ctx context.Context, id models.NamespacedID) (TransactionGroup, error)
// ListTransactions lists transactions on the Ledger according to some filters
//
// TODO: Cursoring gets problematic due to diff between wall_clock and booked_at. It would be convenient to return in order of booked_at as that simplifies parsing. This API will likely change.
ListTransactions(ctx context.Context, params ListTransactionsInput) (ListTransactionsResult, error)
}
type ListAccountsInput ¶
type ListAccountsInput struct {
Namespace string
AccountTypes []AccountType
}
type ListSubAccountsInput ¶
type ListSubAccountsInput struct {
Namespace string
AccountID string
Route RouteFilter
}
type ListTransactionsCreditMovement ¶
type ListTransactionsCreditMovement uint8
const ( ListTransactionsCreditMovementUnspecified ListTransactionsCreditMovement = iota ListTransactionsCreditMovementPositive ListTransactionsCreditMovementNegative )
type ListTransactionsInput ¶
type ListTransactionsInput struct {
Namespace string
Cursor *TransactionCursor
Before *TransactionCursor
Limit int
TransactionID *models.NamespacedID
// AccountIDs scopes the query to transactions with entries on these accounts.
AccountIDs []string
Currency *currencyx.Code
CreditMovement ListTransactionsCreditMovement
// AnnotationFilters matches transactions whose annotations contain all the given key-value pairs.
AnnotationFilters map[string]string
}
func (ListTransactionsInput) Validate ¶
func (i ListTransactionsInput) Validate() error
type ListTransactionsResult ¶
type ListTransactionsResult struct {
Items []Transaction
NextCursor *TransactionCursor
}
type PostingAddress ¶
type PostingAddress interface {
models.Equaler[PostingAddress]
SubAccountID() string
AccountType() AccountType
Route() SubAccountRoute
}
PostingAddress encapsulates an address you can post-against. This is a one-to-one mapping to a SubAccount, this address format exists for routing purposes where the full sub-sccount isn't needed.
type QuerySummedResult ¶
type QuerySummedResult struct {
SettledSum alpacadecimal.Decimal
PendingSum alpacadecimal.Decimal
}
type Route ¶
type Route struct {
Currency currencyx.Code
TaxCode *string
Features []string
CostBasis *alpacadecimal.Decimal
CreditPriority *int
TransactionAuthorizationStatus *TransactionAuthorizationStatus
}
Route holds the literal values that identify a sub-account's routing path. It is used for creation, persistence, and routing key generation.
func (Route) Filter ¶
func (r Route) Filter() RouteFilter
Filter converts a Route to a RouteFilter for use in queries.
type RouteFilter ¶
type RouteFilter struct {
Currency currencyx.Code
// DEFERRED: tax/feature not active yet.
// Non-currency fields are retained for near-future expansion.
TaxCode *string
Features []string
CostBasis mo.Option[*alpacadecimal.Decimal]
// CreditPriority is only meaningful for customer_fbo queries.
CreditPriority *int
// TransactionAuthorizationStatus is currently only meaningful for customer_receivable queries.
// Nil means "do not filter by authorization status", not "open".
TransactionAuthorizationStatus *TransactionAuthorizationStatus
}
RouteFilter is the set of route fields that can be used to filter sub-accounts and query balances.
func (RouteFilter) Normalize ¶
func (f RouteFilter) Normalize() (RouteFilter, error)
Normalize canonicalizes route filter values before querying.
type RoutingKey ¶
type RoutingKey struct {
// contains filtered or unexported fields
}
func BuildRoutingKey ¶
func BuildRoutingKey(version RoutingKeyVersion, route Route) (RoutingKey, error)
func BuildRoutingKeyV1 ¶
func BuildRoutingKeyV1(route Route) (RoutingKey, error)
func NewRoutingKey ¶
func NewRoutingKey(version RoutingKeyVersion, value string) (RoutingKey, error)
func (RoutingKey) Value ¶
func (k RoutingKey) Value() string
func (RoutingKey) Version ¶
func (k RoutingKey) Version() RoutingKeyVersion
type RoutingKeyVersion ¶
type RoutingKeyVersion string
const RoutingKeyVersionV1 RoutingKeyVersion = "v1"
func (RoutingKeyVersion) Validate ¶
func (v RoutingKeyVersion) Validate() error
type RoutingValidator ¶
type RoutingValidator interface {
ValidateEntries(entries []EntryInput) error
}
type SubAccount ¶
type SubAccount interface {
// Returns the address of the sub-account
Address() PostingAddress
// AccountID returns the identifier of the parent account.
AccountID() models.NamespacedID
// Route returns the routing values of the sub-account.
Route() Route
}
SubAccount is an actual address you can post against. It has all required routing information provided. Accounts describe ownership and purpose while SubAccounts parameterize the actual posting address.
type SubAccountRoute ¶
type SubAccountRoute struct {
// contains filtered or unexported fields
}
func NewSubAccountRouteFromData ¶
func NewSubAccountRouteFromData(id string, key RoutingKey, route Route) (SubAccountRoute, error)
NewSubAccountRouteFromData hydrates a sub-account route from persisted data. Does not enforce Route & RoutingKey equality due to possible version mismatch
func NewSubAccountRouteFromRoute ¶
func NewSubAccountRouteFromRoute(id string, version RoutingKeyVersion, route Route) (SubAccountRoute, error)
NewSubAccountRouteFromRoute creates a new sub-account route from a literal route
func (SubAccountRoute) ID ¶
func (r SubAccountRoute) ID() string
func (SubAccountRoute) Route ¶
func (r SubAccountRoute) Route() Route
func (SubAccountRoute) RoutingKey ¶
func (r SubAccountRoute) RoutingKey() RoutingKey
type Transaction ¶
type Transaction interface {
Cursor() TransactionCursor
BookedAt() time.Time
Entries() []Entry
ID() models.NamespacedID
Annotations() models.Annotations
}
Transaction represents a list of entries booked at the same time
type TransactionAuthorizationStatus ¶
type TransactionAuthorizationStatus string
const ( TransactionAuthorizationStatusOpen TransactionAuthorizationStatus = "open" TransactionAuthorizationStatusAuthorized TransactionAuthorizationStatus = "authorized" )
func (TransactionAuthorizationStatus) Validate ¶
func (s TransactionAuthorizationStatus) Validate() error
type TransactionCursor ¶
func (TransactionCursor) Compare ¶
func (c TransactionCursor) Compare(other TransactionCursor) int
Compare returns cursor ordering by BookedAt, then CreatedAt, then ID. It returns -1 if c < other, 0 if equal, and 1 if c > other.
func (TransactionCursor) Validate ¶
func (c TransactionCursor) Validate() error
type TransactionDirection ¶
type TransactionDirection string
const ( TransactionDirectionForward TransactionDirection = "forward" TransactionDirectionCorrection TransactionDirection = "correction" )
func TransactionDirectionFromAnnotations ¶
func TransactionDirectionFromAnnotations(annotations models.Annotations) (TransactionDirection, error)
type TransactionGroup ¶
type TransactionGroup interface {
ID() models.NamespacedID
Transactions() []Transaction
Annotations() models.Annotations
}
TransactionGroup represents a group of transactions written to the ledger at the same time
type TransactionGroupInput ¶
type TransactionGroupInput interface {
Namespace() string
Transactions() []TransactionInput
Annotations() models.Annotations
}
type TransactionInput ¶
type TransactionInput interface {
BookedAt() time.Time
EntryInputs() []EntryInput
Annotations() models.Annotations
AsGroupInput(namespace string, annotations models.Annotations) TransactionGroupInput
}