Fixed billing fees unreachable error propagation. Added USDT ledger creation. Fixed ledger boundaries operation types

This commit is contained in:
Stephan D
2026-02-26 16:25:52 +01:00
parent 54e5c799e8
commit 336f352858
37 changed files with 838 additions and 302 deletions

View File

@@ -1,18 +1,14 @@
package serverimp
import (
oracleclient "github.com/tech/sendico/fx/oracle/client"
mntxclient "github.com/tech/sendico/gateway/mntx/client"
ledgerclient "github.com/tech/sendico/ledger/client"
"github.com/tech/sendico/payments/orchestrator/internal/service/orchestrator"
feesv1 "github.com/tech/sendico/pkg/proto/billing/fees/v1"
)
type orchestratorDeps struct {
feesClient feesv1.FeeEngineClient
ledgerClient ledgerclient.Client
mntxClient mntxclient.Client
oracleClient oracleclient.Client
gatewayInvokeResolver orchestrator.GatewayInvokeResolver
}
@@ -26,9 +22,7 @@ func (i *Imp) initDependencies(_ *config) *orchestratorDeps {
}
i.discoveryClients = newDiscoveryClientResolver(i.logger, i.discoveryReg)
deps.feesClient = &discoveryFeeClient{resolver: i.discoveryClients}
deps.ledgerClient = &discoveryLedgerClient{resolver: i.discoveryClients}
deps.oracleClient = &discoveryOracleClient{resolver: i.discoveryClients}
deps.mntxClient = &discoveryMntxClient{resolver: i.discoveryClients}
deps.gatewayInvokeResolver = discoveryGatewayInvokeResolver{resolver: i.discoveryClients}
return deps
@@ -39,9 +33,6 @@ func (i *Imp) buildServiceOptions(cfg *config, deps *orchestratorDeps) []orchest
return nil
}
opts := []orchestrator.Option{}
if deps.feesClient != nil {
opts = append(opts, orchestrator.WithFeeEngine(deps.feesClient, cfg.Fees.callTimeout()))
}
if deps.ledgerClient != nil {
opts = append(opts, orchestrator.WithLedgerClient(deps.ledgerClient))
}
@@ -49,16 +40,12 @@ func (i *Imp) buildServiceOptions(cfg *config, deps *orchestratorDeps) []orchest
opts = append(opts, orchestrator.WithMntxGateway(deps.mntxClient))
}
opts = append(opts, orchestrator.WithMaxFXQuoteTTLMillis(cfg.maxFXQuoteTTLMillis()))
if deps.gatewayInvokeResolver != nil {
opts = append(opts, orchestrator.WithGatewayInvokeResolver(deps.gatewayInvokeResolver))
}
if routes := buildCardGatewayRoutes(cfg.CardGateways); len(routes) > 0 {
opts = append(opts, orchestrator.WithCardGatewayRoutes(routes))
}
if feeAccounts := buildFeeLedgerAccounts(cfg.FeeAccounts); len(feeAccounts) > 0 {
opts = append(opts, orchestrator.WithFeeLedgerAccounts(feeAccounts))
}
if registry := buildGatewayRegistry(i.logger, cfg.GatewayInstances, i.discoveryReg); registry != nil {
opts = append(opts, orchestrator.WithGatewayRegistry(registry))
}

View File

@@ -33,7 +33,7 @@ func (i *Imp) initDiscovery(cfg *config) {
}
announce := discovery.Announcement{
Service: "PAYMENTS_ORCHESTRATOR",
Operations: []string{"payment.initiate"},
Operations: []string{discovery.OperationPaymentInitiate},
InvokeURI: cfg.GRPC.DiscoveryInvokeURI(),
Version: appversion.Create().Short(),
}

View File

