TG settlement service
This commit is contained in:
@@ -29,6 +29,15 @@ const (
|
||||
SettlementModeFixReceived SettlementMode = "fix_received"
|
||||
)
|
||||
|
||||
// CommitPolicy controls when a step is committed during orchestration.
|
||||
type CommitPolicy string
|
||||
|
||||
const (
|
||||
CommitPolicyUnspecified CommitPolicy = "UNSPECIFIED"
|
||||
CommitPolicyImmediate CommitPolicy = "IMMEDIATE"
|
||||
CommitPolicyAfterSuccess CommitPolicy = "AFTER_SUCCESS"
|
||||
)
|
||||
|
||||
// PaymentState enumerates lifecycle phases.
|
||||
type PaymentState string
|
||||
|
||||
@@ -180,6 +189,7 @@ type CardPayout struct {
|
||||
// PaymentEndpoint is a polymorphic payment destination/source.
|
||||
type PaymentEndpoint struct {
|
||||
Type PaymentEndpointType `bson:"type" json:"type"`
|
||||
InstanceID string `bson:"instanceId,omitempty" json:"instanceId,omitempty"`
|
||||
Ledger *LedgerEndpoint `bson:"ledger,omitempty" json:"ledger,omitempty"`
|
||||
ManagedWallet *ManagedWalletEndpoint `bson:"managedWallet,omitempty" json:"managedWallet,omitempty"`
|
||||
ExternalChain *ExternalChainEndpoint `bson:"externalChain,omitempty" json:"externalChain,omitempty"`
|
||||
@@ -199,16 +209,17 @@ type FXIntent struct {
|
||||
|
||||
// PaymentIntent models the requested payment operation.
|
||||
type PaymentIntent struct {
|
||||
Kind PaymentKind `bson:"kind" json:"kind"`
|
||||
Source PaymentEndpoint `bson:"source" json:"source"`
|
||||
Destination PaymentEndpoint `bson:"destination" json:"destination"`
|
||||
Amount *paymenttypes.Money `bson:"amount" json:"amount"`
|
||||
RequiresFX bool `bson:"requiresFx,omitempty" json:"requiresFx,omitempty"`
|
||||
FX *FXIntent `bson:"fx,omitempty" json:"fx,omitempty"`
|
||||
FeePolicy *paymenttypes.FeePolicy `bson:"feePolicy,omitempty" json:"feePolicy,omitempty"`
|
||||
SettlementMode SettlementMode `bson:"settlementMode,omitempty" json:"settlementMode,omitempty"`
|
||||
Attributes map[string]string `bson:"attributes,omitempty" json:"attributes,omitempty"`
|
||||
Customer *Customer `bson:"customer,omitempty" json:"customer,omitempty"`
|
||||
Kind PaymentKind `bson:"kind" json:"kind"`
|
||||
Source PaymentEndpoint `bson:"source" json:"source"`
|
||||
Destination PaymentEndpoint `bson:"destination" json:"destination"`
|
||||
Amount *paymenttypes.Money `bson:"amount" json:"amount"`
|
||||
RequiresFX bool `bson:"requiresFx,omitempty" json:"requiresFx,omitempty"`
|
||||
FX *FXIntent `bson:"fx,omitempty" json:"fx,omitempty"`
|
||||
FeePolicy *paymenttypes.FeePolicy `bson:"feePolicy,omitempty" json:"feePolicy,omitempty"`
|
||||
SettlementMode SettlementMode `bson:"settlementMode,omitempty" json:"settlementMode,omitempty"`
|
||||
SettlementCurrency string `bson:"settlementCurrency,omitempty" json:"settlementCurrency,omitempty"`
|
||||
Attributes map[string]string `bson:"attributes,omitempty" json:"attributes,omitempty"`
|
||||
Customer *Customer `bson:"customer,omitempty" json:"customer,omitempty"`
|
||||
}
|
||||
|
||||
// Customer captures payer/recipient identity details for downstream processing.
|
||||
@@ -249,19 +260,26 @@ type ExecutionRefs struct {
|
||||
|
||||
// PaymentStep is an explicit action within a payment plan.
|
||||
type PaymentStep struct {
|
||||
Rail Rail `bson:"rail" json:"rail"`
|
||||
GatewayID string `bson:"gatewayId,omitempty" json:"gatewayId,omitempty"`
|
||||
Action RailOperation `bson:"action" json:"action"`
|
||||
Amount *paymenttypes.Money `bson:"amount,omitempty" json:"amount,omitempty"`
|
||||
Ref string `bson:"ref,omitempty" json:"ref,omitempty"`
|
||||
StepID string `bson:"stepId,omitempty" json:"stepId,omitempty"`
|
||||
Rail Rail `bson:"rail" json:"rail"`
|
||||
GatewayID string `bson:"gatewayId,omitempty" json:"gatewayId,omitempty"`
|
||||
InstanceID string `bson:"instanceId,omitempty" json:"instanceId,omitempty"`
|
||||
Action RailOperation `bson:"action" json:"action"`
|
||||
DependsOn []string `bson:"dependsOn,omitempty" json:"dependsOn,omitempty"`
|
||||
CommitPolicy CommitPolicy `bson:"commitPolicy,omitempty" json:"commitPolicy,omitempty"`
|
||||
CommitAfter []string `bson:"commitAfter,omitempty" json:"commitAfter,omitempty"`
|
||||
Amount *paymenttypes.Money `bson:"amount,omitempty" json:"amount,omitempty"`
|
||||
Ref string `bson:"ref,omitempty" json:"ref,omitempty"`
|
||||
}
|
||||
|
||||
// PaymentPlan captures the ordered list of steps to execute a payment.
|
||||
type PaymentPlan struct {
|
||||
ID string `bson:"id,omitempty" json:"id,omitempty"`
|
||||
Steps []*PaymentStep `bson:"steps,omitempty" json:"steps,omitempty"`
|
||||
IdempotencyKey string `bson:"idempotencyKey,omitempty" json:"idempotencyKey,omitempty"`
|
||||
CreatedAt time.Time `bson:"createdAt,omitempty" json:"createdAt,omitempty"`
|
||||
ID string `bson:"id,omitempty" json:"id,omitempty"`
|
||||
FXQuote *paymenttypes.FXQuote `bson:"fxQuote,omitempty" json:"fxQuote,omitempty"`
|
||||
Fees []*paymenttypes.FeeLine `bson:"fees,omitempty" json:"fees,omitempty"`
|
||||
Steps []*PaymentStep `bson:"steps,omitempty" json:"steps,omitempty"`
|
||||
IdempotencyKey string `bson:"idempotencyKey,omitempty" json:"idempotencyKey,omitempty"`
|
||||
CreatedAt time.Time `bson:"createdAt,omitempty" json:"createdAt,omitempty"`
|
||||
}
|
||||
|
||||
// ExecutionStep describes a planned or executed payment step for reporting.
|
||||
@@ -338,6 +356,7 @@ func (p *Payment) Normalize() {
|
||||
p.Intent.Attributes[k] = strings.TrimSpace(v)
|
||||
}
|
||||
}
|
||||
p.Intent.SettlementCurrency = strings.TrimSpace(p.Intent.SettlementCurrency)
|
||||
if p.Intent.Customer != nil {
|
||||
p.Intent.Customer.ID = strings.TrimSpace(p.Intent.Customer.ID)
|
||||
p.Intent.Customer.FirstName = strings.TrimSpace(p.Intent.Customer.FirstName)
|
||||
@@ -380,9 +399,14 @@ func (p *Payment) Normalize() {
|
||||
if step == nil {
|
||||
continue
|
||||
}
|
||||
step.StepID = strings.TrimSpace(step.StepID)
|
||||
step.Rail = Rail(strings.TrimSpace(string(step.Rail)))
|
||||
step.GatewayID = strings.TrimSpace(step.GatewayID)
|
||||
step.InstanceID = strings.TrimSpace(step.InstanceID)
|
||||
step.Action = RailOperation(strings.TrimSpace(string(step.Action)))
|
||||
step.CommitPolicy = normalizeCommitPolicy(step.CommitPolicy)
|
||||
step.DependsOn = normalizeStringList(step.DependsOn)
|
||||
step.CommitAfter = normalizeStringList(step.CommitAfter)
|
||||
step.Ref = strings.TrimSpace(step.Ref)
|
||||
}
|
||||
}
|
||||
@@ -392,6 +416,7 @@ func normalizeEndpoint(ep *PaymentEndpoint) {
|
||||
if ep == nil {
|
||||
return
|
||||
}
|
||||
ep.InstanceID = strings.TrimSpace(ep.InstanceID)
|
||||
if ep.Metadata != nil {
|
||||
for k, v := range ep.Metadata {
|
||||
ep.Metadata[k] = strings.TrimSpace(v)
|
||||
@@ -433,3 +458,34 @@ func normalizeEndpoint(ep *PaymentEndpoint) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeCommitPolicy(policy CommitPolicy) CommitPolicy {
|
||||
val := strings.ToUpper(strings.TrimSpace(string(policy)))
|
||||
switch CommitPolicy(val) {
|
||||
case CommitPolicyImmediate, CommitPolicyAfterSuccess:
|
||||
return CommitPolicy(val)
|
||||
default:
|
||||
if val == "" {
|
||||
return CommitPolicyUnspecified
|
||||
}
|
||||
return CommitPolicy(val)
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeStringList(items []string) []string {
|
||||
if len(items) == 0 {
|
||||
return nil
|
||||
}
|
||||
result := make([]string, 0, len(items))
|
||||
for _, item := range items {
|
||||
clean := strings.TrimSpace(item)
|
||||
if clean == "" {
|
||||
continue
|
||||
}
|
||||
result = append(result, clean)
|
||||
}
|
||||
if len(result) == 0 {
|
||||
return nil
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
69
api/payments/orchestrator/storage/model/plan_template.go
Normal file
69
api/payments/orchestrator/storage/model/plan_template.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/tech/sendico/pkg/db/storable"
|
||||
"github.com/tech/sendico/pkg/mservice"
|
||||
)
|
||||
|
||||
// OrchestrationStep defines a template step for execution planning.
|
||||
type OrchestrationStep struct {
|
||||
StepID string `bson:"stepId" json:"stepId"`
|
||||
Rail Rail `bson:"rail" json:"rail"`
|
||||
Operation string `bson:"operation" json:"operation"`
|
||||
DependsOn []string `bson:"dependsOn,omitempty" json:"dependsOn,omitempty"`
|
||||
CommitPolicy CommitPolicy `bson:"commitPolicy,omitempty" json:"commitPolicy,omitempty"`
|
||||
CommitAfter []string `bson:"commitAfter,omitempty" json:"commitAfter,omitempty"`
|
||||
}
|
||||
|
||||
// PaymentPlanTemplate stores reusable orchestration templates.
|
||||
type PaymentPlanTemplate struct {
|
||||
storable.Base `bson:",inline" json:",inline"`
|
||||
|
||||
FromRail Rail `bson:"fromRail" json:"fromRail"`
|
||||
ToRail Rail `bson:"toRail" json:"toRail"`
|
||||
Network string `bson:"network,omitempty" json:"network,omitempty"`
|
||||
Steps []OrchestrationStep `bson:"steps,omitempty" json:"steps,omitempty"`
|
||||
IsEnabled bool `bson:"isEnabled" json:"isEnabled"`
|
||||
}
|
||||
|
||||
// Collection implements storable.Storable.
|
||||
func (*PaymentPlanTemplate) Collection() string {
|
||||
return mservice.PaymentPlanTemplates
|
||||
}
|
||||
|
||||
// Normalize standardizes template fields for matching and indexing.
|
||||
func (t *PaymentPlanTemplate) Normalize() {
|
||||
if t == nil {
|
||||
return
|
||||
}
|
||||
t.FromRail = Rail(strings.ToUpper(strings.TrimSpace(string(t.FromRail))))
|
||||
t.ToRail = Rail(strings.ToUpper(strings.TrimSpace(string(t.ToRail))))
|
||||
t.Network = strings.ToUpper(strings.TrimSpace(t.Network))
|
||||
if len(t.Steps) == 0 {
|
||||
return
|
||||
}
|
||||
for i := range t.Steps {
|
||||
step := &t.Steps[i]
|
||||
step.StepID = strings.TrimSpace(step.StepID)
|
||||
step.Rail = Rail(strings.ToUpper(strings.TrimSpace(string(step.Rail))))
|
||||
step.Operation = strings.ToLower(strings.TrimSpace(step.Operation))
|
||||
step.CommitPolicy = normalizeCommitPolicy(step.CommitPolicy)
|
||||
step.DependsOn = normalizeStringList(step.DependsOn)
|
||||
step.CommitAfter = normalizeStringList(step.CommitAfter)
|
||||
}
|
||||
}
|
||||
|
||||
// PaymentPlanTemplateFilter selects templates for lookup.
|
||||
type PaymentPlanTemplateFilter struct {
|
||||
FromRail Rail
|
||||
ToRail Rail
|
||||
Network string
|
||||
IsEnabled *bool
|
||||
}
|
||||
|
||||
// PaymentPlanTemplateList holds template results.
|
||||
type PaymentPlanTemplateList struct {
|
||||
Items []*PaymentPlanTemplate
|
||||
}
|
||||
Reference in New Issue
Block a user