fixed rail & operation names
This commit is contained in:
@@ -12,20 +12,32 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bmatcuk/doublestar/v4 v4.10.0 // indirect
|
||||
github.com/casbin/casbin/v2 v2.135.0 // indirect
|
||||
github.com/casbin/govaluate v1.10.0 // indirect
|
||||
github.com/casbin/mongodb-adapter/v4 v4.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/klauspost/compress v1.18.4 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/nats-io/nats.go v1.49.0 // indirect
|
||||
github.com/nats-io/nkeys v0.4.15 // indirect
|
||||
github.com/nats-io/nuid v1.0.1 // indirect
|
||||
github.com/prometheus/client_golang v1.23.2 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.67.5 // indirect
|
||||
github.com/prometheus/procfs v0.20.0 // indirect
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||
github.com/xdg-go/scram v1.2.0 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||
golang.org/x/crypto v0.48.0 // indirect
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/sys v0.41.0 // indirect
|
||||
golang.org/x/text v0.34.0 // indirect
|
||||
google.golang.org/protobuf v1.36.11 // indirect
|
||||
)
|
||||
|
||||
@@ -4,6 +4,8 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
|
||||
github.com/bmatcuk/doublestar/v4 v4.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6TYWexEs=
|
||||
github.com/bmatcuk/doublestar/v4 v4.10.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
|
||||
@@ -53,6 +55,10 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c=
|
||||
github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 h1:mFWunSatvkQQDhpdyuFAYwyAan3hzCuma+Pz8sqvOfg=
|
||||
github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
@@ -77,6 +83,14 @@ github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/nats-io/nats.go v1.49.0 h1:yh/WvY59gXqYpgl33ZI+XoVPKyut/IcEaqtsiuTJpoE=
|
||||
github.com/nats-io/nats.go v1.49.0/go.mod h1:fDCn3mN5cY8HooHwE2ukiLb4p4G4ImmzvXyJt+tGwdw=
|
||||
github.com/nats-io/nkeys v0.4.15 h1:JACV5jRVO9V856KOapQ7x+EY8Jo3qw1vJt/9Jpwzkk4=
|
||||
github.com/nats-io/nkeys v0.4.15/go.mod h1:CpMchTXC9fxA5zrMo4KpySxNjiDVvr8ANOSZdiNfUrs=
|
||||
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
||||
@@ -87,6 +101,16 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
|
||||
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
|
||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
|
||||
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
|
||||
github.com/prometheus/procfs v0.20.0 h1:AA7aCvjxwAquZAlonN7888f2u4IN8WVeFgBi4k82M4Q=
|
||||
github.com/prometheus/procfs v0.20.0/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
|
||||
github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
|
||||
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
||||
@@ -136,6 +160,8 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
|
||||
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
|
||||
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||
@@ -171,5 +197,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
@@ -2,6 +2,7 @@ package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/tech/sendico/pkg/discovery"
|
||||
"strings"
|
||||
|
||||
"github.com/shopspring/decimal"
|
||||
@@ -110,7 +111,7 @@ func gatewayAllowsAction(operations []RailOperation, cap RailCapabilities, actio
|
||||
|
||||
func capabilityAllowsAction(cap RailCapabilities, action RailOperation, dir GatewayDirection) bool {
|
||||
switch action {
|
||||
case RailOperationSend:
|
||||
case discovery.RailOperationSend:
|
||||
switch dir {
|
||||
case GatewayDirectionOut:
|
||||
return cap.CanPayOut
|
||||
@@ -119,7 +120,7 @@ func capabilityAllowsAction(cap RailCapabilities, action RailOperation, dir Gate
|
||||
default:
|
||||
return cap.CanPayIn || cap.CanPayOut
|
||||
}
|
||||
case RailOperationExternalDebit, RailOperationExternalCredit:
|
||||
case discovery.RailOperationExternalDebit, discovery.RailOperationExternalCredit:
|
||||
switch dir {
|
||||
case GatewayDirectionOut:
|
||||
return cap.CanPayOut
|
||||
@@ -128,13 +129,13 @@ func capabilityAllowsAction(cap RailCapabilities, action RailOperation, dir Gate
|
||||
default:
|
||||
return cap.CanPayIn || cap.CanPayOut
|
||||
}
|
||||
case RailOperationFee:
|
||||
case discovery.RailOperationFee:
|
||||
return cap.CanSendFee
|
||||
case RailOperationObserveConfirm:
|
||||
case discovery.RailOperationObserveConfirm:
|
||||
return cap.RequiresObserveConfirm
|
||||
case RailOperationBlock:
|
||||
case discovery.RailOperationBlock:
|
||||
return cap.CanBlock
|
||||
case RailOperationRelease:
|
||||
case discovery.RailOperationRelease:
|
||||
return cap.CanRelease
|
||||
default:
|
||||
return true
|
||||
@@ -143,7 +144,7 @@ func capabilityAllowsAction(cap RailCapabilities, action RailOperation, dir Gate
|
||||
|
||||
func operationsAllowAction(operations []RailOperation, action RailOperation, dir GatewayDirection) bool {
|
||||
action = ParseRailOperation(string(action))
|
||||
if action == RailOperationUnspecified {
|
||||
if action == discovery.RailOperationUnspecified {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -152,20 +153,20 @@ func operationsAllowAction(operations []RailOperation, action RailOperation, dir
|
||||
}
|
||||
|
||||
switch action {
|
||||
case RailOperationSend:
|
||||
case discovery.RailOperationSend:
|
||||
switch dir {
|
||||
case GatewayDirectionIn:
|
||||
return HasRailOperation(operations, RailOperationExternalDebit)
|
||||
return HasRailOperation(operations, discovery.RailOperationExternalDebit)
|
||||
case GatewayDirectionOut:
|
||||
return HasRailOperation(operations, RailOperationExternalCredit)
|
||||
return HasRailOperation(operations, discovery.RailOperationExternalCredit)
|
||||
default:
|
||||
return HasRailOperation(operations, RailOperationExternalDebit) ||
|
||||
HasRailOperation(operations, RailOperationExternalCredit)
|
||||
return HasRailOperation(operations, discovery.RailOperationExternalDebit) ||
|
||||
HasRailOperation(operations, discovery.RailOperationExternalCredit)
|
||||
}
|
||||
case RailOperationExternalDebit:
|
||||
return HasRailOperation(operations, RailOperationSend)
|
||||
case RailOperationExternalCredit:
|
||||
return HasRailOperation(operations, RailOperationSend)
|
||||
case discovery.RailOperationExternalDebit:
|
||||
return HasRailOperation(operations, discovery.RailOperationSend)
|
||||
case discovery.RailOperationExternalCredit:
|
||||
return HasRailOperation(operations, discovery.RailOperationSend)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
@@ -181,7 +182,7 @@ func amountWithinLimits(gw *GatewayInstanceDescriptor, limits Limits, currency s
|
||||
if override, ok := limits.CurrencyLimits[currency]; ok {
|
||||
min = firstLimitValue(override.MinAmount, min)
|
||||
max = firstLimitValue(override.MaxAmount, max)
|
||||
if action == RailOperationFee {
|
||||
if action == discovery.RailOperationFee {
|
||||
maxFee = firstLimitValue(override.MaxFee, maxFee)
|
||||
}
|
||||
}
|
||||
@@ -206,7 +207,7 @@ func amountWithinLimits(gw *GatewayInstanceDescriptor, limits Limits, currency s
|
||||
return gatewayIneligible(gw, fmt.Sprintf("amount %s %s exceeds per-tx max limit %s", amount.String(), currency, val.String()))
|
||||
}
|
||||
}
|
||||
if action == RailOperationFee && maxFee != "" {
|
||||
if action == discovery.RailOperationFee && maxFee != "" {
|
||||
if val, err := decimal.NewFromString(maxFee); err == nil && amount.GreaterThan(val) {
|
||||
return gatewayIneligible(gw, fmt.Sprintf("fee amount %s %s exceeds max fee limit %s", amount.String(), currency, val.String()))
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/tech/sendico/pkg/discovery"
|
||||
"testing"
|
||||
|
||||
"github.com/shopspring/decimal"
|
||||
@@ -10,14 +11,14 @@ func TestIsGatewayEligible_AllowsMatchingGateway(t *testing.T) {
|
||||
gw := &GatewayInstanceDescriptor{
|
||||
ID: "gw-1",
|
||||
InstanceID: "inst-1",
|
||||
Rail: RailCrypto,
|
||||
Rail: discovery.RailCrypto,
|
||||
Network: "TRON",
|
||||
Currencies: []string{"USDT"},
|
||||
Operations: []RailOperation{RailOperationSend, RailOperationExternalCredit},
|
||||
Operations: []RailOperation{discovery.RailOperationSend, discovery.RailOperationExternalCredit},
|
||||
IsEnabled: true,
|
||||
}
|
||||
|
||||
err := IsGatewayEligible(gw, RailCrypto, "TRON", "USDT", RailOperationSend, GatewayDirectionOut, decimal.RequireFromString("10"))
|
||||
err := IsGatewayEligible(gw, discovery.RailCrypto, "TRON", "USDT", discovery.RailOperationSend, GatewayDirectionOut, decimal.RequireFromString("10"))
|
||||
if err != nil {
|
||||
t.Fatalf("expected gateway to be eligible, got err=%v", err)
|
||||
}
|
||||
@@ -27,21 +28,21 @@ func TestIsGatewayEligible_RejectsNetworkMismatch(t *testing.T) {
|
||||
gw := &GatewayInstanceDescriptor{
|
||||
ID: "gw-1",
|
||||
InstanceID: "inst-1",
|
||||
Rail: RailCrypto,
|
||||
Rail: discovery.RailCrypto,
|
||||
Network: "ETH",
|
||||
Currencies: []string{"USDT"},
|
||||
Operations: []RailOperation{RailOperationSend},
|
||||
Operations: []RailOperation{discovery.RailOperationSend},
|
||||
IsEnabled: true,
|
||||
}
|
||||
|
||||
err := IsGatewayEligible(gw, RailCrypto, "TRON", "USDT", RailOperationSend, GatewayDirectionOut, decimal.RequireFromString("10"))
|
||||
err := IsGatewayEligible(gw, discovery.RailCrypto, "TRON", "USDT", discovery.RailOperationSend, GatewayDirectionOut, decimal.RequireFromString("10"))
|
||||
if err == nil {
|
||||
t.Fatalf("expected network mismatch error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoEligibleGatewayMessage(t *testing.T) {
|
||||
got := NoEligibleGatewayMessage("tron", "usdt", RailOperationSend, GatewayDirectionOut)
|
||||
got := NoEligibleGatewayMessage("tron", "usdt", discovery.RailOperationSend, GatewayDirectionOut)
|
||||
want := "plan builder: no eligible gateway found for TRON USDT SEND for direction out"
|
||||
if got != want {
|
||||
t.Fatalf("unexpected message: got=%q want=%q", got, want)
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/tech/sendico/pkg/db/storable"
|
||||
"github.com/tech/sendico/pkg/discovery"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"github.com/tech/sendico/pkg/model/account_role"
|
||||
"github.com/tech/sendico/pkg/mservice"
|
||||
@@ -79,35 +80,10 @@ const (
|
||||
)
|
||||
|
||||
// Rail identifies a payment rail for orchestration.
|
||||
type Rail string
|
||||
|
||||
const (
|
||||
RailUnspecified Rail = "UNSPECIFIED"
|
||||
RailCrypto Rail = "CRYPTO"
|
||||
RailProviderSettlement Rail = "SETTLEMENT"
|
||||
RailLedger Rail = "LEDGER"
|
||||
RailCardPayout Rail = "CARD"
|
||||
RailFiatOnRamp Rail = "ONRAMP"
|
||||
RailFiatOffRamp Rail = "OFFRAMP"
|
||||
)
|
||||
type Rail = discovery.Rail
|
||||
|
||||
// RailOperation identifies an explicit action within a payment plan.
|
||||
type RailOperation string
|
||||
|
||||
const (
|
||||
RailOperationUnspecified RailOperation = "UNSPECIFIED"
|
||||
RailOperationDebit RailOperation = "DEBIT"
|
||||
RailOperationCredit RailOperation = "CREDIT"
|
||||
RailOperationExternalDebit RailOperation = "EXTERNAL_DEBIT"
|
||||
RailOperationExternalCredit RailOperation = "EXTERNAL_CREDIT"
|
||||
RailOperationMove RailOperation = "MOVE"
|
||||
RailOperationSend RailOperation = "SEND"
|
||||
RailOperationFee RailOperation = "FEE"
|
||||
RailOperationObserveConfirm RailOperation = "OBSERVE_CONFIRM"
|
||||
RailOperationFXConvert RailOperation = "FX_CONVERT"
|
||||
RailOperationBlock RailOperation = "BLOCK"
|
||||
RailOperationRelease RailOperation = "RELEASE"
|
||||
)
|
||||
type RailOperation = discovery.RailOperation
|
||||
|
||||
// RailCapabilities are declared per gateway instance.
|
||||
type RailCapabilities struct {
|
||||
|
||||
@@ -1,26 +1,29 @@
|
||||
package model
|
||||
|
||||
import "strings"
|
||||
import (
|
||||
"github.com/tech/sendico/pkg/discovery"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var supportedRailOperations = map[RailOperation]struct{}{
|
||||
RailOperationDebit: {},
|
||||
RailOperationCredit: {},
|
||||
RailOperationExternalDebit: {},
|
||||
RailOperationExternalCredit: {},
|
||||
RailOperationMove: {},
|
||||
RailOperationSend: {},
|
||||
RailOperationFee: {},
|
||||
RailOperationObserveConfirm: {},
|
||||
RailOperationFXConvert: {},
|
||||
RailOperationBlock: {},
|
||||
RailOperationRelease: {},
|
||||
discovery.RailOperationDebit: {},
|
||||
discovery.RailOperationCredit: {},
|
||||
discovery.RailOperationExternalDebit: {},
|
||||
discovery.RailOperationExternalCredit: {},
|
||||
discovery.RailOperationMove: {},
|
||||
discovery.RailOperationSend: {},
|
||||
discovery.RailOperationFee: {},
|
||||
discovery.RailOperationObserveConfirm: {},
|
||||
discovery.RailOperationFXConvert: {},
|
||||
discovery.RailOperationBlock: {},
|
||||
discovery.RailOperationRelease: {},
|
||||
}
|
||||
|
||||
// ParseRailOperation canonicalizes string values into a RailOperation token.
|
||||
func ParseRailOperation(value string) RailOperation {
|
||||
clean := strings.ToUpper(strings.TrimSpace(value))
|
||||
if clean == "" {
|
||||
return RailOperationUnspecified
|
||||
return discovery.RailOperationUnspecified
|
||||
}
|
||||
return RailOperation(clean)
|
||||
}
|
||||
@@ -40,7 +43,7 @@ func NormalizeRailOperations(values []RailOperation) []RailOperation {
|
||||
seen := map[RailOperation]bool{}
|
||||
for _, value := range values {
|
||||
op := ParseRailOperation(string(value))
|
||||
if op == RailOperationUnspecified || !IsSupportedRailOperation(op) || seen[op] {
|
||||
if op == discovery.RailOperationUnspecified || !IsSupportedRailOperation(op) || seen[op] {
|
||||
continue
|
||||
}
|
||||
seen[op] = true
|
||||
@@ -67,7 +70,7 @@ func NormalizeRailOperationStrings(values []string) []RailOperation {
|
||||
// HasRailOperation checks whether ops includes action.
|
||||
func HasRailOperation(ops []RailOperation, action RailOperation) bool {
|
||||
want := ParseRailOperation(string(action))
|
||||
if want == RailOperationUnspecified {
|
||||
if want == discovery.RailOperationUnspecified {
|
||||
return false
|
||||
}
|
||||
for _, op := range ops {
|
||||
@@ -82,12 +85,12 @@ func HasRailOperation(ops []RailOperation, action RailOperation) bool {
|
||||
func RailCapabilitiesFromOperations(ops []RailOperation) RailCapabilities {
|
||||
normalized := NormalizeRailOperations(ops)
|
||||
return RailCapabilities{
|
||||
CanPayIn: HasRailOperation(normalized, RailOperationExternalDebit),
|
||||
CanPayOut: HasRailOperation(normalized, RailOperationSend) || HasRailOperation(normalized, RailOperationExternalCredit),
|
||||
CanPayIn: HasRailOperation(normalized, discovery.RailOperationExternalDebit),
|
||||
CanPayOut: HasRailOperation(normalized, discovery.RailOperationSend) || HasRailOperation(normalized, discovery.RailOperationExternalCredit),
|
||||
CanReadBalance: false,
|
||||
CanSendFee: HasRailOperation(normalized, RailOperationFee),
|
||||
RequiresObserveConfirm: HasRailOperation(normalized, RailOperationObserveConfirm),
|
||||
CanBlock: HasRailOperation(normalized, RailOperationBlock),
|
||||
CanRelease: HasRailOperation(normalized, RailOperationRelease),
|
||||
CanSendFee: HasRailOperation(normalized, discovery.RailOperationFee),
|
||||
RequiresObserveConfirm: HasRailOperation(normalized, discovery.RailOperationObserveConfirm),
|
||||
CanBlock: HasRailOperation(normalized, discovery.RailOperationBlock),
|
||||
CanRelease: HasRailOperation(normalized, discovery.RailOperationRelease),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package model
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"github.com/tech/sendico/pkg/discovery"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNormalizeRailOperations(t *testing.T) {
|
||||
ops := NormalizeRailOperations([]RailOperation{
|
||||
@@ -13,35 +16,35 @@ func TestNormalizeRailOperations(t *testing.T) {
|
||||
if len(ops) != 2 {
|
||||
t.Fatalf("unexpected operations count: got=%d want=2", len(ops))
|
||||
}
|
||||
if ops[0] != RailOperationSend {
|
||||
t.Fatalf("unexpected first operation: got=%q want=%q", ops[0], RailOperationSend)
|
||||
if ops[0] != discovery.RailOperationSend {
|
||||
t.Fatalf("unexpected first operation: got=%q want=%q", ops[0], discovery.RailOperationSend)
|
||||
}
|
||||
if ops[1] != RailOperationExternalCredit {
|
||||
t.Fatalf("unexpected second operation: got=%q want=%q", ops[1], RailOperationExternalCredit)
|
||||
if ops[1] != discovery.RailOperationExternalCredit {
|
||||
t.Fatalf("unexpected second operation: got=%q want=%q", ops[1], discovery.RailOperationExternalCredit)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasRailOperation(t *testing.T) {
|
||||
ops := []RailOperation{RailOperationSend, RailOperationExternalCredit}
|
||||
if !HasRailOperation(ops, RailOperationSend) {
|
||||
ops := []RailOperation{discovery.RailOperationSend, discovery.RailOperationExternalCredit}
|
||||
if !HasRailOperation(ops, discovery.RailOperationSend) {
|
||||
t.Fatalf("expected send operation to be present")
|
||||
}
|
||||
if !HasRailOperation(ops, " external_credit ") {
|
||||
t.Fatalf("expected external credit operation to be present")
|
||||
}
|
||||
if HasRailOperation(ops, RailOperationObserveConfirm) {
|
||||
if HasRailOperation(ops, discovery.RailOperationObserveConfirm) {
|
||||
t.Fatalf("did not expect observe confirm operation to be present")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRailCapabilitiesFromOperations(t *testing.T) {
|
||||
cap := RailCapabilitiesFromOperations([]RailOperation{
|
||||
RailOperationExternalDebit,
|
||||
RailOperationExternalCredit,
|
||||
RailOperationFee,
|
||||
RailOperationObserveConfirm,
|
||||
RailOperationBlock,
|
||||
RailOperationRelease,
|
||||
discovery.RailOperationExternalDebit,
|
||||
discovery.RailOperationExternalCredit,
|
||||
discovery.RailOperationFee,
|
||||
discovery.RailOperationObserveConfirm,
|
||||
discovery.RailOperationBlock,
|
||||
discovery.RailOperationRelease,
|
||||
})
|
||||
|
||||
if !cap.CanPayIn {
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
package model
|
||||
|
||||
import "strings"
|
||||
import (
|
||||
"github.com/tech/sendico/pkg/discovery"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var supportedRails = map[Rail]struct{}{
|
||||
RailCrypto: {},
|
||||
RailProviderSettlement: {},
|
||||
RailLedger: {},
|
||||
RailCardPayout: {},
|
||||
RailFiatOnRamp: {},
|
||||
RailFiatOffRamp: {},
|
||||
discovery.RailCrypto: {},
|
||||
discovery.RailProviderSettlement: {},
|
||||
discovery.RailLedger: {},
|
||||
discovery.RailCardPayout: {},
|
||||
discovery.RailFiatOnRamp: {},
|
||||
discovery.RailFiatOffRamp: {},
|
||||
}
|
||||
|
||||
// ParseRail canonicalizes string values into a Rail token.
|
||||
func ParseRail(value string) Rail {
|
||||
clean := strings.ToUpper(strings.TrimSpace(value))
|
||||
if clean == "" {
|
||||
return RailUnspecified
|
||||
return discovery.RailUnspecified
|
||||
}
|
||||
clean = strings.ReplaceAll(clean, "-", "_")
|
||||
clean = strings.ReplaceAll(clean, " ", "_")
|
||||
@@ -24,20 +27,20 @@ func ParseRail(value string) Rail {
|
||||
}
|
||||
|
||||
switch clean {
|
||||
case string(RailCrypto), "RAIL_CRYPTO":
|
||||
return RailCrypto
|
||||
case string(RailProviderSettlement), "PROVIDER_SETTLEMENT", "RAIL_SETTLEMENT", "RAIL_PROVIDER_SETTLEMENT":
|
||||
return RailProviderSettlement
|
||||
case string(RailLedger), "RAIL_LEDGER":
|
||||
return RailLedger
|
||||
case string(RailCardPayout), "CARD_PAYOUT", "RAIL_CARD", "RAIL_CARD_PAYOUT":
|
||||
return RailCardPayout
|
||||
case string(RailFiatOnRamp), "FIAT_ONRAMP", "RAIL_ONRAMP", "RAIL_FIAT_ONRAMP":
|
||||
return RailFiatOnRamp
|
||||
case string(RailFiatOffRamp), "FIAT_OFFRAMP", "RAIL_OFFRAMP", "RAIL_FIAT_OFFRAMP":
|
||||
return RailFiatOffRamp
|
||||
case string(discovery.RailCrypto), "RAIL_CRYPTO":
|
||||
return discovery.RailCrypto
|
||||
case string(discovery.RailProviderSettlement), "PROVIDER_SETTLEMENT", "RAIL_SETTLEMENT", "RAIL_PROVIDER_SETTLEMENT":
|
||||
return discovery.RailProviderSettlement
|
||||
case string(discovery.RailLedger), "RAIL_LEDGER":
|
||||
return discovery.RailLedger
|
||||
case string(discovery.RailCardPayout), "CARD_PAYOUT", "RAIL_CARD", "RAIL_CARD_PAYOUT":
|
||||
return discovery.RailCardPayout
|
||||
case string(discovery.RailFiatOnRamp), "FIAT_ONRAMP", "RAIL_ONRAMP", "RAIL_FIAT_ONRAMP":
|
||||
return discovery.RailFiatOnRamp
|
||||
case string(discovery.RailFiatOffRamp), "FIAT_OFFRAMP", "RAIL_OFFRAMP", "RAIL_FIAT_OFFRAMP":
|
||||
return discovery.RailFiatOffRamp
|
||||
default:
|
||||
return RailUnspecified
|
||||
return discovery.RailUnspecified
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,13 +52,13 @@ func IsSupportedRail(rail Rail) bool {
|
||||
|
||||
func normalizeRail(value Rail) Rail {
|
||||
parsed := ParseRail(string(value))
|
||||
if parsed != RailUnspecified {
|
||||
if parsed != discovery.RailUnspecified {
|
||||
return parsed
|
||||
}
|
||||
|
||||
clean := strings.ToUpper(strings.TrimSpace(string(value)))
|
||||
if clean == "" {
|
||||
return RailUnspecified
|
||||
return discovery.RailUnspecified
|
||||
}
|
||||
|
||||
return Rail(clean)
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package model
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"github.com/tech/sendico/pkg/discovery"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseRail(t *testing.T) {
|
||||
cases := []struct {
|
||||
@@ -8,14 +11,14 @@ func TestParseRail(t *testing.T) {
|
||||
input string
|
||||
want Rail
|
||||
}{
|
||||
{name: "crypto", input: "crypto", want: RailCrypto},
|
||||
{name: "settlement canonical", input: "SETTLEMENT", want: RailProviderSettlement},
|
||||
{name: "settlement legacy", input: "provider_settlement", want: RailProviderSettlement},
|
||||
{name: "card canonical", input: "card", want: RailCardPayout},
|
||||
{name: "card legacy", input: "card_payout", want: RailCardPayout},
|
||||
{name: "onramp", input: "fiat_onramp", want: RailFiatOnRamp},
|
||||
{name: "offramp", input: "fiat_offramp", want: RailFiatOffRamp},
|
||||
{name: "unknown", input: "telegram", want: RailUnspecified},
|
||||
{name: "crypto", input: "crypto", want: discovery.RailCrypto},
|
||||
{name: "settlement canonical", input: "SETTLEMENT", want: discovery.RailProviderSettlement},
|
||||
{name: "settlement legacy", input: "provider_settlement", want: discovery.RailProviderSettlement},
|
||||
{name: "card canonical", input: "card", want: discovery.RailCardPayout},
|
||||
{name: "card legacy", input: "card_payout", want: discovery.RailCardPayout},
|
||||
{name: "onramp", input: "fiat_onramp", want: discovery.RailFiatOnRamp},
|
||||
{name: "offramp", input: "fiat_offramp", want: discovery.RailFiatOffRamp},
|
||||
{name: "unknown", input: "telegram", want: discovery.RailUnspecified},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
|
||||
@@ -3,6 +3,7 @@ package store
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/tech/sendico/pkg/discovery"
|
||||
"strings"
|
||||
|
||||
"github.com/tech/sendico/payments/storage"
|
||||
@@ -65,10 +66,10 @@ func (r *Routes) Create(ctx context.Context, route *model.PaymentRoute) error {
|
||||
return merrors.InvalidArgument("routesStore: nil route")
|
||||
}
|
||||
route.Normalize()
|
||||
if route.FromRail == "" || route.FromRail == model.RailUnspecified {
|
||||
if route.FromRail == "" || route.FromRail == discovery.RailUnspecified {
|
||||
return merrors.InvalidArgument("routesStore: from_rail is required")
|
||||
}
|
||||
if route.ToRail == "" || route.ToRail == model.RailUnspecified {
|
||||
if route.ToRail == "" || route.ToRail == discovery.RailUnspecified {
|
||||
return merrors.InvalidArgument("routesStore: to_rail is required")
|
||||
}
|
||||
if route.ID.IsZero() {
|
||||
@@ -176,20 +177,20 @@ func normalizedRailFilterValues(rail model.Rail) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
if parsed := model.ParseRail(string(rail)); parsed != model.RailUnspecified {
|
||||
if parsed := model.ParseRail(string(rail)); parsed != discovery.RailUnspecified {
|
||||
switch parsed {
|
||||
case model.RailCrypto:
|
||||
return []string{string(model.RailCrypto), "RAIL_CRYPTO"}
|
||||
case model.RailProviderSettlement:
|
||||
return []string{string(model.RailProviderSettlement), "PROVIDER_SETTLEMENT", "RAIL_SETTLEMENT", "RAIL_PROVIDER_SETTLEMENT"}
|
||||
case model.RailLedger:
|
||||
return []string{string(model.RailLedger), "RAIL_LEDGER"}
|
||||
case model.RailCardPayout:
|
||||
return []string{string(model.RailCardPayout), "CARD_PAYOUT", "RAIL_CARD", "RAIL_CARD_PAYOUT"}
|
||||
case model.RailFiatOnRamp:
|
||||
return []string{string(model.RailFiatOnRamp), "FIAT_ONRAMP", "RAIL_ONRAMP", "RAIL_FIAT_ONRAMP"}
|
||||
case model.RailFiatOffRamp:
|
||||
return []string{string(model.RailFiatOffRamp), "FIAT_OFFRAMP", "RAIL_OFFRAMP", "RAIL_FIAT_OFFRAMP"}
|
||||
case discovery.RailCrypto:
|
||||
return []string{string(discovery.RailCrypto), "RAIL_CRYPTO"}
|
||||
case discovery.RailProviderSettlement:
|
||||
return []string{string(discovery.RailProviderSettlement), "PROVIDER_SETTLEMENT", "RAIL_SETTLEMENT", "RAIL_PROVIDER_SETTLEMENT"}
|
||||
case discovery.RailLedger:
|
||||
return []string{string(discovery.RailLedger), "RAIL_LEDGER"}
|
||||
case discovery.RailCardPayout:
|
||||
return []string{string(discovery.RailCardPayout), "CARD_PAYOUT", "RAIL_CARD", "RAIL_CARD_PAYOUT"}
|
||||
case discovery.RailFiatOnRamp:
|
||||
return []string{string(discovery.RailFiatOnRamp), "FIAT_ONRAMP", "RAIL_ONRAMP", "RAIL_FIAT_ONRAMP"}
|
||||
case discovery.RailFiatOffRamp:
|
||||
return []string{string(discovery.RailFiatOffRamp), "FIAT_OFFRAMP", "RAIL_OFFRAMP", "RAIL_FIAT_OFFRAMP"}
|
||||
default:
|
||||
return []string{string(parsed)}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user