pkg update
This commit is contained in:
1
api/payments/orchestrator/.gitignore
vendored
1
api/payments/orchestrator/.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
internal/generated
|
internal/generated
|
||||||
.gocache
|
.gocache
|
||||||
app
|
app
|
||||||
|
tmp
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package grpcimp
|
package grpcimp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -59,23 +58,7 @@ func (c *Config) DiscoveryInvokeURI() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("%s://%s:%s", c.discoveryScheme(), host, addrPort)
|
return net.JoinHostPort(host, addrPort)
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) discoveryScheme() string {
|
|
||||||
scheme := strings.TrimSpace(c.AdvertiseScheme)
|
|
||||||
if envKey := strings.TrimSpace(c.AdvertiseSchemeEnv); envKey != "" {
|
|
||||||
if value := strings.TrimSpace(os.Getenv(envKey)); value != "" {
|
|
||||||
scheme = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if scheme != "" {
|
|
||||||
return scheme
|
|
||||||
}
|
|
||||||
if c != nil && c.TLS != nil && strings.TrimSpace(c.TLS.CertFile) != "" && strings.TrimSpace(c.TLS.KeyFile) != "" {
|
|
||||||
return "grpcs"
|
|
||||||
}
|
|
||||||
return "grpc"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func splitHostPort(address string) (string, string) {
|
func splitHostPort(address string) (string, string) {
|
||||||
|
|||||||
@@ -166,5 +166,5 @@ func DefaultInvokeURI(service string) string {
|
|||||||
if clean == "" {
|
if clean == "" {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return "grpc://" + clean
|
return clean
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,10 +40,10 @@ func announcementFields(announce Announcement) []zap.Field {
|
|||||||
fields = append(fields, zap.Int("currencies", len(announce.Currencies)))
|
fields = append(fields, zap.Int("currencies", len(announce.Currencies)))
|
||||||
}
|
}
|
||||||
if announce.Health.IntervalSec > 0 {
|
if announce.Health.IntervalSec > 0 {
|
||||||
fields = append(fields, zap.Int("interval_sec", announce.Health.IntervalSec))
|
fields = append(fields, zap.Int("interval_seconds", announce.Health.IntervalSec))
|
||||||
}
|
}
|
||||||
if announce.Health.TimeoutSec > 0 {
|
if announce.Health.TimeoutSec > 0 {
|
||||||
fields = append(fields, zap.Int("timeout_sec", announce.Health.TimeoutSec))
|
fields = append(fields, zap.Int("timeout_seconds", announce.Health.TimeoutSec))
|
||||||
}
|
}
|
||||||
return fields
|
return fields
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,6 +93,6 @@ require (
|
|||||||
golang.org/x/sys v0.40.0 // indirect
|
golang.org/x/sys v0.40.0 // indirect
|
||||||
golang.org/x/text v0.33.0 // indirect
|
golang.org/x/text v0.33.0 // indirect
|
||||||
golang.org/x/time v0.5.0 // indirect
|
golang.org/x/time v0.5.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260122232226-8e98ce8d340d // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -269,8 +269,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
|||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20251029180050-ab9386a59fda h1:+2XxjfsAu6vqFxwGBRcHiMaDCuZiqXGDUDVWVtrFAnE=
|
google.golang.org/genproto/googleapis/api v0.0.0-20251029180050-ab9386a59fda h1:+2XxjfsAu6vqFxwGBRcHiMaDCuZiqXGDUDVWVtrFAnE=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20251029180050-ab9386a59fda/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo=
|
google.golang.org/genproto/googleapis/api v0.0.0-20251029180050-ab9386a59fda/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260122232226-8e98ce8d340d h1:xXzuihhT3gL/ntduUZwHECzAn57E8dA6l8SOtYWdD8Q=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 h1:H86B94AW+VfJWDqFeEbBPhEtHzJwJfTbgE2lZa54ZAQ=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260122232226-8e98ce8d340d/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
|
|||||||
@@ -36,6 +36,37 @@ func ParseAccountStatus(value string) (ledgerv1.AccountStatus, bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ParseAccountRole(value string) (ledgerv1.AccountRole, bool) {
|
||||||
|
switch strings.ToUpper(strings.TrimSpace(value)) {
|
||||||
|
case "ACCOUNT_ROLE_OPERATING", "OPERATING":
|
||||||
|
return ledgerv1.AccountRole_ACCOUNT_ROLE_OPERATING, true
|
||||||
|
case "ACCOUNT_ROLE_HOLD", "HOLD":
|
||||||
|
return ledgerv1.AccountRole_ACCOUNT_ROLE_HOLD, true
|
||||||
|
case "ACCOUNT_ROLE_TRANSIT", "TRANSIT":
|
||||||
|
return ledgerv1.AccountRole_ACCOUNT_ROLE_TRANSIT, true
|
||||||
|
case "ACCOUNT_ROLE_SETTLEMENT", "SETTLEMENT":
|
||||||
|
return ledgerv1.AccountRole_ACCOUNT_ROLE_SETTLEMENT, true
|
||||||
|
case "ACCOUNT_ROLE_CLEARING", "CLEARING":
|
||||||
|
return ledgerv1.AccountRole_ACCOUNT_ROLE_CLEARING, true
|
||||||
|
case "ACCOUNT_ROLE_PENDING", "PENDING":
|
||||||
|
return ledgerv1.AccountRole_ACCOUNT_ROLE_PENDING, true
|
||||||
|
case "ACCOUNT_ROLE_RESERVE", "RESERVE":
|
||||||
|
return ledgerv1.AccountRole_ACCOUNT_ROLE_RESERVE, true
|
||||||
|
case "ACCOUNT_ROLE_LIQUIDITY", "LIQUIDITY":
|
||||||
|
return ledgerv1.AccountRole_ACCOUNT_ROLE_LIQUIDITY, true
|
||||||
|
case "ACCOUNT_ROLE_FEE", "FEE":
|
||||||
|
return ledgerv1.AccountRole_ACCOUNT_ROLE_FEE, true
|
||||||
|
case "ACCOUNT_ROLE_CHARGEBACK", "CHARGEBACK":
|
||||||
|
return ledgerv1.AccountRole_ACCOUNT_ROLE_CHARGEBACK, true
|
||||||
|
case "ACCOUNT_ROLE_ADJUSTMENT", "ADJUSTMENT":
|
||||||
|
return ledgerv1.AccountRole_ACCOUNT_ROLE_ADJUSTMENT, true
|
||||||
|
case "ACCOUNT_ROLE_UNSPECIFIED", "UNSPECIFIED", "":
|
||||||
|
return ledgerv1.AccountRole_ACCOUNT_ROLE_UNSPECIFIED, true
|
||||||
|
default:
|
||||||
|
return ledgerv1.AccountRole_ACCOUNT_ROLE_UNSPECIFIED, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func IsAccountTypeUnspecified(value string) bool {
|
func IsAccountTypeUnspecified(value string) bool {
|
||||||
switch strings.ToUpper(strings.TrimSpace(value)) {
|
switch strings.ToUpper(strings.TrimSpace(value)) {
|
||||||
case "", "ACCOUNT_TYPE_UNSPECIFIED", "UNSPECIFIED":
|
case "", "ACCOUNT_TYPE_UNSPECIFIED", "UNSPECIFIED":
|
||||||
@@ -53,3 +84,12 @@ func IsAccountStatusUnspecified(value string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsAccountRoleUnspecified(value string) bool {
|
||||||
|
switch strings.ToUpper(strings.TrimSpace(value)) {
|
||||||
|
case "", "ACCOUNT_ROLE_UNSPECIFIED", "UNSPECIFIED":
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
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
|
package model
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
// ChainNetwork identifies a blockchain network for routing and discovery.
|
||||||
type ChainNetwork string
|
type ChainNetwork string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ChainNetworkARB ChainNetwork = "arbitrum_one"
|
ChainNetworkArbitrumOne ChainNetwork = "arbitrum_one"
|
||||||
ChainNetworkEthMain ChainNetwork = "ethereum_mainnet"
|
ChainNetworkArbitrumSepolia ChainNetwork = "arbitrum_sepolia"
|
||||||
ChainNetworkTronMain ChainNetwork = "tron_mainnet"
|
ChainNetworkEthereumMainnet ChainNetwork = "ethereum_mainnet"
|
||||||
|
ChainNetworkTronMainnet ChainNetwork = "tron_mainnet"
|
||||||
ChainNetworkTronNile ChainNetwork = "tron_nile"
|
ChainNetworkTronNile ChainNetwork = "tron_nile"
|
||||||
ChainNetworkUnspecified ChainNetwork = "unspecified"
|
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
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@ const (
|
|||||||
PaymentGateway Type = "payment_gateway" // Represents payment gateway microservice
|
PaymentGateway Type = "payment_gateway" // Represents payment gateway microservice
|
||||||
FXOracle Type = "fx_oracle" // Represents FX oracle microservice
|
FXOracle Type = "fx_oracle" // Represents FX oracle microservice
|
||||||
FeePlans Type = "fee_plans" // Represents fee plans microservice
|
FeePlans Type = "fee_plans" // Represents fee plans microservice
|
||||||
|
BillingDocuments Type = "billing_documents" // Represents billing documents microservice
|
||||||
FilterProjects Type = "filter_projects" // Represents comments on tasks or other resources
|
FilterProjects Type = "filter_projects" // Represents comments on tasks or other resources
|
||||||
Invitations Type = "invitations" // Represents invitations sent to users
|
Invitations Type = "invitations" // Represents invitations sent to users
|
||||||
Invoices Type = "invoices" // Represents invoices
|
Invoices Type = "invoices" // Represents invoices
|
||||||
@@ -55,7 +56,7 @@ const (
|
|||||||
func StringToSType(s string) (Type, error) {
|
func StringToSType(s string) (Type, error) {
|
||||||
switch Type(s) {
|
switch Type(s) {
|
||||||
case Accounts, Confirmations, Amplitude, Site, Changes, Clients, ChainGateway, ChainWallets, ChainWalletBalances,
|
case Accounts, Confirmations, Amplitude, Site, Changes, Clients, ChainGateway, ChainWallets, ChainWalletBalances,
|
||||||
ChainTransfers, ChainDeposits, MntxGateway, PaymentGateway, FXOracle, FeePlans, FilterProjects, Invitations, Invoices, Logo, Ledger,
|
ChainTransfers, ChainDeposits, MntxGateway, PaymentGateway, FXOracle, FeePlans, BillingDocuments, FilterProjects, Invitations, Invoices, Logo, Ledger,
|
||||||
LedgerAccounts, LedgerBalances, LedgerEntries, LedgerOutbox, LedgerParties, LedgerPlines, Notifications,
|
LedgerAccounts, LedgerBalances, LedgerEntries, LedgerOutbox, LedgerParties, LedgerPlines, Notifications,
|
||||||
Organizations, Payments, PaymentRoutes, PaymentPlanTemplates, PaymentOrchestrator, Permissions, Policies, PolicyAssignements,
|
Organizations, Payments, PaymentRoutes, PaymentPlanTemplates, PaymentOrchestrator, Permissions, Policies, PolicyAssignements,
|
||||||
RefreshTokens, Roles, Storage, Tenants, Workflows, Discovery:
|
RefreshTokens, Roles, Storage, Tenants, Workflows, Discovery:
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package rail
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"github.com/tech/sendico/pkg/model"
|
||||||
paymenttypes "github.com/tech/sendico/pkg/payments/types"
|
paymenttypes "github.com/tech/sendico/pkg/payments/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -49,6 +50,8 @@ type TransferRequest struct {
|
|||||||
Metadata map[string]string
|
Metadata map[string]string
|
||||||
ClientReference string
|
ClientReference string
|
||||||
DestinationMemo string
|
DestinationMemo string
|
||||||
|
FromRole model.AccountRole
|
||||||
|
ToRole model.AccountRole
|
||||||
}
|
}
|
||||||
|
|
||||||
// BlockRequest defines the inputs for reserving value through a rail gateway.
|
// BlockRequest defines the inputs for reserving value through a rail gateway.
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ type LedgerTx struct {
|
|||||||
FromRail string
|
FromRail string
|
||||||
ToRail string
|
ToRail string
|
||||||
ExternalReferenceID string
|
ExternalReferenceID string
|
||||||
|
Operation string
|
||||||
FXRateUsed string
|
FXRateUsed string
|
||||||
IdempotencyKey string
|
IdempotencyKey string
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
|
|||||||
Reference in New Issue
Block a user