refactored payment orchestration

This commit is contained in:
Stephan D
2026-02-03 00:40:46 +01:00
parent 05d998e0f7
commit 5e87e2f2f9
184 changed files with 3920 additions and 2219 deletions

View File

@@ -138,5 +138,5 @@ require (
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.40.0 // indirect
golang.org/x/text v0.33.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260202165425-ce8ad4cf556b // indirect
)

View File

@@ -363,8 +363,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=
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/rpc v0.0.0-20260128011058-8636f8732409 h1:H86B94AW+VfJWDqFeEbBPhEtHzJwJfTbgE2lZa54ZAQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260202165425-ce8ad4cf556b h1:GZxXGdFaHX27ZSMHudWc4FokdD+xl8BC2UJm1OVIEzs=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260202165425-ce8ad4cf556b/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
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/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=

View File

@@ -6,6 +6,7 @@ import (
"github.com/tech/sendico/pkg/ledgerconv"
"github.com/tech/sendico/pkg/merrors"
"github.com/tech/sendico/pkg/model"
"github.com/tech/sendico/pkg/model/account_role"
"go.mongodb.org/mongo-driver/v2/bson"
)
@@ -28,13 +29,13 @@ const (
)
type CreateLedgerAccount struct {
AccountType LedgerAccountType `json:"accountType"`
Currency string `json:"currency"`
AllowNegative bool `json:"allowNegative,omitempty"`
Role model.AccountRole `json:"role"`
Describable model.Describable `json:"describable"`
OwnerRef *bson.ObjectID `json:"ownerRef,omitempty"`
Metadata map[string]string `json:"metadata,omitempty"`
AccountType LedgerAccountType `json:"accountType"`
Currency string `json:"currency"`
AllowNegative bool `json:"allowNegative,omitempty"`
Role account_role.AccountRole `json:"role"`
Describable model.Describable `json:"describable"`
OwnerRef *bson.ObjectID `json:"ownerRef,omitempty"`
Metadata map[string]string `json:"metadata,omitempty"`
}
func (r *CreateLedgerAccount) Validate() error {

View File

@@ -4,19 +4,19 @@ import (
"strings"
"github.com/tech/sendico/pkg/merrors"
"github.com/tech/sendico/pkg/model"
paymenttypes "github.com/tech/sendico/pkg/payments/types"
)
type PaymentIntent struct {
Kind PaymentKind `json:"kind,omitempty"`
Source *Endpoint `json:"source,omitempty"`
Destination *Endpoint `json:"destination,omitempty"`
Amount *model.Money `json:"amount,omitempty"`
FX *FXIntent `json:"fx,omitempty"`
SettlementMode SettlementMode `json:"settlement_mode,omitempty"`
SettlementCurrency string `json:"settlement_currency,omitempty"`
Attributes map[string]string `json:"attributes,omitempty"`
Customer *Customer `json:"customer,omitempty"`
Kind PaymentKind `json:"kind,omitempty"`
Source *Endpoint `json:"source,omitempty"`
Destination *Endpoint `json:"destination,omitempty"`
Amount *paymenttypes.Money `json:"amount,omitempty"`
FX *FXIntent `json:"fx,omitempty"`
SettlementMode SettlementMode `json:"settlement_mode,omitempty"`
SettlementCurrency string `json:"settlement_currency,omitempty"`
Attributes map[string]string `json:"attributes,omitempty"`
Customer *Customer `json:"customer,omitempty"`
}
type AssetResolverStub struct{}

View File

@@ -6,7 +6,7 @@ import (
"strings"
"testing"
"github.com/tech/sendico/pkg/model"
paymenttypes "github.com/tech/sendico/pkg/payments/types"
)
func TestEndpointDTOBuildersAndDecoders(t *testing.T) {
@@ -255,7 +255,7 @@ func TestPaymentIntentJSONRoundTrip(t *testing.T) {
Kind: PaymentKindPayout,
Source: &source,
Destination: &dest,
Amount: &model.Money{Amount: "10", Currency: "USD"},
Amount: &paymenttypes.Money{Amount: "10", Currency: "USD"},
FX: &FXIntent{
Pair: &CurrencyPair{Base: "USD", Quote: "EUR"},
Side: FXSideBuyBaseSellQuote,
@@ -324,7 +324,7 @@ func TestPaymentIntentMinimalRoundTrip(t *testing.T) {
Kind: PaymentKindInternalTransfer,
Source: &source,
Destination: &dest,
Amount: &model.Money{Amount: "1", Currency: "USD"},
Amount: &paymenttypes.Money{Amount: "1", Currency: "USD"},
}
data, err := json.Marshal(intent)

View File

@@ -6,7 +6,7 @@ import (
"github.com/shopspring/decimal"
"github.com/tech/sendico/pkg/merrors"
"github.com/tech/sendico/pkg/model"
paymenttypes "github.com/tech/sendico/pkg/payments/types"
)
// AssetResolver defines environment-specific supported assets.
@@ -50,7 +50,7 @@ func ValidateCurrency(cur string, assetResolver AssetResolver) error {
return nil
}
func ValidateMoney(m *model.Money, assetResolver AssetResolver) error {
func ValidateMoney(m *paymenttypes.Money, assetResolver AssetResolver) error {
if m == nil {
return merrors.InvalidArgument("money is required", "intent.amount")
}

View File

@@ -1,25 +1,25 @@
package sresponse
import (
"github.com/tech/sendico/pkg/model"
paymenttypes "github.com/tech/sendico/pkg/payments/types"
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
)
func toMoney(m *moneyv1.Money) *model.Money {
func toMoney(m *moneyv1.Money) *paymenttypes.Money {
if m == nil {
return nil
}
return &model.Money{
return &paymenttypes.Money{
Amount: m.GetAmount(),
Currency: m.GetCurrency(),
}
}
func toMoneyList(list []*moneyv1.Money) []*model.Money {
func toMoneyList(list []*moneyv1.Money) []*paymenttypes.Money {
if len(list) == 0 {
return nil
}
result := make([]*model.Money, 0, len(list))
result := make([]*paymenttypes.Money, 0, len(list))
for _, item := range list {
if m := toMoney(item); m != nil {
result = append(result, m)

View File

@@ -5,7 +5,7 @@ import (
"github.com/tech/sendico/pkg/api/http/response"
"github.com/tech/sendico/pkg/mlogger"
"github.com/tech/sendico/pkg/model"
paymenttypes "github.com/tech/sendico/pkg/payments/types"
feesv1 "github.com/tech/sendico/pkg/proto/billing/fees/v1"
paginationv1 "github.com/tech/sendico/pkg/proto/common/pagination/v1"
oraclev1 "github.com/tech/sendico/pkg/proto/oracle/v1"
@@ -13,40 +13,40 @@ import (
)
type FeeLine struct {
LedgerAccountRef string `json:"ledgerAccountRef,omitempty"`
Amount *model.Money `json:"amount,omitempty"`
LineType string `json:"lineType,omitempty"`
Side string `json:"side,omitempty"`
Meta map[string]string `json:"meta,omitempty"`
LedgerAccountRef string `json:"ledgerAccountRef,omitempty"`
Amount *paymenttypes.Money `json:"amount,omitempty"`
LineType string `json:"lineType,omitempty"`
Side string `json:"side,omitempty"`
Meta map[string]string `json:"meta,omitempty"`
}
type FxQuote struct {
QuoteRef string `json:"quoteRef,omitempty"`
BaseCurrency string `json:"baseCurrency,omitempty"`
QuoteCurrency string `json:"quoteCurrency,omitempty"`
Side string `json:"side,omitempty"`
Price string `json:"price,omitempty"`
BaseAmount *model.Money `json:"baseAmount,omitempty"`
QuoteAmount *model.Money `json:"quoteAmount,omitempty"`
ExpiresAtUnixMs int64 `json:"expiresAtUnixMs,omitempty"`
Provider string `json:"provider,omitempty"`
RateRef string `json:"rateRef,omitempty"`
Firm bool `json:"firm,omitempty"`
QuoteRef string `json:"quoteRef,omitempty"`
BaseCurrency string `json:"baseCurrency,omitempty"`
QuoteCurrency string `json:"quoteCurrency,omitempty"`
Side string `json:"side,omitempty"`
Price string `json:"price,omitempty"`
BaseAmount *paymenttypes.Money `json:"baseAmount,omitempty"`
QuoteAmount *paymenttypes.Money `json:"quoteAmount,omitempty"`
ExpiresAtUnixMs int64 `json:"expiresAtUnixMs,omitempty"`
Provider string `json:"provider,omitempty"`
RateRef string `json:"rateRef,omitempty"`
Firm bool `json:"firm,omitempty"`
}
type PaymentQuote struct {
QuoteRef string `json:"quoteRef,omitempty"`
DebitAmount *model.Money `json:"debitAmount,omitempty"`
ExpectedSettlementAmount *model.Money `json:"expectedSettlementAmount,omitempty"`
ExpectedFeeTotal *model.Money `json:"expectedFeeTotal,omitempty"`
FeeLines []FeeLine `json:"feeLines,omitempty"`
FxQuote *FxQuote `json:"fxQuote,omitempty"`
QuoteRef string `json:"quoteRef,omitempty"`
DebitAmount *paymenttypes.Money `json:"debitAmount,omitempty"`
ExpectedSettlementAmount *paymenttypes.Money `json:"expectedSettlementAmount,omitempty"`
ExpectedFeeTotal *paymenttypes.Money `json:"expectedFeeTotal,omitempty"`
FeeLines []FeeLine `json:"feeLines,omitempty"`
FxQuote *FxQuote `json:"fxQuote,omitempty"`
}
type PaymentQuoteAggregate struct {
DebitAmounts []*model.Money `json:"debitAmounts,omitempty"`
ExpectedSettlementAmounts []*model.Money `json:"expectedSettlementAmounts,omitempty"`
ExpectedFeeTotals []*model.Money `json:"expectedFeeTotals,omitempty"`
DebitAmounts []*paymenttypes.Money `json:"debitAmounts,omitempty"`
ExpectedSettlementAmounts []*paymenttypes.Money `json:"expectedSettlementAmounts,omitempty"`
ExpectedFeeTotals []*paymenttypes.Money `json:"expectedFeeTotals,omitempty"`
}
type PaymentQuotes struct {

View File

@@ -8,7 +8,7 @@ import (
"github.com/tech/sendico/pkg/api/http/response"
"github.com/tech/sendico/pkg/mlogger"
"github.com/tech/sendico/pkg/model"
paymenttypes "github.com/tech/sendico/pkg/payments/types"
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
paginationv1 "github.com/tech/sendico/pkg/proto/common/pagination/v1"
connectorv1 "github.com/tech/sendico/pkg/proto/connector/v1"
@@ -43,10 +43,10 @@ type walletsResponse struct {
}
type walletBalance struct {
Available *model.Money `json:"available,omitempty"`
PendingInbound *model.Money `json:"pendingInbound,omitempty"`
PendingOutbound *model.Money `json:"pendingOutbound,omitempty"`
CalculatedAt string `json:"calculatedAt,omitempty"`
Available *paymenttypes.Money `json:"available,omitempty"`
PendingInbound *paymenttypes.Money `json:"pendingInbound,omitempty"`
PendingOutbound *paymenttypes.Money `json:"pendingOutbound,omitempty"`
CalculatedAt string `json:"calculatedAt,omitempty"`
}
type walletBalanceResponse struct {
@@ -281,11 +281,11 @@ func connectorBalanceToWalletBalance(b *connectorv1.Balance) walletBalance {
}
}
func connectorMoneyToModel(m *moneyv1.Money) *model.Money {
func connectorMoneyToModel(m *moneyv1.Money) *paymenttypes.Money {
if m == nil {
return nil
}
return &model.Money{
return &paymenttypes.Money{
Amount: m.GetAmount(),
Currency: m.GetCurrency(),
}

View File

@@ -9,6 +9,7 @@ import (
"github.com/tech/sendico/pkg/ledgerconv"
"github.com/tech/sendico/pkg/merrors"
"github.com/tech/sendico/pkg/model"
"github.com/tech/sendico/pkg/model/account_role"
"github.com/tech/sendico/pkg/mservice"
describablev1 "github.com/tech/sendico/pkg/proto/common/describable/v1"
ledgerv1 "github.com/tech/sendico/pkg/proto/ledger/v1"
@@ -132,7 +133,7 @@ func mapLedgerAccountType(accountType srequest.LedgerAccountType) (ledgerv1.Acco
return parsed, nil
}
func mapLedgerAccountRole(role model.AccountRole) (ledgerv1.AccountRole, error) {
func mapLedgerAccountRole(role account_role.AccountRole) (ledgerv1.AccountRole, error) {
raw := strings.TrimSpace(string(role))
if ledgerconv.IsAccountRoleUnspecified(raw) {
return ledgerv1.AccountRole_ACCOUNT_ROLE_OPERATING, nil

View File

@@ -3,8 +3,9 @@ package paymentapiimp
import (
"strings"
"github.com/google/uuid"
"github.com/tech/sendico/pkg/merrors"
"github.com/tech/sendico/pkg/model"
paymenttypes "github.com/tech/sendico/pkg/payments/types"
fxv1 "github.com/tech/sendico/pkg/proto/common/fx/v1"
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1"
@@ -46,6 +47,7 @@ func mapPaymentIntent(intent *srequest.PaymentIntent) (*orchestratorv1.PaymentIn
}
return &orchestratorv1.PaymentIntent{
Ref: uuid.New().String(),
Kind: kind,
Source: source,
Destination: destination,
@@ -225,7 +227,7 @@ func mapAsset(asset *srequest.Asset) (*chainv1.Asset, error) {
}, nil
}
func mapMoney(m *model.Money) *moneyv1.Money {
func mapMoney(m *paymenttypes.Money) *moneyv1.Money {
if m == nil {
return nil
}