pkg update
This commit is contained in:
117
api/pkg/model/account_role.go
Normal file
117
api/pkg/model/account_role.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
accountrolev1 "github.com/tech/sendico/pkg/proto/common/account_role/v1"
|
||||
)
|
||||
|
||||
type AccountRole string
|
||||
|
||||
const (
|
||||
AccountRoleOperating AccountRole = "operating"
|
||||
AccountRoleHold AccountRole = "hold"
|
||||
AccountRoleTransit AccountRole = "transit"
|
||||
AccountRoleSettlement AccountRole = "settlement"
|
||||
AccountRoleClearing AccountRole = "clearing"
|
||||
AccountRolePending AccountRole = "pending"
|
||||
AccountRoleReserve AccountRole = "reserve"
|
||||
AccountRoleLiquidity AccountRole = "liquidity"
|
||||
AccountRoleFee AccountRole = "fee"
|
||||
AccountRoleChargeback AccountRole = "chargeback"
|
||||
AccountRoleAdjustment AccountRole = "adjustment"
|
||||
)
|
||||
|
||||
const (
|
||||
MetadataKeyFromRole = "from_role"
|
||||
MetadataKeyToRole = "to_role"
|
||||
)
|
||||
|
||||
func Parse(value string) (AccountRole, bool) {
|
||||
switch strings.ToUpper(strings.TrimSpace(value)) {
|
||||
case "ACCOUNT_ROLE_OPERATING", "OPERATING":
|
||||
return AccountRoleOperating, true
|
||||
case "ACCOUNT_ROLE_HOLD", "HOLD":
|
||||
return AccountRoleHold, true
|
||||
case "ACCOUNT_ROLE_TRANSIT", "TRANSIT":
|
||||
return AccountRoleTransit, true
|
||||
case "ACCOUNT_ROLE_SETTLEMENT", "SETTLEMENT":
|
||||
return AccountRoleSettlement, true
|
||||
case "ACCOUNT_ROLE_CLEARING", "CLEARING":
|
||||
return AccountRoleClearing, true
|
||||
case "ACCOUNT_ROLE_PENDING", "PENDING":
|
||||
return AccountRolePending, true
|
||||
case "ACCOUNT_ROLE_RESERVE", "RESERVE":
|
||||
return AccountRoleReserve, true
|
||||
case "ACCOUNT_ROLE_LIQUIDITY", "LIQUIDITY":
|
||||
return AccountRoleLiquidity, true
|
||||
case "ACCOUNT_ROLE_FEE", "FEE":
|
||||
return AccountRoleFee, true
|
||||
case "ACCOUNT_ROLE_CHARGEBACK", "CHARGEBACK":
|
||||
return AccountRoleChargeback, true
|
||||
case "ACCOUNT_ROLE_ADJUSTMENT", "ADJUSTMENT":
|
||||
return AccountRoleAdjustment, true
|
||||
case "ACCOUNT_ROLE_UNSPECIFIED", "UNSPECIFIED", "":
|
||||
return "", true
|
||||
default:
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
|
||||
func ToProto(role AccountRole) accountrolev1.AccountRole {
|
||||
switch role {
|
||||
case AccountRoleOperating:
|
||||
return accountrolev1.AccountRole_OPERATING
|
||||
case AccountRoleHold:
|
||||
return accountrolev1.AccountRole_HOLD
|
||||
case AccountRoleTransit:
|
||||
return accountrolev1.AccountRole_TRANSIT
|
||||
case AccountRoleSettlement:
|
||||
return accountrolev1.AccountRole_SETTLEMENT
|
||||
case AccountRoleClearing:
|
||||
return accountrolev1.AccountRole_CLEARING
|
||||
case AccountRolePending:
|
||||
return accountrolev1.AccountRole_PENDING
|
||||
case AccountRoleReserve:
|
||||
return accountrolev1.AccountRole_RESERVE
|
||||
case AccountRoleLiquidity:
|
||||
return accountrolev1.AccountRole_LIQUIDITY
|
||||
case AccountRoleFee:
|
||||
return accountrolev1.AccountRole_FEE
|
||||
case AccountRoleChargeback:
|
||||
return accountrolev1.AccountRole_CHARGEBACK
|
||||
case AccountRoleAdjustment:
|
||||
return accountrolev1.AccountRole_ADJUSTMENT
|
||||
default:
|
||||
return accountrolev1.AccountRole_ACCOUNT_ROLE_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func FromProto(role accountrolev1.AccountRole) AccountRole {
|
||||
switch role {
|
||||
case accountrolev1.AccountRole_OPERATING:
|
||||
return AccountRoleOperating
|
||||
case accountrolev1.AccountRole_HOLD:
|
||||
return AccountRoleHold
|
||||
case accountrolev1.AccountRole_TRANSIT:
|
||||
return AccountRoleTransit
|
||||
case accountrolev1.AccountRole_SETTLEMENT:
|
||||
return AccountRoleSettlement
|
||||
case accountrolev1.AccountRole_CLEARING:
|
||||
return AccountRoleClearing
|
||||
case accountrolev1.AccountRole_PENDING:
|
||||
return AccountRolePending
|
||||
case accountrolev1.AccountRole_RESERVE:
|
||||
return AccountRoleReserve
|
||||
case accountrolev1.AccountRole_LIQUIDITY:
|
||||
return AccountRoleLiquidity
|
||||
case accountrolev1.AccountRole_FEE:
|
||||
return AccountRoleFee
|
||||
case accountrolev1.AccountRole_CHARGEBACK:
|
||||
return AccountRoleChargeback
|
||||
case accountrolev1.AccountRole_ADJUSTMENT:
|
||||
return AccountRoleAdjustment
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,93 @@
|
||||
package model
|
||||
|
||||
import "strings"
|
||||
|
||||
// ChainNetwork identifies a blockchain network for routing and discovery.
|
||||
type ChainNetwork string
|
||||
|
||||
const (
|
||||
ChainNetworkARB ChainNetwork = "arbitrum_one"
|
||||
ChainNetworkEthMain ChainNetwork = "ethereum_mainnet"
|
||||
ChainNetworkTronMain ChainNetwork = "tron_mainnet"
|
||||
ChainNetworkTronNile ChainNetwork = "tron_nile"
|
||||
ChainNetworkUnspecified ChainNetwork = "unspecified"
|
||||
ChainNetworkArbitrumOne ChainNetwork = "arbitrum_one"
|
||||
ChainNetworkArbitrumSepolia ChainNetwork = "arbitrum_sepolia"
|
||||
ChainNetworkEthereumMainnet ChainNetwork = "ethereum_mainnet"
|
||||
ChainNetworkTronMainnet ChainNetwork = "tron_mainnet"
|
||||
ChainNetworkTronNile ChainNetwork = "tron_nile"
|
||||
ChainNetworkUnspecified ChainNetwork = ""
|
||||
)
|
||||
|
||||
// AllChainNetworks returns all valid chain networks.
|
||||
func AllChainNetworks() []ChainNetwork {
|
||||
return []ChainNetwork{
|
||||
ChainNetworkArbitrumOne,
|
||||
ChainNetworkEthereumMainnet,
|
||||
ChainNetworkTronMainnet,
|
||||
ChainNetworkTronNile,
|
||||
}
|
||||
}
|
||||
|
||||
// ParseChainNetwork parses a string into a ChainNetwork.
|
||||
// Returns the network and true if valid, or empty and false if invalid.
|
||||
func ParseChainNetwork(value string) (ChainNetwork, bool) {
|
||||
v := strings.ToLower(strings.TrimSpace(value))
|
||||
switch v {
|
||||
case "arbitrum_one", "arbitrum", "arb":
|
||||
return ChainNetworkArbitrumOne, true
|
||||
case "ethereum_mainnet", "ethereum", "eth":
|
||||
return ChainNetworkEthereumMainnet, true
|
||||
case "tron_mainnet", "tron":
|
||||
return ChainNetworkTronMainnet, true
|
||||
case "tron_nile", "nile":
|
||||
return ChainNetworkTronNile, true
|
||||
case "unspecified", "":
|
||||
return ChainNetworkUnspecified, true
|
||||
default:
|
||||
return ChainNetworkUnspecified, false
|
||||
}
|
||||
}
|
||||
|
||||
// String returns the string representation of the network.
|
||||
func (n ChainNetwork) String() string {
|
||||
return string(n)
|
||||
}
|
||||
|
||||
// IsValid returns true if the network is a known valid network.
|
||||
func (n ChainNetwork) IsValid() bool {
|
||||
switch n {
|
||||
case ChainNetworkArbitrumOne,
|
||||
ChainNetworkEthereumMainnet,
|
||||
ChainNetworkTronMainnet,
|
||||
ChainNetworkTronNile:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// IsTron returns true if the network is a TRON network.
|
||||
func (n ChainNetwork) IsTron() bool {
|
||||
switch n {
|
||||
case ChainNetworkTronMainnet, ChainNetworkTronNile:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// IsEVM returns true if the network is an EVM-compatible network.
|
||||
func (n ChainNetwork) IsEVM() bool {
|
||||
switch n {
|
||||
case ChainNetworkArbitrumOne, ChainNetworkEthereumMainnet:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// IsTestnet returns true if the network is a testnet.
|
||||
func (n ChainNetwork) IsTestnet() bool {
|
||||
switch n {
|
||||
case ChainNetworkTronNile:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
131
api/pkg/model/ledger.go
Normal file
131
api/pkg/model/ledger.go
Normal file
@@ -0,0 +1,131 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/tech/sendico/pkg/db/storable"
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
"github.com/tech/sendico/pkg/mservice"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
// AccountType defines the category of account (asset, liability, revenue, expense).
|
||||
type LedgerAccountType string
|
||||
|
||||
const (
|
||||
LedgerAccountTypeAsset LedgerAccountType = "asset"
|
||||
LedgerAccountTypeLiability LedgerAccountType = "liability"
|
||||
LedgerAccountTypeRevenue LedgerAccountType = "revenue"
|
||||
LedgerAccountTypeExpense LedgerAccountType = "expense"
|
||||
)
|
||||
|
||||
// AccountStatus tracks the operational state of an account.
|
||||
type LedgerAccountStatus string
|
||||
|
||||
const (
|
||||
LedgerAccountStatusActive LedgerAccountStatus = "active"
|
||||
LedgerAccountStatusFrozen LedgerAccountStatus = "frozen"
|
||||
LedgerAccountStatusClosed LedgerAccountStatus = "closed"
|
||||
)
|
||||
|
||||
type LedgerAccountScope string
|
||||
|
||||
const (
|
||||
LedgerAccountScopeOrganization LedgerAccountScope = "organization"
|
||||
LedgerAccountScopeSystem LedgerAccountScope = "system"
|
||||
)
|
||||
|
||||
type SystemAccountPurpose string
|
||||
|
||||
const (
|
||||
SystemAccountPurposeExternalSource SystemAccountPurpose = "external_source"
|
||||
SystemAccountPurposeExternalSink SystemAccountPurpose = "external_sink"
|
||||
)
|
||||
|
||||
// Account represents a ledger account that holds balances for a specific currency.
|
||||
type LedgerAccount struct {
|
||||
storable.Base `bson:",inline" json:",inline"`
|
||||
Describable `bson:",inline" json:",inline"`
|
||||
|
||||
// Scope defines whether the account belongs to an organization
|
||||
// or is a system-level ledger account used for internal accounting.
|
||||
Scope LedgerAccountScope `bson:"scope" json:"scope"`
|
||||
|
||||
// SystemPurpose specifies the role of a system-scoped account
|
||||
// (e.g., external source or sink of funds). Must be set for system accounts
|
||||
// and must be nil for organization accounts.
|
||||
SystemPurpose *SystemAccountPurpose `bson:"systemPurpose,omitempty" json:"systemPurpose,omitempty"`
|
||||
|
||||
// OrganizationRef links the account to an organization.
|
||||
// Must be set for organization accounts and nil for system accounts.
|
||||
OrganizationRef *primitive.ObjectID `bson:"organizationRef,omitempty" json:"organizationRef,omitempty"`
|
||||
|
||||
// Role defines the functional purpose of the account within an organization
|
||||
// (e.g., pending, operating, settlement, hold, etc.).
|
||||
// Must be set for organization accounts and omitted for system accounts.
|
||||
Role AccountRole `bson:"role,omitempty" json:"role,omitempty"`
|
||||
|
||||
// AccountCode is a logical classification code of the account
|
||||
// (e.g., "asset:cash:usd") used for reporting and grouping.
|
||||
AccountCode string `bson:"accountCode" json:"accountCode"`
|
||||
|
||||
// Currency is the ISO 4217 currency code the account operates in.
|
||||
Currency string `bson:"currency" json:"currency"`
|
||||
|
||||
// AccountType defines the accounting category of the account
|
||||
// (asset, liability, revenue, expense).
|
||||
AccountType LedgerAccountType `bson:"accountType" json:"accountType"`
|
||||
|
||||
// Status represents the operational state of the account.
|
||||
Status LedgerAccountStatus `bson:"status" json:"status"`
|
||||
|
||||
// AllowNegative defines whether the account is allowed to have
|
||||
// a negative balance (used for system control accounts).
|
||||
AllowNegative bool `bson:"allowNegative" json:"allowNegative"`
|
||||
|
||||
// OwnerRef optionally links the account to a specific owner entity
|
||||
// (e.g., user or sub-entity within the organization).
|
||||
OwnerRef *primitive.ObjectID `bson:"ownerRef,omitempty" json:"ownerRef,omitempty"`
|
||||
|
||||
// Metadata holds additional arbitrary key-value attributes.
|
||||
Metadata map[string]string `bson:"metadata,omitempty" json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
// Collection implements storable.Storable.
|
||||
func (*LedgerAccount) Collection() string {
|
||||
return mservice.LedgerAccounts
|
||||
}
|
||||
|
||||
// Validate enforces scope-specific invariants for ledger accounts.
|
||||
func (a *LedgerAccount) Validate() error {
|
||||
if a == nil {
|
||||
return merrors.InvalidArgument("ledger account is required")
|
||||
}
|
||||
|
||||
switch a.Scope {
|
||||
case LedgerAccountScopeOrganization:
|
||||
if a.OrganizationRef == nil || a.OrganizationRef.IsZero() {
|
||||
return merrors.InvalidArgument("organization_ref is required for organization accounts")
|
||||
}
|
||||
if strings.TrimSpace(string(a.Role)) == "" {
|
||||
return merrors.InvalidArgument("role is required for organization accounts")
|
||||
}
|
||||
if a.SystemPurpose != nil {
|
||||
return merrors.InvalidArgument("system_purpose must be nil for organization accounts")
|
||||
}
|
||||
case LedgerAccountScopeSystem:
|
||||
if a.OrganizationRef != nil && !a.OrganizationRef.IsZero() {
|
||||
return merrors.InvalidArgument("organization_ref must be nil for system accounts")
|
||||
}
|
||||
if strings.TrimSpace(string(a.Role)) != "" {
|
||||
return merrors.InvalidArgument("role must be empty for system accounts")
|
||||
}
|
||||
if a.SystemPurpose == nil {
|
||||
return merrors.InvalidArgument("system_purpose is required for system accounts")
|
||||
}
|
||||
default:
|
||||
return merrors.InvalidArgument("scope is required")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user