payment quotation v2 + payment orchestration v2 draft
This commit is contained in:
142
api/pkg/discovery/rail_vocab.go
Normal file
142
api/pkg/discovery/rail_vocab.go
Normal file
@@ -0,0 +1,142 @@
|
||||
package discovery
|
||||
|
||||
import "strings"
|
||||
|
||||
const (
|
||||
RailCrypto = "CRYPTO"
|
||||
RailProviderSettlement = "PROVIDER_SETTLEMENT"
|
||||
RailLedger = "LEDGER"
|
||||
RailCardPayout = "CARD_PAYOUT"
|
||||
RailFiatOnRamp = "FIAT_ONRAMP"
|
||||
)
|
||||
|
||||
const (
|
||||
RailOperationDebit = "DEBIT"
|
||||
RailOperationCredit = "CREDIT"
|
||||
RailOperationExternalDebit = "EXTERNAL_DEBIT"
|
||||
RailOperationExternalCredit = "EXTERNAL_CREDIT"
|
||||
RailOperationMove = "MOVE"
|
||||
RailOperationSend = "SEND"
|
||||
RailOperationFee = "FEE"
|
||||
RailOperationObserveConfirm = "OBSERVE_CONFIRM"
|
||||
RailOperationFXConvert = "FX_CONVERT"
|
||||
RailOperationBlock = "BLOCK"
|
||||
RailOperationRelease = "RELEASE"
|
||||
)
|
||||
|
||||
var knownRails = map[string]struct{}{
|
||||
RailCrypto: {},
|
||||
RailProviderSettlement: {},
|
||||
RailLedger: {},
|
||||
RailCardPayout: {},
|
||||
RailFiatOnRamp: {},
|
||||
}
|
||||
|
||||
var knownRailOperations = map[string]struct{}{
|
||||
RailOperationDebit: {},
|
||||
RailOperationCredit: {},
|
||||
RailOperationExternalDebit: {},
|
||||
RailOperationExternalCredit: {},
|
||||
RailOperationMove: {},
|
||||
RailOperationSend: {},
|
||||
RailOperationFee: {},
|
||||
RailOperationObserveConfirm: {},
|
||||
RailOperationFXConvert: {},
|
||||
RailOperationBlock: {},
|
||||
RailOperationRelease: {},
|
||||
}
|
||||
|
||||
// NormalizeRail canonicalizes a rail token.
|
||||
func NormalizeRail(value string) string {
|
||||
return strings.ToUpper(strings.TrimSpace(value))
|
||||
}
|
||||
|
||||
// IsKnownRail reports whether the value is a recognized payment rail.
|
||||
func IsKnownRail(value string) bool {
|
||||
_, ok := knownRails[NormalizeRail(value)]
|
||||
return ok
|
||||
}
|
||||
|
||||
// NormalizeRailOperation canonicalizes a rail operation token.
|
||||
func NormalizeRailOperation(value string) string {
|
||||
clean := strings.ToUpper(strings.TrimSpace(value))
|
||||
if strings.HasPrefix(clean, "RAIL_OPERATION_") {
|
||||
clean = strings.TrimPrefix(clean, "RAIL_OPERATION_")
|
||||
}
|
||||
return clean
|
||||
}
|
||||
|
||||
// IsKnownRailOperation reports whether the value is a recognized rail operation.
|
||||
func IsKnownRailOperation(value string) bool {
|
||||
_, ok := knownRailOperations[NormalizeRailOperation(value)]
|
||||
return ok
|
||||
}
|
||||
|
||||
// ExpandRailOperation maps canonical and legacy names to normalized rail operations.
|
||||
func ExpandRailOperation(value string) []string {
|
||||
if op := NormalizeRailOperation(value); op != "" {
|
||||
if IsKnownRailOperation(op) {
|
||||
return []string{op}
|
||||
}
|
||||
}
|
||||
|
||||
switch strings.ToLower(strings.TrimSpace(value)) {
|
||||
case "payin", "payin.crypto", "payin.fiat", "payin.card":
|
||||
return []string{RailOperationExternalDebit}
|
||||
case "payout", "payout.crypto", "payout.fiat", "payout.card":
|
||||
return []string{RailOperationExternalCredit, RailOperationSend}
|
||||
case "fee.send", "fees.send":
|
||||
return []string{RailOperationFee}
|
||||
case "observe.confirm", "observe_confirm":
|
||||
return []string{RailOperationObserveConfirm}
|
||||
case "funds.block", "hold.balance", "block":
|
||||
return []string{RailOperationBlock}
|
||||
case "funds.release", "release", "unblock":
|
||||
return []string{RailOperationRelease}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// NormalizeRailOperations canonicalizes and deduplicates rail operation values.
|
||||
func NormalizeRailOperations(values []string) []string {
|
||||
if len(values) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
result := make([]string, 0, len(values))
|
||||
seen := map[string]bool{}
|
||||
for _, value := range values {
|
||||
for _, op := range ExpandRailOperation(value) {
|
||||
if op == "" || seen[op] {
|
||||
continue
|
||||
}
|
||||
seen[op] = true
|
||||
result = append(result, op)
|
||||
}
|
||||
}
|
||||
if len(result) == 0 {
|
||||
return nil
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// CryptoRailGatewayOperations returns canonical operations for crypto rail gateways.
|
||||
func CryptoRailGatewayOperations() []string {
|
||||
return []string{
|
||||
RailOperationSend,
|
||||
RailOperationExternalDebit,
|
||||
RailOperationExternalCredit,
|
||||
RailOperationFee,
|
||||
RailOperationObserveConfirm,
|
||||
}
|
||||
}
|
||||
|
||||
// CardPayoutRailGatewayOperations returns canonical operations for card payout gateways.
|
||||
func CardPayoutRailGatewayOperations() []string {
|
||||
return []string{
|
||||
RailOperationSend,
|
||||
RailOperationExternalCredit,
|
||||
RailOperationObserveConfirm,
|
||||
}
|
||||
}
|
||||
49
api/pkg/discovery/rail_vocab_test.go
Normal file
49
api/pkg/discovery/rail_vocab_test.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package discovery
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestNormalizeRailOperations(t *testing.T) {
|
||||
got := NormalizeRailOperations([]string{
|
||||
"send",
|
||||
"payout.crypto",
|
||||
"observe.confirm",
|
||||
"unknown",
|
||||
"EXTERNAL_CREDIT",
|
||||
})
|
||||
|
||||
want := []string{
|
||||
RailOperationSend,
|
||||
RailOperationExternalCredit,
|
||||
RailOperationObserveConfirm,
|
||||
}
|
||||
if len(got) != len(want) {
|
||||
t.Fatalf("unexpected operations count: got=%d want=%d", len(got), len(want))
|
||||
}
|
||||
for i := range want {
|
||||
if got[i] != want[i] {
|
||||
t.Fatalf("unexpected operation[%d]: got=%q want=%q", i, got[i], want[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExpandRailOperationLegacyAliases(t *testing.T) {
|
||||
got := ExpandRailOperation("payout.fiat")
|
||||
if len(got) != 2 {
|
||||
t.Fatalf("unexpected operations count: got=%d want=2", len(got))
|
||||
}
|
||||
if got[0] != RailOperationExternalCredit {
|
||||
t.Fatalf("unexpected first operation: got=%q want=%q", got[0], RailOperationExternalCredit)
|
||||
}
|
||||
if got[1] != RailOperationSend {
|
||||
t.Fatalf("unexpected second operation: got=%q want=%q", got[1], RailOperationSend)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsKnownRail(t *testing.T) {
|
||||
if !IsKnownRail("crypto") {
|
||||
t.Fatalf("expected crypto rail to be known")
|
||||
}
|
||||
if IsKnownRail("telegram") {
|
||||
t.Fatalf("did not expect telegram rail to be known")
|
||||
}
|
||||
}
|
||||
@@ -229,7 +229,7 @@ func normalizeEntry(entry RegistryEntry) RegistryEntry {
|
||||
entry.InstanceID = entry.ID
|
||||
}
|
||||
entry.Service = strings.TrimSpace(entry.Service)
|
||||
entry.Rail = strings.ToUpper(strings.TrimSpace(entry.Rail))
|
||||
entry.Rail = NormalizeRail(entry.Rail)
|
||||
entry.Network = strings.ToUpper(strings.TrimSpace(entry.Network))
|
||||
entry.Operations = normalizeStrings(entry.Operations, false)
|
||||
entry.CurrencyMeta = normalizeCurrencyAnnouncements(entry.CurrencyMeta)
|
||||
@@ -259,7 +259,7 @@ func normalizeAnnouncement(announce Announcement) Announcement {
|
||||
announce.InstanceID = announce.ID
|
||||
}
|
||||
announce.Service = strings.TrimSpace(announce.Service)
|
||||
announce.Rail = strings.ToUpper(strings.TrimSpace(announce.Rail))
|
||||
announce.Rail = NormalizeRail(announce.Rail)
|
||||
announce.Operations = normalizeStrings(announce.Operations, false)
|
||||
announce.Currencies = normalizeCurrencyAnnouncements(announce.Currencies)
|
||||
announce.InvokeURI = strings.TrimSpace(announce.InvokeURI)
|
||||
|
||||
Reference in New Issue
Block a user