fixed linting config
This commit is contained in:
@@ -51,7 +51,7 @@ func (r *discoveryGatewayRegistry) List(_ context.Context) ([]*model.GatewayInst
|
||||
InvokeURI: strings.TrimSpace(entry.InvokeURI),
|
||||
Currencies: normalizeCurrencies(entry.Currencies),
|
||||
Capabilities: capabilitiesFromOps(entry.Operations),
|
||||
Limits: limitsFromDiscovery(entry.Limits),
|
||||
Limits: limitsFromDiscovery(entry.Limits, entry.CurrencyMeta),
|
||||
Version: entry.Version,
|
||||
IsEnabled: entry.Healthy,
|
||||
})
|
||||
@@ -102,36 +102,111 @@ func capabilitiesFromOps(ops []string) model.RailCapabilities {
|
||||
return cap
|
||||
}
|
||||
|
||||
func limitsFromDiscovery(src *discovery.Limits) model.Limits {
|
||||
if src == nil {
|
||||
return model.Limits{}
|
||||
}
|
||||
func limitsFromDiscovery(src *discovery.Limits, currencies []discovery.CurrencyAnnouncement) model.Limits {
|
||||
limits := model.Limits{
|
||||
MinAmount: strings.TrimSpace(src.MinAmount),
|
||||
MaxAmount: strings.TrimSpace(src.MaxAmount),
|
||||
VolumeLimit: map[string]string{},
|
||||
VelocityLimit: map[string]int{},
|
||||
VolumeLimit: map[string]string{},
|
||||
VelocityLimit: map[string]int{},
|
||||
CurrencyLimits: map[string]model.LimitsOverride{},
|
||||
}
|
||||
for key, value := range src.VolumeLimit {
|
||||
k := strings.TrimSpace(key)
|
||||
v := strings.TrimSpace(value)
|
||||
if k == "" || v == "" {
|
||||
continue
|
||||
if src != nil {
|
||||
limits.MinAmount = strings.TrimSpace(src.MinAmount)
|
||||
limits.MaxAmount = strings.TrimSpace(src.MaxAmount)
|
||||
for key, value := range src.VolumeLimit {
|
||||
k := strings.TrimSpace(key)
|
||||
v := strings.TrimSpace(value)
|
||||
if k == "" || v == "" {
|
||||
continue
|
||||
}
|
||||
limits.VolumeLimit[k] = v
|
||||
}
|
||||
limits.VolumeLimit[k] = v
|
||||
}
|
||||
for key, value := range src.VelocityLimit {
|
||||
k := strings.TrimSpace(key)
|
||||
if k == "" {
|
||||
continue
|
||||
for key, value := range src.VelocityLimit {
|
||||
k := strings.TrimSpace(key)
|
||||
if k == "" {
|
||||
continue
|
||||
}
|
||||
limits.VelocityLimit[k] = value
|
||||
}
|
||||
limits.VelocityLimit[k] = value
|
||||
}
|
||||
applyCurrencyTransferLimits(&limits, currencies)
|
||||
if len(limits.VolumeLimit) == 0 {
|
||||
limits.VolumeLimit = nil
|
||||
}
|
||||
if len(limits.VelocityLimit) == 0 {
|
||||
limits.VelocityLimit = nil
|
||||
}
|
||||
if len(limits.CurrencyLimits) == 0 {
|
||||
limits.CurrencyLimits = nil
|
||||
}
|
||||
return limits
|
||||
}
|
||||
|
||||
func applyCurrencyTransferLimits(dst *model.Limits, currencies []discovery.CurrencyAnnouncement) {
|
||||
if dst == nil || len(currencies) == 0 {
|
||||
return
|
||||
}
|
||||
var (
|
||||
commonMin string
|
||||
commonMax string
|
||||
commonMinInit bool
|
||||
commonMaxInit bool
|
||||
commonMinConsistent = true
|
||||
commonMaxConsistent = true
|
||||
)
|
||||
|
||||
for _, currency := range currencies {
|
||||
code := strings.ToUpper(strings.TrimSpace(currency.Currency))
|
||||
if code == "" || currency.Limits == nil || currency.Limits.Amount == nil {
|
||||
commonMinConsistent = false
|
||||
commonMaxConsistent = false
|
||||
continue
|
||||
}
|
||||
min := strings.TrimSpace(currency.Limits.Amount.Min)
|
||||
max := strings.TrimSpace(currency.Limits.Amount.Max)
|
||||
|
||||
if min != "" || max != "" {
|
||||
override := dst.CurrencyLimits[code]
|
||||
if min != "" {
|
||||
override.MinAmount = min
|
||||
}
|
||||
if max != "" {
|
||||
override.MaxAmount = max
|
||||
}
|
||||
if override.MinAmount != "" || override.MaxAmount != "" || override.MaxFee != "" || override.MaxOps > 0 || override.MaxVolume != "" {
|
||||
dst.CurrencyLimits[code] = override
|
||||
}
|
||||
}
|
||||
|
||||
if min == "" {
|
||||
commonMinConsistent = false
|
||||
} else if !commonMinInit {
|
||||
commonMin = min
|
||||
commonMinInit = true
|
||||
} else if commonMin != min {
|
||||
commonMinConsistent = false
|
||||
}
|
||||
|
||||
if max == "" {
|
||||
commonMaxConsistent = false
|
||||
} else if !commonMaxInit {
|
||||
commonMax = max
|
||||
commonMaxInit = true
|
||||
} else if commonMax != max {
|
||||
commonMaxConsistent = false
|
||||
}
|
||||
}
|
||||
|
||||
if commonMinInit && commonMinConsistent {
|
||||
dst.PerTxMinAmount = firstDiscoveryLimitValue(dst.PerTxMinAmount, commonMin)
|
||||
}
|
||||
if commonMaxInit && commonMaxConsistent {
|
||||
dst.PerTxMaxAmount = firstDiscoveryLimitValue(dst.PerTxMaxAmount, commonMax)
|
||||
}
|
||||
}
|
||||
|
||||
func firstDiscoveryLimitValue(primary, fallback string) string {
|
||||
primary = strings.TrimSpace(primary)
|
||||
if primary != "" {
|
||||
return primary
|
||||
}
|
||||
return strings.TrimSpace(fallback)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
package orchestrator
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/tech/sendico/pkg/discovery"
|
||||
)
|
||||
|
||||
func TestLimitsFromDiscovery_MapsPerTxMinimumFromCurrencyMeta(t *testing.T) {
|
||||
limits := limitsFromDiscovery(nil, []discovery.CurrencyAnnouncement{
|
||||
{
|
||||
Currency: "RUB",
|
||||
Limits: &discovery.CurrencyLimits{
|
||||
Amount: &discovery.CurrencyAmount{
|
||||
Min: "100.00",
|
||||
Max: "10000.00",
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if limits.PerTxMinAmount != "100.00" {
|
||||
t.Fatalf("expected per tx min 100.00, got %q", limits.PerTxMinAmount)
|
||||
}
|
||||
if limits.PerTxMaxAmount != "10000.00" {
|
||||
t.Fatalf("expected per tx max 10000.00, got %q", limits.PerTxMaxAmount)
|
||||
}
|
||||
override, ok := limits.CurrencyLimits["RUB"]
|
||||
if !ok {
|
||||
t.Fatalf("expected RUB currency override")
|
||||
}
|
||||
if override.MinAmount != "100.00" {
|
||||
t.Fatalf("expected RUB min override 100.00, got %q", override.MinAmount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLimitsFromDiscovery_DropsCommonPerTxMinimumWhenCurrenciesDiffer(t *testing.T) {
|
||||
limits := limitsFromDiscovery(nil, []discovery.CurrencyAnnouncement{
|
||||
{
|
||||
Currency: "USD",
|
||||
Limits: &discovery.CurrencyLimits{
|
||||
Amount: &discovery.CurrencyAmount{Min: "10.00"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Currency: "EUR",
|
||||
Limits: &discovery.CurrencyLimits{
|
||||
Amount: &discovery.CurrencyAmount{Min: "20.00"},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if limits.PerTxMinAmount != "" {
|
||||
t.Fatalf("expected empty common per tx min, got %q", limits.PerTxMinAmount)
|
||||
}
|
||||
if limits.CurrencyLimits["USD"].MinAmount != "10.00" {
|
||||
t.Fatalf("expected USD min override 10.00, got %q", limits.CurrencyLimits["USD"].MinAmount)
|
||||
}
|
||||
if limits.CurrencyLimits["EUR"].MinAmount != "20.00" {
|
||||
t.Fatalf("expected EUR min override 20.00, got %q", limits.CurrencyLimits["EUR"].MinAmount)
|
||||
}
|
||||
}
|
||||
@@ -55,6 +55,9 @@ func (h *initiatePaymentsCommand) Execute(ctx context.Context, req *orchestrator
|
||||
}
|
||||
return gsresponse.Auto[orchestratorv1.InitiatePaymentsResponse](h.logger, mservice.PaymentOrchestrator, err)
|
||||
}
|
||||
if note := strings.TrimSpace(record.ExecutionNote); note != "" {
|
||||
return gsresponse.FailedPrecondition[orchestratorv1.InitiatePaymentsResponse](h.logger, mservice.PaymentOrchestrator, "quote_not_executable", merrors.InvalidArgument(note))
|
||||
}
|
||||
|
||||
intents := record.Intents
|
||||
quotes := record.Quotes
|
||||
@@ -209,6 +212,8 @@ func (h *initiatePaymentCommand) Execute(ctx context.Context, req *orchestratorv
|
||||
return gsresponse.FailedPrecondition[orchestratorv1.InitiatePaymentResponse](h.logger, mservice.PaymentOrchestrator, qerr.code, qerr.err)
|
||||
case "quote_expired":
|
||||
return gsresponse.FailedPrecondition[orchestratorv1.InitiatePaymentResponse](h.logger, mservice.PaymentOrchestrator, qerr.code, qerr.err)
|
||||
case "quote_not_executable":
|
||||
return gsresponse.FailedPrecondition[orchestratorv1.InitiatePaymentResponse](h.logger, mservice.PaymentOrchestrator, qerr.code, qerr.err)
|
||||
case "quote_intent_mismatch":
|
||||
return gsresponse.InvalidArgument[orchestratorv1.InitiatePaymentResponse](h.logger, mservice.PaymentOrchestrator, qerr.err)
|
||||
default:
|
||||
|
||||
@@ -123,6 +123,9 @@ func (s *Service) resolvePaymentQuote(ctx context.Context, in quoteResolutionInp
|
||||
if !record.ExpiresAt.IsZero() && s.clock.Now().After(record.ExpiresAt) {
|
||||
return nil, nil, nil, quoteResolutionError{code: "quote_expired", err: merrors.InvalidArgument("quote_ref expired")}
|
||||
}
|
||||
if note := strings.TrimSpace(record.ExecutionNote); note != "" {
|
||||
return nil, nil, nil, quoteResolutionError{code: "quote_not_executable", err: merrors.InvalidArgument(note)}
|
||||
}
|
||||
intent, err := recordIntentFromQuote(record)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
|
||||
@@ -125,6 +125,38 @@ func TestResolvePaymentQuote_Expired(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolvePaymentQuote_NotExecutable(t *testing.T) {
|
||||
org := bson.NewObjectID()
|
||||
intent := &sharedv1.PaymentIntent{
|
||||
Ref: "ref-1",
|
||||
Amount: &moneyv1.Money{Currency: "USD", Amount: "1"},
|
||||
SettlementCurrency: "USD",
|
||||
}
|
||||
record := &model.PaymentQuoteRecord{
|
||||
QuoteRef: "q1",
|
||||
Intent: intentFromProto(intent),
|
||||
Quote: &model.PaymentQuoteSnapshot{},
|
||||
ExecutionNote: "quote will not be executed: amount 1 USD below per-tx min limit 10",
|
||||
ExpiresAt: time.Now().Add(time.Minute),
|
||||
IdempotencyKey: "idem-1",
|
||||
}
|
||||
svc := &Service{
|
||||
storage: stubRepo{quotes: &helperQuotesStore{records: map[string]*model.PaymentQuoteRecord{"q1": record}}},
|
||||
clock: clockpkg.NewSystem(),
|
||||
}
|
||||
|
||||
_, _, _, err := svc.resolvePaymentQuote(context.Background(), quoteResolutionInput{
|
||||
OrgRef: org.Hex(),
|
||||
OrgID: org,
|
||||
Meta: &sharedv1.RequestMeta{OrganizationRef: org.Hex()},
|
||||
Intent: intent,
|
||||
QuoteRef: "q1",
|
||||
})
|
||||
if qerr, ok := err.(quoteResolutionError); !ok || qerr.code != "quote_not_executable" {
|
||||
t.Fatalf("expected quote_not_executable, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolvePaymentQuote_QuoteRefUsesStoredIntent(t *testing.T) {
|
||||
org := bson.NewObjectID()
|
||||
intent := &sharedv1.PaymentIntent{
|
||||
|
||||
Reference in New Issue
Block a user