outbox for gateways
This commit is contained in:
11
api/payments/storage/model/dpolicy.go
Normal file
11
api/payments/storage/model/dpolicy.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package model
|
||||
|
||||
import moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
|
||||
|
||||
// DepositCheckPolicy defines how an external deposit satisfies pre-funding.
|
||||
type DepositCheckPolicy struct {
|
||||
WalletRef string
|
||||
ExpectedAmount *moneyv1.Money
|
||||
MinConfirmations uint32
|
||||
TimeoutSeconds int64
|
||||
}
|
||||
11
api/payments/storage/model/funding.go
Normal file
11
api/payments/storage/model/funding.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package model
|
||||
|
||||
// FundingMode defines how payout liquidity must be satisfied for a gateway.
|
||||
type FundingMode string
|
||||
|
||||
const (
|
||||
FundingModeUnspecified FundingMode = "unspecified"
|
||||
FundingModeNone FundingMode = "none"
|
||||
FundingModeBalanceReserve FundingMode = "balance_reserve"
|
||||
FundingModeDepositObserved FundingMode = "deposit_observed"
|
||||
)
|
||||
@@ -252,15 +252,18 @@ type Customer struct {
|
||||
|
||||
// PaymentQuoteSnapshot stores the latest quote info.
|
||||
type PaymentQuoteSnapshot struct {
|
||||
DebitAmount *paymenttypes.Money `bson:"debitAmount,omitempty" json:"debitAmount,omitempty"`
|
||||
DebitSettlementAmount *paymenttypes.Money `bson:"debitSettlementAmount,omitempty" json:"debitSettlementAmount,omitempty"`
|
||||
ExpectedSettlementAmount *paymenttypes.Money `bson:"expectedSettlementAmount,omitempty" json:"expectedSettlementAmount,omitempty"`
|
||||
ExpectedFeeTotal *paymenttypes.Money `bson:"expectedFeeTotal,omitempty" json:"expectedFeeTotal,omitempty"`
|
||||
FeeLines []*paymenttypes.FeeLine `bson:"feeLines,omitempty" json:"feeLines,omitempty"`
|
||||
FeeRules []*paymenttypes.AppliedRule `bson:"feeRules,omitempty" json:"feeRules,omitempty"`
|
||||
FXQuote *paymenttypes.FXQuote `bson:"fxQuote,omitempty" json:"fxQuote,omitempty"`
|
||||
NetworkFee *paymenttypes.NetworkFeeEstimate `bson:"networkFee,omitempty" json:"networkFee,omitempty"`
|
||||
QuoteRef string `bson:"quoteRef,omitempty" json:"quoteRef,omitempty"`
|
||||
DebitAmount *paymenttypes.Money `bson:"debitAmount,omitempty" json:"debitAmount,omitempty"`
|
||||
DebitSettlementAmount *paymenttypes.Money `bson:"debitSettlementAmount,omitempty" json:"debitSettlementAmount,omitempty"`
|
||||
ExpectedSettlementAmount *paymenttypes.Money `bson:"expectedSettlementAmount,omitempty" json:"expectedSettlementAmount,omitempty"`
|
||||
ExpectedFeeTotal *paymenttypes.Money `bson:"expectedFeeTotal,omitempty" json:"expectedFeeTotal,omitempty"`
|
||||
TotalCost *paymenttypes.Money `bson:"totalCost,omitempty" json:"totalCost,omitempty"`
|
||||
FeeLines []*paymenttypes.FeeLine `bson:"feeLines,omitempty" json:"feeLines,omitempty"`
|
||||
FeeRules []*paymenttypes.AppliedRule `bson:"feeRules,omitempty" json:"feeRules,omitempty"`
|
||||
Route *paymenttypes.QuoteRouteSpecification `bson:"route,omitempty" json:"route,omitempty"`
|
||||
ExecutionConditions *paymenttypes.QuoteExecutionConditions `bson:"executionConditions,omitempty" json:"executionConditions,omitempty"`
|
||||
FXQuote *paymenttypes.FXQuote `bson:"fxQuote,omitempty" json:"fxQuote,omitempty"`
|
||||
NetworkFee *paymenttypes.NetworkFeeEstimate `bson:"networkFee,omitempty" json:"networkFee,omitempty"`
|
||||
QuoteRef string `bson:"quoteRef,omitempty" json:"quoteRef,omitempty"`
|
||||
}
|
||||
|
||||
// ExecutionRefs links to downstream systems.
|
||||
|
||||
@@ -18,6 +18,8 @@ type PaymentQuoteRecord struct {
|
||||
Intents []PaymentIntent `bson:"intents,omitempty" json:"intents,omitempty"`
|
||||
Quote *PaymentQuoteSnapshot `bson:"quote,omitempty" json:"quote,omitempty"`
|
||||
Quotes []*PaymentQuoteSnapshot `bson:"quotes,omitempty" json:"quotes,omitempty"`
|
||||
StatusV2 *QuoteStatusV2 `bson:"statusV2,omitempty" json:"statusV2,omitempty"`
|
||||
StatusesV2 []*QuoteStatusV2 `bson:"statusesV2,omitempty" json:"statusesV2,omitempty"`
|
||||
Plan *PaymentPlan `bson:"plan,omitempty" json:"plan,omitempty"`
|
||||
Plans []*PaymentPlan `bson:"plans,omitempty" json:"plans,omitempty"`
|
||||
ExecutionNote string `bson:"executionNote,omitempty" json:"executionNote,omitempty"`
|
||||
|
||||
41
api/payments/storage/model/quote_v2.go
Normal file
41
api/payments/storage/model/quote_v2.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package model
|
||||
|
||||
// QuoteKind captures v2 quote kind metadata for persistence.
|
||||
type QuoteKind string
|
||||
|
||||
const (
|
||||
QuoteKindUnspecified QuoteKind = "unspecified"
|
||||
QuoteKindExecutable QuoteKind = "executable"
|
||||
QuoteKindIndicative QuoteKind = "indicative"
|
||||
)
|
||||
|
||||
// QuoteLifecycle captures v2 quote lifecycle metadata for persistence.
|
||||
type QuoteLifecycle string
|
||||
|
||||
const (
|
||||
QuoteLifecycleUnspecified QuoteLifecycle = "unspecified"
|
||||
QuoteLifecycleActive QuoteLifecycle = "active"
|
||||
QuoteLifecycleExpired QuoteLifecycle = "expired"
|
||||
)
|
||||
|
||||
// QuoteBlockReason captures v2 non-executability reason for persistence.
|
||||
type QuoteBlockReason string
|
||||
|
||||
const (
|
||||
QuoteBlockReasonUnspecified QuoteBlockReason = "unspecified"
|
||||
QuoteBlockReasonRouteUnavailable QuoteBlockReason = "route_unavailable"
|
||||
QuoteBlockReasonLimitBlocked QuoteBlockReason = "limit_blocked"
|
||||
QuoteBlockReasonRiskBlocked QuoteBlockReason = "risk_blocked"
|
||||
QuoteBlockReasonInsufficientLiquidity QuoteBlockReason = "insufficient_liquidity"
|
||||
QuoteBlockReasonPriceStale QuoteBlockReason = "price_stale"
|
||||
QuoteBlockReasonAmountTooSmall QuoteBlockReason = "amount_too_small"
|
||||
QuoteBlockReasonAmountTooLarge QuoteBlockReason = "amount_too_large"
|
||||
)
|
||||
|
||||
// QuoteStatusV2 stores execution status metadata from quotation v2.
|
||||
type QuoteStatusV2 struct {
|
||||
Kind QuoteKind `bson:"kind,omitempty" json:"kind,omitempty"`
|
||||
Lifecycle QuoteLifecycle `bson:"lifecycle,omitempty" json:"lifecycle,omitempty"`
|
||||
Executable *bool `bson:"executable,omitempty" json:"executable,omitempty"`
|
||||
BlockReason QuoteBlockReason `bson:"blockReason,omitempty" json:"blockReason,omitempty"`
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
pkgmodel "github.com/tech/sendico/pkg/model"
|
||||
"github.com/tech/sendico/pkg/mservice"
|
||||
mutil "github.com/tech/sendico/pkg/mutil/db"
|
||||
mauth "github.com/tech/sendico/pkg/mutil/db/auth"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
"go.uber.org/zap"
|
||||
@@ -50,7 +51,7 @@ func NewPaymentMethods(logger mlogger.Logger, repo repository.Repository, enforc
|
||||
|
||||
for _, def := range indexes {
|
||||
if err := repo.CreateIndex(def); err != nil {
|
||||
logger.Error("failed to ensure payment methods index", zap.Error(err), zap.String("collection", repo.Collection()))
|
||||
logger.Error("Failed to ensure payment methods index", zap.Error(err), zap.String("collection", repo.Collection()))
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -112,6 +113,18 @@ func (p *PaymentMethods) Get(ctx context.Context, accountRef, methodRef bson.Obj
|
||||
return method, nil
|
||||
}
|
||||
|
||||
func (p *PaymentMethods) GetPrivate(ctx context.Context, methodRef bson.ObjectID) (*pkgmodel.PaymentMethod, error) {
|
||||
if methodRef == bson.NilObjectID {
|
||||
return nil, merrors.InvalidArgument("paymentMethodsStore: method_ref is required")
|
||||
}
|
||||
|
||||
method := &pkgmodel.PaymentMethod{}
|
||||
if err := p.repo.Get(ctx, methodRef, method); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return method, nil
|
||||
}
|
||||
|
||||
func (p *PaymentMethods) Update(ctx context.Context, accountRef bson.ObjectID, method *pkgmodel.PaymentMethod) error {
|
||||
if method == nil {
|
||||
return merrors.InvalidArgument("paymentMethodsStore: nil payment method")
|
||||
@@ -193,6 +206,27 @@ func (p *PaymentMethods) List(ctx context.Context, accountRef, organizationRef,
|
||||
return items, err
|
||||
}
|
||||
|
||||
func (p *PaymentMethods) ListPrivate(ctx context.Context, organizationRef, recipientRef bson.ObjectID, cursor *pkgmodel.ViewCursor) ([]pkgmodel.PaymentMethod, error) {
|
||||
if organizationRef == bson.NilObjectID {
|
||||
return nil, merrors.InvalidArgument("paymentMethodsStore: organization_ref is required")
|
||||
}
|
||||
if recipientRef == bson.NilObjectID {
|
||||
return nil, merrors.InvalidArgument("paymentMethodsStore: recipient_ref is required")
|
||||
}
|
||||
|
||||
items, err := mutil.GetObjects[pkgmodel.PaymentMethod](
|
||||
ctx,
|
||||
p.logger,
|
||||
repository.OrgFilter(organizationRef).And(repository.Filter("recipientRef", recipientRef)),
|
||||
cursor,
|
||||
p.repo,
|
||||
)
|
||||
if errors.Is(err, merrors.ErrNoData) {
|
||||
return []pkgmodel.PaymentMethod{}, nil
|
||||
}
|
||||
return items, err
|
||||
}
|
||||
|
||||
func (p *PaymentMethods) SetArchivedByRecipient(ctx context.Context, recipientRef bson.ObjectID, archived bool) (int, error) {
|
||||
if recipientRef == bson.NilObjectID {
|
||||
return 0, merrors.InvalidArgument("paymentMethodsStore: recipient_ref is required")
|
||||
|
||||
@@ -61,13 +61,13 @@ func NewPayments(logger mlogger.Logger, repo repository.Repository) (*Payments,
|
||||
|
||||
for _, def := range indexes {
|
||||
if err := repo.CreateIndex(def); err != nil {
|
||||
logger.Error("failed to ensure payments index", zap.Error(err), zap.String("collection", repo.Collection()))
|
||||
logger.Error("Failed to ensure payments index", zap.Error(err), zap.String("collection", repo.Collection()))
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
childLogger := logger.Named("payments")
|
||||
childLogger.Debug("payments store initialised")
|
||||
childLogger.Debug("Payments store initialised")
|
||||
|
||||
return &Payments{
|
||||
logger: childLogger,
|
||||
@@ -101,7 +101,7 @@ func (p *Payments) Create(ctx context.Context, payment *model.Payment) error {
|
||||
}
|
||||
return err
|
||||
}
|
||||
p.logger.Debug("payment created", zap.String("payment_ref", payment.PaymentRef))
|
||||
p.logger.Debug("Payment created", zap.String("payment_ref", payment.PaymentRef))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ func (p *Payments) List(ctx context.Context, filter *model.PaymentFilter) (*mode
|
||||
if oid, err := bson.ObjectIDFromHex(cursor); err == nil {
|
||||
query = query.Comparison(repository.IDField(), builder.Gt, oid)
|
||||
} else {
|
||||
p.logger.Warn("ignoring invalid payments cursor", zap.String("cursor", cursor), zap.Error(err))
|
||||
p.logger.Warn("Ignoring invalid payments cursor", zap.String("cursor", cursor), zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ func NewPlanTemplates(logger mlogger.Logger, repo repository.Repository) (*PlanT
|
||||
|
||||
for _, def := range indexes {
|
||||
if err := repo.CreateIndex(def); err != nil {
|
||||
logger.Error("failed to ensure plan templates index", zap.Error(err), zap.String("collection", repo.Collection()))
|
||||
logger.Error("Failed to ensure plan templates index", zap.Error(err), zap.String("collection", repo.Collection()))
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ func NewRoutes(logger mlogger.Logger, repo repository.Repository) (*Routes, erro
|
||||
|
||||
for _, def := range indexes {
|
||||
if err := repo.CreateIndex(def); err != nil {
|
||||
logger.Error("failed to ensure routes index", zap.Error(err), zap.String("collection", repo.Collection()))
|
||||
logger.Error("Failed to ensure routes index", zap.Error(err), zap.String("collection", repo.Collection()))
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ func NewQuotes(logger mlogger.Logger, repo repository.Repository, retention time
|
||||
|
||||
for _, def := range indexes {
|
||||
if err := repo.CreateIndex(def); err != nil {
|
||||
logger.Error("failed to ensure quotes index", zap.Error(err), zap.String("collection", repo.Collection()))
|
||||
logger.Error("Failed to ensure quotes index", zap.Error(err), zap.String("collection", repo.Collection()))
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,13 +25,6 @@ var (
|
||||
ErrDuplicatePlanTemplate = errors.New("payments.storage: duplicate plan template")
|
||||
)
|
||||
|
||||
var (
|
||||
// Deprecated: use quote/storage.ErrQuoteNotFound.
|
||||
ErrQuoteNotFound = quotestorage.ErrQuoteNotFound
|
||||
// Deprecated: use quote/storage.ErrDuplicateQuote.
|
||||
ErrDuplicateQuote = quotestorage.ErrDuplicateQuote
|
||||
)
|
||||
|
||||
// Repository exposes persistence primitives for the payments domain.
|
||||
type Repository interface {
|
||||
Ping(ctx context.Context) error
|
||||
@@ -56,11 +49,13 @@ type PaymentsStore interface {
|
||||
type PaymentMethodsStore interface {
|
||||
Create(ctx context.Context, accountRef, organizationRef bson.ObjectID, method *pkgmodel.PaymentMethod) error
|
||||
Get(ctx context.Context, accountRef, methodRef bson.ObjectID) (*pkgmodel.PaymentMethod, error)
|
||||
GetPrivate(ctx context.Context, methodRef bson.ObjectID) (*pkgmodel.PaymentMethod, error)
|
||||
Update(ctx context.Context, accountRef bson.ObjectID, method *pkgmodel.PaymentMethod) error
|
||||
Delete(ctx context.Context, accountRef, methodRef bson.ObjectID) error
|
||||
DeleteCascade(ctx context.Context, accountRef, methodRef bson.ObjectID) error
|
||||
SetArchived(ctx context.Context, accountRef, organizationRef, methodRef bson.ObjectID, archived, cascade bool) error
|
||||
List(ctx context.Context, accountRef, organizationRef, recipientRef bson.ObjectID, cursor *pkgmodel.ViewCursor) ([]pkgmodel.PaymentMethod, error)
|
||||
ListPrivate(ctx context.Context, organizationRef, recipientRef bson.ObjectID, cursor *pkgmodel.ViewCursor) ([]pkgmodel.PaymentMethod, error)
|
||||
|
||||
SetArchivedByRecipient(ctx context.Context, recipientRef bson.ObjectID, archived bool) (int, error)
|
||||
DeleteByRecipient(ctx context.Context, recipientRef bson.ObjectID) error
|
||||
|
||||
Reference in New Issue
Block a user