@@ -32,6 +32,11 @@ var (
ledgerServiceNames = []string{"LEDGER", string(mservice.Ledger)}
oracleServiceNames = []string{"FX_ORACLE", string(mservice.FXOracle)}
mntxServiceNames = []string{"CARD_RAIL_GATEWAY", string(mservice.MntxGateway)}
feesRequiredOps = []string{discovery.OperationFeeCalc}
ledgerRequiredOps = discovery.LedgerServiceOperations()
oracleRequiredOps = []string{discovery.OperationFXQuote}
mntxRequiredOps = discovery.CardPayoutRailGatewayOperations()
)
type discoveryEndpoint struct {
@@ -109,27 +114,27 @@ func (r *discoveryClientResolver) Close() {
}
func (r *discoveryClientResolver) FeesAvailable() bool {
_, ok := r.findEntry("fees", feesServiceNames, "", "")
_, ok := r.findEntry("fees", feesServiceNames, "", "", feesRequiredOps)
return ok
}
func (r *discoveryClientResolver) LedgerAvailable() bool {
_, ok := r.findEntry("ledger", ledgerServiceNames, "", "")
_, ok := r.findEntry("ledger", ledgerServiceNames, "", "", ledgerRequiredOps)
return ok
}
func (r *discoveryClientResolver) OracleAvailable() bool {
_, ok := r.findEntry("oracle", oracleServiceNames, "", "")
_, ok := r.findEntry("oracle", oracleServiceNames, "", "", oracleRequiredOps)
return ok
}
func (r *discoveryClientResolver) MntxAvailable() bool {
_, ok := r.findEntry("mntx", mntxServiceNames, "", "")
_, ok := r.findEntry("mntx", mntxServiceNames, "", "", mntxRequiredOps)
return ok
}
func (r *discoveryClientResolver) FeesClient(ctx context.Context) (feesv1.FeeEngineClient, error) {
entry, ok := r.findEntry("fees", feesServiceNames, "", "")
entry, ok := r.findEntry("fees", feesServiceNames, "", "", feesRequiredOps)
if !ok {
return nil, merrors.NoData("discovery: fees service unavailable")
}
@@ -160,7 +165,7 @@ func (r *discoveryClientResolver) FeesClient(ctx context.Context) (feesv1.FeeEng
}
func (r *discoveryClientResolver) LedgerClient(ctx context.Context) (ledgerclient.Client, error) {
entry, ok := r.findEntry("ledger", ledgerServiceNames, "", "")
entry, ok := r.findEntry("ledger", ledgerServiceNames, "", "", ledgerRequiredOps)
if !ok {
return nil, merrors.NoData("discovery: ledger service unavailable")
}
@@ -194,7 +199,7 @@ func (r *discoveryClientResolver) LedgerClient(ctx context.Context) (ledgerclien
}
func (r *discoveryClientResolver) OracleClient(ctx context.Context) (oracleclient.Client, error) {
entry, ok := r.findEntry("oracle", oracleServiceNames, "", "")
entry, ok := r.findEntry("oracle", oracleServiceNames, "", "", oracleRequiredOps)
if !ok {
return nil, merrors.NoData("discovery: oracle service unavailable")
}
@@ -228,7 +233,7 @@ func (r *discoveryClientResolver) OracleClient(ctx context.Context) (oracleclien
}
func (r *discoveryClientResolver) MntxClient(ctx context.Context) (mntxclient.Client, error) {
entry, ok := r.findEntry("mntx", mntxServiceNames, "", "")
entry, ok := r.findEntry("mntx", mntxServiceNames, "", "", mntxRequiredOps)
if !ok {
return nil, merrors.NoData("discovery: mntx service unavailable")
}
@@ -316,14 +321,19 @@ func (r *discoveryClientResolver) PaymentGatewayClient(ctx context.Context, invo
return client, nil
}
func (r *discoveryClientResolver) findEntry(key string, services []string, rail string, network string) (*discovery.RegistryEntry, bool) {
func (r *discoveryClientResolver) findEntry(key string, services []string, rail string, network string, requiredOps []string) (*discovery.RegistryEntry, bool) {
if r == nil || r.registry == nil {
r.logMissing(key, "discovery registry unavailable", "", nil)
return nil, false
}
type discoveryMatch struct {
entry discovery.RegistryEntry
opMatch bool
}
entries := r.registry.List(time.Now(), true)
matches := make([]discovery.RegistryEntry, 0)
matches := make([]discoveryMatch, 0)
for _, entry := range entries {
if !matchesService(entry.Service, services) {
continue
@@ -334,7 +344,10 @@ func (r *discoveryClientResolver) findEntry(key string, services []string, rail
if network != "" && !strings.EqualFold(strings.TrimSpace(entry.Network), network) {
continue
}
matches = append(matches, entry)
matches = append(matches, discoveryMatch{
entry: entry,
opMatch: discovery.HasAnyOperation(entry.Operations, requiredOps),
})
}
if len(matches) == 0 {
@@ -343,16 +356,19 @@ func (r *discoveryClientResolver) findEntry(key string, services []string, rail
}
sort.Slice(matches, func(i, j int) bool {
if matches[i].RoutingPriority != matches[j].RoutingPriority {
return matches[i].RoutingPriority > matches[j].RoutingPriority
if matches[i].opMatch != matches[j].opMatch {
return matches[i].opMatch
}
if matches[i].ID != matches[j].ID {
return matches[i].ID < matches[j].ID
if matches[i].entry.RoutingPriority != matches[j].entry.RoutingPriority {
return matches[i].entry.RoutingPriority > matches[j].entry.RoutingPriority
}
return matches[i].InstanceID < matches[j].InstanceID
if matches[i].entry.ID != matches[j].entry.ID {
return matches[i].entry.ID < matches[j].entry.ID
}
return matches[i].entry.InstanceID < matches[j].entry.InstanceID
})
entry := matches[0]
entry := matches[0].entry
entryKey := discoveryEntryKey(entry)
r.logSelection(key, entryKey, entry)
return &entry, true

View File

@@ -134,6 +134,22 @@ func (c *discoveryLedgerClient) PostDebitWithCharges(ctx context.Context, req *l
return client.PostDebitWithCharges(ctx, req)
}
func (c *discoveryLedgerClient) PostExternalCreditWithCharges(ctx context.Context, req *ledgerv1.PostCreditRequest) (*ledgerv1.PostResponse, error) {
client, err := c.resolver.LedgerClient(ctx)
if err != nil {
return nil, err
}
return client.PostExternalCreditWithCharges(ctx, req)
}
func (c *discoveryLedgerClient) PostExternalDebitWithCharges(ctx context.Context, req *ledgerv1.PostDebitRequest) (*ledgerv1.PostResponse, error) {
client, err := c.resolver.LedgerClient(ctx)
if err != nil {
return nil, err
}
return client.PostExternalDebitWithCharges(ctx, req)
}
func (c *discoveryLedgerClient) ApplyFXWithCharges(ctx context.Context, req *ledgerv1.FXRequest) (*ledgerv1.PostResponse, error) {
client, err := c.resolver.LedgerClient(ctx)
if err != nil {