payment quotation v2 + payment orchestration v2 draft

This commit is contained in:
Stephan D
2026-02-24 13:01:35 +01:00
parent 0646f55189
commit 6444813f38
289 changed files with 17005 additions and 16065 deletions

View File

@@ -15,10 +15,10 @@ replace github.com/tech/sendico/payments/storage => ../payments/storage
replace github.com/tech/sendico/gateway/tron => ../gateway/tron
require (
github.com/aws/aws-sdk-go-v2 v1.41.1
github.com/aws/aws-sdk-go-v2/config v1.32.9
github.com/aws/aws-sdk-go-v2/credentials v1.19.9
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0
github.com/aws/aws-sdk-go-v2 v1.41.2
github.com/aws/aws-sdk-go-v2/config v1.32.10
github.com/aws/aws-sdk-go-v2/credentials v1.19.10
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.1
github.com/go-chi/chi/v5 v5.2.5
github.com/go-chi/cors v1.2.2
github.com/go-chi/jwtauth/v5 v5.3.3
@@ -53,21 +53,21 @@ require (
dario.cat/mergo v1.0.1 // indirect
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.5 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.18 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.18 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.18 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17 // indirect
github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.30.10 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.14 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 // indirect
github.com/aws/smithy-go v1.24.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.18 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.5 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.18 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.18 // indirect
github.com/aws/aws-sdk-go-v2/service/signin v1.0.6 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.30.11 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.15 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.41.7 // indirect
github.com/aws/smithy-go v1.24.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/casbin/mongodb-adapter/v4 v4.3.0 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
@@ -76,7 +76,7 @@ require (
github.com/containerd/platforms v0.2.1 // indirect
github.com/cpuguy83/dockercfg v0.3.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1 // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/docker v27.3.1+incompatible // indirect
github.com/docker/go-connections v0.5.0 // indirect
@@ -107,7 +107,7 @@ require (
github.com/moby/term v0.5.0 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nats-io/nats.go v1.48.0 // 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/opencontainers/go-digest v1.0.0 // indirect
@@ -144,5 +144,5 @@ require (
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/genproto/googleapis/rpc v0.0.0-20260217215200-42d3e9bedb6d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260223185530-2f722ef697dc // indirect
)

View File

@@ -6,44 +6,44 @@ 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/aws/aws-sdk-go-v2 v1.41.1 h1:ABlyEARCDLN034NhxlRUSZr4l71mh+T5KAeGh6cerhU=
github.com/aws/aws-sdk-go-v2 v1.41.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4=
github.com/aws/aws-sdk-go-v2/config v1.32.9 h1:ktda/mtAydeObvJXlHzyGpK1xcsLaP16zfUPDGoW90A=
github.com/aws/aws-sdk-go-v2/config v1.32.9/go.mod h1:U+fCQ+9QKsLW786BCfEjYRj34VVTbPdsLP3CHSYXMOI=
github.com/aws/aws-sdk-go-v2/credentials v1.19.9 h1:sWvTKsyrMlJGEuj/WgrwilpoJ6Xa1+KhIpGdzw7mMU8=
github.com/aws/aws-sdk-go-v2/credentials v1.19.9/go.mod h1:+J44MBhmfVY/lETFiKI+klz0Vym2aCmIjqgClMmW82w=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 h1:I0GyV8wiYrP8XpA70g1HBcQO1JlQxCMTW9npl5UbDHY=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17/go.mod h1:tyw7BOl5bBe/oqvoIeECFJjMdzXoa/dfVz3QQ5lgHGA=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 h1:xOLELNKGp2vsiteLsvLPwxC+mYmO6OZ8PYgiuPJzF8U=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17/go.mod h1:5M5CI3D12dNOtH3/mk6minaRwI2/37ifCURZISxA/IQ=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 h1:WWLqlh79iO48yLkj1v3ISRNiv+3KdQoZ6JWyfcsyQik=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17/go.mod h1:EhG22vHRrvF8oXSTYStZhJc1aUgKtnJe+aOiFEV90cM=
github.com/aws/aws-sdk-go-v2 v1.41.2 h1:LuT2rzqNQsauaGkPK/7813XxcZ3o3yePY0Iy891T2ls=
github.com/aws/aws-sdk-go-v2 v1.41.2/go.mod h1:IvvlAZQXvTXznUPfRVfryiG1fbzE2NGK6m9u39YQ+S4=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.5 h1:zWFmPmgw4sveAYi1mRqG+E/g0461cJ5M4bJ8/nc6d3Q=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.5/go.mod h1:nVUlMLVV8ycXSb7mSkcNu9e3v/1TJq2RTlrPwhYWr5c=
github.com/aws/aws-sdk-go-v2/config v1.32.10 h1:9DMthfO6XWZYLfzZglAgW5Fyou2nRI5CuV44sTedKBI=
github.com/aws/aws-sdk-go-v2/config v1.32.10/go.mod h1:2rUIOnA2JaiqYmSKYmRJlcMWy6qTj1vuRFscppSBMcw=
github.com/aws/aws-sdk-go-v2/credentials v1.19.10 h1:EEhmEUFCE1Yhl7vDhNOI5OCL/iKMdkkYFTRpZXNw7m8=
github.com/aws/aws-sdk-go-v2/credentials v1.19.10/go.mod h1:RnnlFCAlxQCkN2Q379B67USkBMu1PipEEiibzYN5UTE=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.18 h1:Ii4s+Sq3yDfaMLpjrJsqD6SmG/Wq/P5L/hw2qa78UAY=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.18/go.mod h1:6x81qnY++ovptLE6nWQeWrpXxbnlIex+4H4eYYGcqfc=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.18 h1:F43zk1vemYIqPAwhjTjYIz0irU2EY7sOb/F5eJ3HuyM=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.18/go.mod h1:w1jdlZXrGKaJcNoL+Nnrj+k5wlpGXqnNrKoP22HvAug=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.18 h1:xCeWVjj0ki0l3nruoyP2slHsGArMxeiiaoPN5QZH6YQ=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.18/go.mod h1:r/eLGuGCBw6l36ZRWiw6PaZwPXb6YOj+i/7MizNl5/k=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17 h1:JqcdRG//czea7Ppjb+g/n4o8i/R50aTBHkA7vu0lK+k=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17/go.mod h1:CO+WeGmIdj/MlPel2KwID9Gt7CNq4M65HUfBW97liM0=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8 h1:Z5EiPIzXKewUQK0QTMkutjiaPVeVYXX7KIqhXu/0fXs=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8/go.mod h1:FsTpJtvC4U1fyDXk7c71XoDv3HlRm8V3NiYLeYLh5YE=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 h1:RuNSMoozM8oXlgLG/n6WLaFGoea7/CddrCfIiSA+xdY=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17/go.mod h1:F2xxQ9TZz5gDWsclCtPQscGpP0VUOc8RqgFM3vDENmU=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17 h1:bGeHBsGZx0Dvu/eJC0Lh9adJa3M1xREcndxLNZlve2U=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17/go.mod h1:dcW24lbU0CzHusTE8LLHhRLI42ejmINN8Lcr22bwh/g=
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0 h1:oeu8VPlOre74lBA/PMhxa5vewaMIMmILM+RraSyB8KA=
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0/go.mod h1:5jggDlZ2CLQhwJBiZJb4vfk4f0GxWdEDruWKEJ1xOdo=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 h1:VrhDvQib/i0lxvr3zqlUwLwJP4fpmpyD9wYG1vfSu+Y=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.5/go.mod h1:k029+U8SY30/3/ras4G/Fnv/b88N4mAfliNn08Dem4M=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.10 h1:+VTRawC4iVY58pS/lzpo0lnoa/SYNGF4/B/3/U5ro8Y=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.10/go.mod h1:yifAsgBxgJWn3ggx70A3urX2AN49Y5sJTD1UQFlfqBw=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.14 h1:0jbJeuEHlwKJ9PfXtpSFc4MF+WIWORdhN1n30ITZGFM=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.14/go.mod h1:sTGThjphYE4Ohw8vJiRStAcu3rbjtXRsdNB0TvZ5wwo=
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 h1:5fFjR/ToSOzB2OQ/XqWpZBmNvmP/pJ1jOWYlFDJTjRQ=
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6/go.mod h1:qgFDZQSD/Kys7nJnVqYlWKnh0SSdMjAi0uSwON4wgYQ=
github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk=
github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.18 h1:eZioDaZGJ0tMM4gzmkNIO2aAoQd+je7Ug7TkvAzlmkU=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.18/go.mod h1:CCXwUKAJdoWr6/NcxZ+zsiPr6oH/Q5aTooRGYieAyj4=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.5 h1:CeY9LUdur+Dxoeldqoun6y4WtJ3RQtzk0JMP2gfUay0=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.5/go.mod h1:AZLZf2fMaahW5s/wMRciu1sYbdsikT/UHwbUjOdEVTc=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.9 h1:IJRzQTvdpjHRPItx9gzNcz7Y1F+xqAR+xiy9rr5ZYl8=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.9/go.mod h1:Kzm5e6OmNH8VMkgK9t+ry5jEih4Y8whqs+1hrkxim1I=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.18 h1:LTRCYFlnnKFlKsyIQxKhJuDuA3ZkrDQMRYm6rXiHlLY=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.18/go.mod h1:XhwkgGG6bHSd00nO/mexWTcTjgd6PjuvWQMqSn2UaEk=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.18 h1:/A/xDuZAVD2BpsS2fftFRo/NoEKQJ8YTnJDEHBy2Gtg=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.18/go.mod h1:hWe9b4f+djUQGmyiGEeOnZv69dtMSgpDRIvNMvuvzvY=
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.1 h1:giB30dEeoar5bgDnkE0q+z7cFjcHaCjulpmPVmuKR84=
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.1/go.mod h1:071TH4M3botFLWDbzQLfBR7tXYi7Fs2RsXSiH7nlUlY=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.6 h1:MzORe+J94I+hYu2a6XmV5yC9huoTv8NRcCrUNedDypQ=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.6/go.mod h1:hXzcHLARD7GeWnifd8j9RWqtfIgxj4/cAtIVIK7hg8g=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.11 h1:7oGD8KPfBOJGXiCoRKrrrQkbvCp8N++u36hrLMPey6o=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.11/go.mod h1:0DO9B5EUJQlIDif+XJRWCljZRKsAFKh3gpFz7UnDtOo=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.15 h1:edCcNp9eGIUDUCrzoCu1jWAXLGFIizeqkdkKgRlJwWc=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.15/go.mod h1:lyRQKED9xWfgkYC/wmmYfv7iVIM68Z5OQ88ZdcV1QbU=
github.com/aws/aws-sdk-go-v2/service/sts v1.41.7 h1:NITQpgo9A5NrDZ57uOWj+abvXSb83BbyggcUBVksN7c=
github.com/aws/aws-sdk-go-v2/service/sts v1.41.7/go.mod h1:sks5UWBhEuWYDPdwlnRFn1w7xWdH29Jcpe+/PJQefEs=
github.com/aws/smithy-go v1.24.1 h1:VbyeNfmYkWoxMVpGUAbQumkODcYmfMRfZ8yQiH30SK0=
github.com/aws/smithy-go v1.24.1/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
@@ -73,8 +73,8 @@ github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1 h1:5RVFMOWjMyRy8cARdy79nAmgYw3hK/4HUq48LQ6Wwqo=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI=
@@ -175,8 +175,8 @@ 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.48.0 h1:pSFyXApG+yWU/TgbKCjmm5K4wrHu86231/w84qRVR+U=
github.com/nats-io/nats.go v1.48.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g=
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=
@@ -363,8 +363,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/genproto/googleapis/api v0.0.0-20260217215200-42d3e9bedb6d h1:EocjzKLywydp5uZ5tJ79iP6Q0UjDnyiHkGRWxuPBP8s=
google.golang.org/genproto/googleapis/api v0.0.0-20260217215200-42d3e9bedb6d/go.mod h1:48U2I+QQUYhsFrg2SY6r+nJzeOtjey7j//WBESw+qyQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260217215200-42d3e9bedb6d h1:t/LOSXPJ9R0B6fnZNyALBRfZBH0Uy0gT+uR+SJ6syqQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260217215200-42d3e9bedb6d/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260223185530-2f722ef697dc h1:51Wupg8spF+5FC6D+iMKbOddFjMckETnNnEiZ+HX37s=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260223185530-2f722ef697dc/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=

View File

@@ -1,6 +1,8 @@
package srequest
import (
"strings"
"github.com/tech/sendico/pkg/merrors"
)
@@ -23,8 +25,7 @@ type QuotePayment struct {
}
func (r *QuotePayment) Validate() error {
// base checks
if err := r.PaymentBase.Validate(); err != nil {
if err := validateQuoteIdempotency(r.PreviewOnly, r.IdempotencyKey); err != nil {
return err
}
@@ -43,7 +44,7 @@ type QuotePayments struct {
}
func (r *QuotePayments) Validate() error {
if err := r.PaymentBase.Validate(); err != nil {
if err := validateQuoteIdempotency(r.PreviewOnly, r.IdempotencyKey); err != nil {
return err
}
if len(r.Intents) == 0 {
@@ -57,6 +58,20 @@ func (r *QuotePayments) Validate() error {
return nil
}
func validateQuoteIdempotency(previewOnly bool, idempotencyKey string) error {
key := strings.TrimSpace(idempotencyKey)
if previewOnly {
if key != "" {
return merrors.InvalidArgument("previewOnly requests must not include idempotencyKey", "idempotencyKey")
}
return nil
}
if key == "" {
return merrors.InvalidArgument("idempotencyKey is required", "idempotencyKey")
}
return nil
}
type InitiatePayment struct {
PaymentBase `json:",inline"`
Intent *PaymentIntent `json:"intent,omitempty"`

View File

@@ -0,0 +1,29 @@
package srequest
import "testing"
func TestValidateQuoteIdempotency(t *testing.T) {
t.Run("non-preview requires idempotency key", func(t *testing.T) {
if err := validateQuoteIdempotency(false, ""); err == nil {
t.Fatalf("expected error for empty idempotency key")
}
})
t.Run("preview rejects idempotency key", func(t *testing.T) {
if err := validateQuoteIdempotency(true, "idem-1"); err == nil {
t.Fatalf("expected error when preview request has idempotency key")
}
})
t.Run("preview accepts empty idempotency key", func(t *testing.T) {
if err := validateQuoteIdempotency(true, ""); err != nil {
t.Fatalf("expected no error, got %v", err)
}
})
t.Run("non-preview accepts idempotency key", func(t *testing.T) {
if err := validateQuoteIdempotency(false, "idem-1"); err != nil {
t.Fatalf("expected no error, got %v", err)
}
})
}

View File

@@ -2,6 +2,7 @@ package sresponse
import (
"net/http"
"strconv"
"strings"
"time"
@@ -11,9 +12,9 @@ import (
feesv1 "github.com/tech/sendico/pkg/proto/billing/fees/v1"
paginationv1 "github.com/tech/sendico/pkg/proto/common/pagination/v1"
oraclev1 "github.com/tech/sendico/pkg/proto/oracle/v1"
orchestratorv1 "github.com/tech/sendico/pkg/proto/payments/orchestration/v1"
quotationv1 "github.com/tech/sendico/pkg/proto/payments/quotation/v1"
sharedv1 "github.com/tech/sendico/pkg/proto/payments/shared/v1"
orchestrationv2 "github.com/tech/sendico/pkg/proto/payments/orchestration/v2"
quotationv2 "github.com/tech/sendico/pkg/proto/payments/quotation/v2"
"google.golang.org/protobuf/types/known/timestamppb"
)
type FeeLine struct {
@@ -96,7 +97,7 @@ type paymentResponse struct {
}
// PaymentQuote wraps a payment quote with refreshed access token.
func PaymentQuoteResponse(logger mlogger.Logger, idempotencyKey string, quote *sharedv1.PaymentQuote, token *TokenData) http.HandlerFunc {
func PaymentQuoteResponse(logger mlogger.Logger, idempotencyKey string, quote *quotationv2.PaymentQuote, token *TokenData) http.HandlerFunc {
return response.Ok(logger, paymentQuoteResponse{
Quote: toPaymentQuote(quote),
IdempotencyKey: idempotencyKey,
@@ -105,7 +106,7 @@ func PaymentQuoteResponse(logger mlogger.Logger, idempotencyKey string, quote *s
}
// PaymentQuotes wraps batch quotes with refreshed access token.
func PaymentQuotesResponse(logger mlogger.Logger, resp *quotationv1.QuotePaymentsResponse, token *TokenData) http.HandlerFunc {
func PaymentQuotesResponse(logger mlogger.Logger, resp *quotationv2.QuotePaymentsResponse, token *TokenData) http.HandlerFunc {
return response.Ok(logger, paymentQuotesResponse{
Quote: toPaymentQuotes(resp),
authResponse: authResponse{AccessToken: *token},
@@ -113,7 +114,7 @@ func PaymentQuotesResponse(logger mlogger.Logger, resp *quotationv1.QuotePayment
}
// Payments wraps a list of payments with refreshed access token.
func PaymentsResponse(logger mlogger.Logger, payments []*sharedv1.Payment, token *TokenData) http.HandlerFunc {
func PaymentsResponse(logger mlogger.Logger, payments []*orchestrationv2.Payment, token *TokenData) http.HandlerFunc {
return response.Ok(logger, paymentsResponse{
Payments: toPayments(payments),
authResponse: authResponse{AccessToken: *token},
@@ -121,7 +122,7 @@ func PaymentsResponse(logger mlogger.Logger, payments []*sharedv1.Payment, token
}
// PaymentsList wraps a list of payments with refreshed access token and pagination data.
func PaymentsListResponse(logger mlogger.Logger, resp *orchestratorv1.ListPaymentsResponse, token *TokenData) http.HandlerFunc {
func PaymentsListResponse(logger mlogger.Logger, resp *orchestrationv2.ListPaymentsResponse, token *TokenData) http.HandlerFunc {
return response.Ok(logger, paymentsResponse{
Payments: toPayments(resp.GetPayments()),
Page: resp.GetPage(),
@@ -130,7 +131,7 @@ func PaymentsListResponse(logger mlogger.Logger, resp *orchestratorv1.ListPaymen
}
// Payment wraps a payment with refreshed access token.
func PaymentResponse(logger mlogger.Logger, payment *sharedv1.Payment, token *TokenData) http.HandlerFunc {
func PaymentResponse(logger mlogger.Logger, payment *orchestrationv2.Payment, token *TokenData) http.HandlerFunc {
return response.Ok(logger, paymentResponse{
Payment: toPayment(payment),
authResponse: authResponse{AccessToken: *token},
@@ -191,33 +192,20 @@ func toFxQuote(q *oraclev1.Quote) *FxQuote {
}
}
func toPaymentQuote(q *sharedv1.PaymentQuote) *PaymentQuote {
func toPaymentQuote(q *quotationv2.PaymentQuote) *PaymentQuote {
if q == nil {
return nil
}
return &PaymentQuote{
QuoteRef: q.GetQuoteRef(),
DebitAmount: toMoney(q.GetDebitAmount()),
DebitSettlementAmount: toMoney(q.GetDebitSettlementAmount()),
ExpectedSettlementAmount: toMoney(q.GetExpectedSettlementAmount()),
ExpectedFeeTotal: toMoney(q.GetExpectedFeeTotal()),
DebitAmount: toMoney(q.GetPayerTotalDebitAmount()),
ExpectedSettlementAmount: toMoney(q.GetDestinationAmount()),
FeeLines: toFeeLines(q.GetFeeLines()),
FxQuote: toFxQuote(q.GetFxQuote()),
}
}
func toPaymentQuoteAggregate(q *sharedv1.PaymentQuoteAggregate) *PaymentQuoteAggregate {
if q == nil {
return nil
}
return &PaymentQuoteAggregate{
DebitAmounts: toMoneyList(q.GetDebitAmounts()),
ExpectedSettlementAmounts: toMoneyList(q.GetExpectedSettlementAmounts()),
ExpectedFeeTotals: toMoneyList(q.GetExpectedFeeTotals()),
}
}
func toPaymentQuotes(resp *quotationv1.QuotePaymentsResponse) *PaymentQuotes {
func toPaymentQuotes(resp *quotationv2.QuotePaymentsResponse) *PaymentQuotes {
if resp == nil {
return nil
}
@@ -233,12 +221,11 @@ func toPaymentQuotes(resp *quotationv1.QuotePaymentsResponse) *PaymentQuotes {
return &PaymentQuotes{
IdempotencyKey: resp.GetIdempotencyKey(),
QuoteRef: resp.GetQuoteRef(),
Aggregate: toPaymentQuoteAggregate(resp.GetAggregate()),
Quotes: quotes,
}
}
func toPayments(items []*sharedv1.Payment) []Payment {
func toPayments(items []*orchestrationv2.Payment) []Payment {
if len(items) == 0 {
return nil
}
@@ -254,22 +241,65 @@ func toPayments(items []*sharedv1.Payment) []Payment {
return result
}
func toPayment(p *sharedv1.Payment) *Payment {
func toPayment(p *orchestrationv2.Payment) *Payment {
if p == nil {
return nil
}
failureCode, failureReason := firstFailure(p.GetStepExecutions())
return &Payment{
PaymentRef: p.GetPaymentRef(),
IdempotencyKey: p.GetIdempotencyKey(),
State: enumJSONName(p.GetState().String()),
FailureCode: enumJSONName(p.GetFailureCode().String()),
FailureReason: p.GetFailureReason(),
LastQuote: toPaymentQuote(p.GetLastQuote()),
CreatedAt: p.GetCreatedAt().AsTime(),
Meta: p.GetMetadata(),
FailureCode: failureCode,
FailureReason: failureReason,
LastQuote: toPaymentQuote(p.GetQuoteSnapshot()),
CreatedAt: timestampAsTime(p.GetCreatedAt()),
Meta: paymentMeta(p),
IdempotencyKey: "",
}
}
func firstFailure(steps []*orchestrationv2.StepExecution) (string, string) {
for _, step := range steps {
if step == nil || step.GetFailure() == nil {
continue
}
failure := step.GetFailure()
message := strings.TrimSpace(failure.GetMessage())
if message == "" {
message = strings.TrimSpace(failure.GetCode())
}
return enumJSONName(failure.GetCategory().String()), message
}
return "", ""
}
func paymentMeta(p *orchestrationv2.Payment) map[string]string {
if p == nil {
return nil
}
meta := make(map[string]string)
if quotationRef := strings.TrimSpace(p.GetQuotationRef()); quotationRef != "" {
meta["quotationRef"] = quotationRef
}
if clientPaymentRef := strings.TrimSpace(p.GetClientPaymentRef()); clientPaymentRef != "" {
meta["clientPaymentRef"] = clientPaymentRef
}
if version := p.GetVersion(); version > 0 {
meta["version"] = strconv.FormatUint(version, 10)
}
if len(meta) == 0 {
return nil
}
return meta
}
func timestampAsTime(ts *timestamppb.Timestamp) time.Time {
if ts == nil {
return time.Time{}
}
return ts.AsTime()
}
func enumJSONName(value string) string {
return strings.ToLower(strings.TrimSpace(value))
}

View File

@@ -4,18 +4,19 @@ import (
"net/http"
"strconv"
"strings"
"time"
"github.com/tech/sendico/pkg/api/http/response"
"github.com/tech/sendico/pkg/merrors"
"github.com/tech/sendico/pkg/model"
"github.com/tech/sendico/pkg/mutil/mzap"
paginationv1 "github.com/tech/sendico/pkg/proto/common/pagination/v1"
orchestratorv1 "github.com/tech/sendico/pkg/proto/payments/orchestration/v1"
sharedv1 "github.com/tech/sendico/pkg/proto/payments/shared/v1"
orchestrationv2 "github.com/tech/sendico/pkg/proto/payments/orchestration/v2"
"github.com/tech/sendico/server/interface/api/sresponse"
mutil "github.com/tech/sendico/server/internal/mutil/param"
"go.mongodb.org/mongo-driver/v2/bson"
"go.uber.org/zap"
"google.golang.org/protobuf/types/known/timestamppb"
)
const maxInt32 = int64(1<<31 - 1)
@@ -38,9 +39,7 @@ func (a *PaymentAPI) listPayments(r *http.Request, account *model.Account, token
return response.AccessDenied(a.logger, a.Name(), "payments read permission denied")
}
req := &orchestratorv1.ListPaymentsRequest{
OrganizationRef: orgRef.Hex(),
}
req := &orchestrationv2.ListPaymentsRequest{Meta: requestMeta(orgRef.Hex(), "")}
if page, err := listPaymentsPage(r); err != nil {
return response.Auto(a.logger, a.Name(), err)
@@ -49,17 +48,33 @@ func (a *PaymentAPI) listPayments(r *http.Request, account *model.Account, token
}
query := r.URL.Query()
if sourceRef := strings.TrimSpace(query.Get("source_ref")); sourceRef != "" {
req.SourceRef = sourceRef
if quotationRef := firstNonEmpty(query.Get("quotation_ref"), query.Get("quote_ref")); quotationRef != "" {
req.QuotationRef = quotationRef
}
if destinationRef := strings.TrimSpace(query.Get("destination_ref")); destinationRef != "" {
req.DestinationRef = destinationRef
createdFrom, err := parseRFC3339Timestamp(firstNonEmpty(query.Get("created_from"), query.Get("createdFrom")), "created_from")
if err != nil {
return response.Auto(a.logger, a.Name(), err)
}
if createdFrom != nil {
req.CreatedFrom = createdFrom
}
createdTo, err := parseRFC3339Timestamp(firstNonEmpty(query.Get("created_to"), query.Get("createdTo")), "created_to")
if err != nil {
return response.Auto(a.logger, a.Name(), err)
}
if createdTo != nil {
req.CreatedTo = createdTo
}
if req.GetCreatedFrom() != nil && req.GetCreatedTo() != nil {
if !req.GetCreatedTo().AsTime().After(req.GetCreatedFrom().AsTime()) {
return response.Auto(a.logger, a.Name(), merrors.InvalidArgument("created_to must be after created_from", "created_to"))
}
}
if states, err := parsePaymentStateFilters(r); err != nil {
return response.Auto(a.logger, a.Name(), err)
} else if len(states) > 0 {
req.FilterStates = states
req.States = states
}
resp, err := a.execution.ListPayments(ctx, req)
@@ -106,7 +121,7 @@ func listPaymentsPage(r *http.Request) (*paginationv1.CursorPageRequest, error)
return page, nil
}
func parsePaymentStateFilters(r *http.Request) ([]sharedv1.PaymentState, error) {
func parsePaymentStateFilters(r *http.Request) ([]orchestrationv2.OrchestrationState, error) {
query := r.URL.Query()
values := append([]string{}, query["state"]...)
values = append(values, query["states"]...)
@@ -115,14 +130,14 @@ func parsePaymentStateFilters(r *http.Request) ([]sharedv1.PaymentState, error)
return nil, nil
}
states := make([]sharedv1.PaymentState, 0, len(values))
states := make([]orchestrationv2.OrchestrationState, 0, len(values))
for _, raw := range values {
for _, part := range strings.Split(raw, ",") {
trimmed := strings.TrimSpace(part)
if trimmed == "" {
continue
}
state, ok := paymentStateFromString(trimmed)
state, ok := orchestrationStateFromString(trimmed)
if !ok {
return nil, merrors.InvalidArgument("unsupported payment state: "+trimmed, "state")
}
@@ -136,17 +151,49 @@ func parsePaymentStateFilters(r *http.Request) ([]sharedv1.PaymentState, error)
return states, nil
}
func paymentStateFromString(value string) (sharedv1.PaymentState, bool) {
func orchestrationStateFromString(value string) (orchestrationv2.OrchestrationState, bool) {
upper := strings.ToUpper(strings.TrimSpace(value))
if upper == "" {
return 0, false
}
if !strings.HasPrefix(upper, "PAYMENT_STATE_") {
upper = "PAYMENT_STATE_" + upper
switch upper {
case "PAYMENT_STATE_ACCEPTED", "ACCEPTED":
return orchestrationv2.OrchestrationState_ORCHESTRATION_STATE_CREATED, true
case "PAYMENT_STATE_FUNDS_RESERVED", "FUNDS_RESERVED", "PAYMENT_STATE_SUBMITTED", "SUBMITTED":
return orchestrationv2.OrchestrationState_ORCHESTRATION_STATE_EXECUTING, true
case "PAYMENT_STATE_SETTLED", "SETTLED":
return orchestrationv2.OrchestrationState_ORCHESTRATION_STATE_SETTLED, true
case "PAYMENT_STATE_FAILED", "FAILED", "PAYMENT_STATE_CANCELLED", "CANCELLED":
return orchestrationv2.OrchestrationState_ORCHESTRATION_STATE_FAILED, true
}
enumValue, ok := sharedv1.PaymentState_value[upper]
if !strings.HasPrefix(upper, "ORCHESTRATION_STATE_") {
upper = "ORCHESTRATION_STATE_" + upper
}
enumValue, ok := orchestrationv2.OrchestrationState_value[upper]
if !ok {
return 0, false
}
return sharedv1.PaymentState(enumValue), true
return orchestrationv2.OrchestrationState(enumValue), true
}
func firstNonEmpty(values ...string) string {
for _, value := range values {
trimmed := strings.TrimSpace(value)
if trimmed != "" {
return trimmed
}
}
return ""
}
func parseRFC3339Timestamp(raw string, field string) (*timestamppb.Timestamp, error) {
trimmed := strings.TrimSpace(raw)
if trimmed == "" {
return nil, nil
}
parsed, err := time.Parse(time.RFC3339, trimmed)
if err != nil {
return nil, merrors.InvalidArgument("invalid "+field+", expected RFC3339", field)
}
return timestamppb.New(parsed), nil
}

View File

@@ -1,26 +1,26 @@
package paymentapiimp
import (
"strconv"
"strings"
"github.com/google/uuid"
"github.com/tech/sendico/pkg/merrors"
pkgmodel "github.com/tech/sendico/pkg/model"
paymenttypes "github.com/tech/sendico/pkg/payments/types"
fxv1 "github.com/tech/sendico/pkg/proto/common/fx/v1"
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
paymentv1 "github.com/tech/sendico/pkg/proto/common/payment/v1"
chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1"
sharedv1 "github.com/tech/sendico/pkg/proto/payments/shared/v1"
endpointv1 "github.com/tech/sendico/pkg/proto/payments/endpoint/v1"
quotationv2 "github.com/tech/sendico/pkg/proto/payments/quotation/v2"
"github.com/tech/sendico/server/interface/api/srequest"
"go.mongodb.org/mongo-driver/v2/bson"
)
func mapPaymentIntent(intent *srequest.PaymentIntent) (*sharedv1.PaymentIntent, error) {
func mapQuoteIntent(intent *srequest.PaymentIntent) (*quotationv2.QuoteIntent, error) {
if intent == nil {
return nil, merrors.InvalidArgument("intent is required")
}
kind, err := mapPaymentKind(intent.Kind)
if err != nil {
if err := validatePaymentKind(intent.Kind); err != nil {
return nil, err
}
@@ -33,33 +33,35 @@ func mapPaymentIntent(intent *srequest.PaymentIntent) (*sharedv1.PaymentIntent,
settlementCurrency = resolveSettlementCurrency(intent)
}
source, err := mapPaymentEndpoint(intent.Source, "source")
source, err := mapQuoteEndpoint(intent.Source, "intent.source")
if err != nil {
return nil, err
}
destination, err := mapPaymentEndpoint(intent.Destination, "destination")
destination, err := mapQuoteEndpoint(intent.Destination, "intent.destination")
if err != nil {
return nil, err
}
fx, err := mapFXIntent(intent.FX)
if err != nil {
return nil, err
}
return &sharedv1.PaymentIntent{
Ref: uuid.New().String(),
Kind: kind,
quoteIntent := &quotationv2.QuoteIntent{
Source: source,
Destination: destination,
Amount: mapMoney(intent.Amount),
RequiresFx: fx != nil,
Fx: fx,
SettlementMode: settlementMode,
SettlementCurrency: settlementCurrency,
Attributes: copyStringMap(intent.Attributes),
Customer: mapCustomer(intent.Customer),
}, nil
}
if comment := strings.TrimSpace(intent.Attributes["comment"]); comment != "" {
quoteIntent.Comment = comment
}
return quoteIntent, nil
}
func validatePaymentKind(kind srequest.PaymentKind) error {
switch strings.TrimSpace(string(kind)) {
case string(srequest.PaymentKindPayout), string(srequest.PaymentKindInternalTransfer), string(srequest.PaymentKindFxConversion):
return nil
default:
return merrors.InvalidArgument("unsupported payment kind: " + string(kind))
}
}
func resolveSettlementCurrency(intent *srequest.PaymentIntent) string {
@@ -81,150 +83,147 @@ func resolveSettlementCurrency(intent *srequest.PaymentIntent) string {
return quote
}
}
if intent.Amount != nil {
amountCurrency := strings.TrimSpace(intent.Amount.Currency)
if amountCurrency != "" {
switch {
case strings.EqualFold(amountCurrency, base) && quote != "":
return quote
case strings.EqualFold(amountCurrency, quote) && base != "":
return base
default:
return amountCurrency
}
}
}
if quote != "" {
return quote
}
if base != "" {
return base
}
}
if intent.Amount != nil {
return strings.TrimSpace(intent.Amount.Currency)
}
return ""
}
func mapPaymentEndpoint(endpoint *srequest.Endpoint, field string) (*sharedv1.PaymentEndpoint, error) {
func mapQuoteEndpoint(endpoint *srequest.Endpoint, field string) (*endpointv1.PaymentEndpoint, error) {
if endpoint == nil {
return nil, nil
return nil, merrors.InvalidArgument(field + " is required")
}
var result sharedv1.PaymentEndpoint
switch endpoint.Type {
case srequest.EndpointTypeLedger:
payload, err := endpoint.DecodeLedger()
if err != nil {
return nil, merrors.InvalidArgument(field + " endpoint: " + err.Error())
return nil, merrors.InvalidArgument(field + ": " + err.Error())
}
result.Endpoint = &sharedv1.PaymentEndpoint_Ledger{
Ledger: mapLedgerEndpoint(&payload),
method := &ledgerMethodData{
LedgerAccountRef: strings.TrimSpace(payload.LedgerAccountRef),
ContraLedgerAccountRef: strings.TrimSpace(payload.ContraLedgerAccountRef),
}
if method.LedgerAccountRef == "" {
return nil, merrors.InvalidArgument(field + ".ledger_account_ref is required")
}
return endpointFromMethod(endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_LEDGER, method)
case srequest.EndpointTypeManagedWallet:
payload, err := endpoint.DecodeManagedWallet()
if err != nil {
return nil, merrors.InvalidArgument(field + " endpoint: " + err.Error())
return nil, merrors.InvalidArgument(field + ": " + err.Error())
}
mw, err := mapManagedWalletEndpoint(&payload)
method := &pkgmodel.WalletPaymentData{WalletID: strings.TrimSpace(payload.ManagedWalletRef)}
if method.WalletID == "" {
return nil, merrors.InvalidArgument(field + ".managed_wallet_ref is required")
}
return endpointFromMethod(endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_WALLET, method)
case srequest.EndpointTypeWallet:
payload, err := endpoint.DecodeWallet()
if err != nil {
return nil, merrors.InvalidArgument(field + " endpoint: " + err.Error())
return nil, merrors.InvalidArgument(field + ": " + err.Error())
}
result.Endpoint = &sharedv1.PaymentEndpoint_ManagedWallet{
ManagedWallet: mw,
method := &pkgmodel.WalletPaymentData{WalletID: strings.TrimSpace(payload.WalletID)}
if method.WalletID == "" {
return nil, merrors.InvalidArgument(field + ".walletId is required")
}
return endpointFromMethod(endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_WALLET, method)
case srequest.EndpointTypeExternalChain:
payload, err := endpoint.DecodeExternalChain()
if err != nil {
return nil, merrors.InvalidArgument(field + " endpoint: " + err.Error())
return nil, merrors.InvalidArgument(field + ": " + err.Error())
}
ext, err := mapExternalChainEndpoint(&payload)
if err != nil {
return nil, merrors.InvalidArgument(field + " endpoint: " + err.Error())
}
result.Endpoint = &sharedv1.PaymentEndpoint_ExternalChain{
ExternalChain: ext,
method, mapErr := mapExternalChainMethod(payload, field)
if mapErr != nil {
return nil, mapErr
}
return endpointFromMethod(endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_CRYPTO_ADDRESS, method)
case srequest.EndpointTypeCard:
payload, err := endpoint.DecodeCard()
if err != nil {
return nil, merrors.InvalidArgument(field + " endpoint: " + err.Error())
return nil, merrors.InvalidArgument(field + ": " + err.Error())
}
result.Endpoint = &sharedv1.PaymentEndpoint_Card{
Card: mapCardEndpoint(&payload),
method := &pkgmodel.CardPaymentData{
Pan: strings.TrimSpace(payload.Pan),
FirstName: strings.TrimSpace(payload.FirstName),
LastName: strings.TrimSpace(payload.LastName),
ExpMonth: uint32ToString(payload.ExpMonth),
ExpYear: uint32ToString(payload.ExpYear),
Country: strings.TrimSpace(payload.Country),
}
if method.Pan == "" {
return nil, merrors.InvalidArgument(field + ".pan is required")
}
return endpointFromMethod(endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_CARD, method)
case srequest.EndpointTypeCardToken:
payload, err := endpoint.DecodeCardToken()
if err != nil {
return nil, merrors.InvalidArgument(field + " endpoint: " + err.Error())
return nil, merrors.InvalidArgument(field + ": " + err.Error())
}
result.Endpoint = &sharedv1.PaymentEndpoint_Card{
Card: mapCardTokenEndpoint(&payload),
method := &pkgmodel.TokenPaymentData{
Token: strings.TrimSpace(payload.Token),
Last4: strings.TrimSpace(payload.MaskedPan),
}
if method.Token == "" {
return nil, merrors.InvalidArgument(field + ".token is required")
}
return endpointFromMethod(endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_CARD_TOKEN, method)
case "":
return nil, merrors.InvalidArgument(field + " endpoint type is required")
default:
return nil, merrors.InvalidArgument(field + " endpoint has unsupported type: " + string(endpoint.Type))
}
result.Metadata = copyStringMap(endpoint.Metadata)
return &result, nil
}
func mapLedgerEndpoint(endpoint *srequest.LedgerEndpoint) *sharedv1.LedgerEndpoint {
if endpoint == nil {
return nil
}
return &sharedv1.LedgerEndpoint{
LedgerAccountRef: endpoint.LedgerAccountRef,
ContraLedgerAccountRef: endpoint.ContraLedgerAccountRef,
return nil, merrors.InvalidArgument(field + " endpoint type is unsupported in v2: " + string(endpoint.Type))
}
}
func mapManagedWalletEndpoint(endpoint *srequest.ManagedWalletEndpoint) (*sharedv1.ManagedWalletEndpoint, error) {
if endpoint == nil {
return nil, nil
func mapExternalChainMethod(payload srequest.ExternalChainEndpoint, field string) (*pkgmodel.CryptoAddressPaymentData, error) {
address := strings.TrimSpace(payload.Address)
if address == "" {
return nil, merrors.InvalidArgument(field + ".address is required")
}
asset, err := mapAsset(endpoint.Asset)
if payload.Asset == nil {
return nil, merrors.InvalidArgument(field + ".asset is required")
}
token := strings.ToUpper(strings.TrimSpace(payload.Asset.TokenSymbol))
if token == "" {
return nil, merrors.InvalidArgument(field + ".asset.token_symbol is required")
}
if _, err := mapChainNetwork(payload.Asset.Chain); err != nil {
return nil, merrors.InvalidArgument(field + ".asset.chain: " + err.Error())
}
result := &pkgmodel.CryptoAddressPaymentData{
Currency: pkgmodel.Currency(token),
Address: address,
Network: strings.ToUpper(strings.TrimSpace(string(payload.Asset.Chain))),
}
if memo := strings.TrimSpace(payload.Memo); memo != "" {
result.DestinationTag = &memo
}
return result, nil
}
func endpointFromMethod(methodType endpointv1.PaymentMethodType, data any) (*endpointv1.PaymentEndpoint, error) {
raw, err := bson.Marshal(data)
if err != nil {
return nil, err
return nil, merrors.InternalWrap(err, "failed to encode payment method data")
}
return &sharedv1.ManagedWalletEndpoint{
ManagedWalletRef: endpoint.ManagedWalletRef,
Asset: asset,
}, nil
}
func mapExternalChainEndpoint(endpoint *srequest.ExternalChainEndpoint) (*sharedv1.ExternalChainEndpoint, error) {
if endpoint == nil {
return nil, nil
method := &endpointv1.PaymentMethod{
Type: methodType,
Data: raw,
}
asset, err := mapAsset(endpoint.Asset)
if err != nil {
return nil, err
}
return &sharedv1.ExternalChainEndpoint{
Asset: asset,
Address: endpoint.Address,
Memo: endpoint.Memo,
}, nil
}
func mapAsset(asset *srequest.Asset) (*chainv1.Asset, error) {
if asset == nil {
return nil, nil
}
chain, err := mapChainNetwork(asset.Chain)
if err != nil {
return nil, err
}
return &chainv1.Asset{
Chain: chain,
TokenSymbol: asset.TokenSymbol,
ContractAddress: asset.ContractAddress,
return &endpointv1.PaymentEndpoint{
Source: &endpointv1.PaymentEndpoint_PaymentMethod{
PaymentMethod: method,
},
}, nil
}
@@ -238,94 +237,6 @@ func mapMoney(m *paymenttypes.Money) *moneyv1.Money {
}
}
func mapFXIntent(fx *srequest.FXIntent) (*sharedv1.FXIntent, error) {
if fx == nil {
return nil, nil
}
side, err := mapFXSide(fx.Side)
if err != nil {
return nil, err
}
return &sharedv1.FXIntent{
Pair: mapCurrencyPair(fx.Pair),
Side: side,
Firm: fx.Firm,
TtlMs: fx.TTLms,
PreferredProvider: fx.PreferredProvider,
MaxAgeMs: fx.MaxAgeMs,
}, nil
}
func mapCustomer(customer *srequest.Customer) *sharedv1.Customer {
if customer == nil {
return nil
}
return &sharedv1.Customer{
Id: strings.TrimSpace(customer.ID),
FirstName: strings.TrimSpace(customer.FirstName),
MiddleName: strings.TrimSpace(customer.MiddleName),
LastName: strings.TrimSpace(customer.LastName),
Ip: strings.TrimSpace(customer.IP),
Zip: strings.TrimSpace(customer.Zip),
Country: strings.TrimSpace(customer.Country),
State: strings.TrimSpace(customer.State),
City: strings.TrimSpace(customer.City),
Address: strings.TrimSpace(customer.Address),
}
}
func mapCurrencyPair(pair *srequest.CurrencyPair) *fxv1.CurrencyPair {
if pair == nil {
return nil
}
return &fxv1.CurrencyPair{
Base: pair.Base,
Quote: pair.Quote,
}
}
func mapCardEndpoint(card *srequest.CardEndpoint) *sharedv1.CardEndpoint {
if card == nil {
return nil
}
result := &sharedv1.CardEndpoint{
CardholderName: strings.TrimSpace(card.FirstName),
CardholderSurname: strings.TrimSpace(card.LastName),
ExpMonth: card.ExpMonth,
ExpYear: card.ExpYear,
Country: strings.TrimSpace(card.Country),
}
if pan := strings.TrimSpace(card.Pan); pan != "" {
result.Card = &sharedv1.CardEndpoint_Pan{Pan: pan}
}
return result
}
func mapCardTokenEndpoint(card *srequest.CardTokenEndpoint) *sharedv1.CardEndpoint {
if card == nil {
return nil
}
return &sharedv1.CardEndpoint{
Card: &sharedv1.CardEndpoint_Token{Token: strings.TrimSpace(card.Token)},
MaskedPan: strings.TrimSpace(card.MaskedPan),
}
}
func mapPaymentKind(kind srequest.PaymentKind) (sharedv1.PaymentKind, error) {
switch strings.TrimSpace(string(kind)) {
case "", string(srequest.PaymentKindUnspecified):
return sharedv1.PaymentKind_PAYMENT_KIND_UNSPECIFIED, nil
case string(srequest.PaymentKindPayout):
return sharedv1.PaymentKind_PAYMENT_KIND_PAYOUT, nil
case string(srequest.PaymentKindInternalTransfer):
return sharedv1.PaymentKind_PAYMENT_KIND_INTERNAL_TRANSFER, nil
case string(srequest.PaymentKindFxConversion):
return sharedv1.PaymentKind_PAYMENT_KIND_FX_CONVERSION, nil
default:
return sharedv1.PaymentKind_PAYMENT_KIND_UNSPECIFIED, merrors.InvalidArgument("unsupported payment kind: " + string(kind))
}
}
func mapSettlementMode(mode srequest.SettlementMode) (paymentv1.SettlementMode, error) {
switch strings.TrimSpace(string(mode)) {
case "", string(srequest.SettlementModeUnspecified):
@@ -339,19 +250,6 @@ func mapSettlementMode(mode srequest.SettlementMode) (paymentv1.SettlementMode,
}
}
func mapFXSide(side srequest.FXSide) (fxv1.Side, error) {
switch strings.TrimSpace(string(side)) {
case "", string(srequest.FXSideUnspecified):
return fxv1.Side_SIDE_UNSPECIFIED, nil
case string(srequest.FXSideBuyBaseSellQuote):
return fxv1.Side_BUY_BASE_SELL_QUOTE, nil
case string(srequest.FXSideSellBaseBuyQuote):
return fxv1.Side_SELL_BASE_BUY_QUOTE, nil
default:
return fxv1.Side_SIDE_UNSPECIFIED, merrors.InvalidArgument("unsupported fx side: " + string(side))
}
}
func mapChainNetwork(chain srequest.ChainNetwork) (chainv1.ChainNetwork, error) {
switch strings.TrimSpace(string(chain)) {
case "", string(srequest.ChainNetworkUnspecified):
@@ -369,13 +267,14 @@ func mapChainNetwork(chain srequest.ChainNetwork) (chainv1.ChainNetwork, error)
}
}
func copyStringMap(src map[string]string) map[string]string {
if len(src) == 0 {
return nil
func uint32ToString(v uint32) string {
if v == 0 {
return ""
}
dst := make(map[string]string, len(src))
for k, v := range src {
dst[k] = v
}
return dst
return strconv.FormatUint(uint64(v), 10)
}
type ledgerMethodData struct {
LedgerAccountRef string `bson:"ledgerAccountRef"`
ContraLedgerAccountRef string `bson:"contraLedgerAccountRef,omitempty"`
}

View File

@@ -9,7 +9,9 @@ import (
"github.com/tech/sendico/pkg/merrors"
"github.com/tech/sendico/pkg/model"
"github.com/tech/sendico/pkg/mutil/mzap"
orchestratorv1 "github.com/tech/sendico/pkg/proto/payments/orchestration/v1"
tracev1 "github.com/tech/sendico/pkg/proto/common/trace/v1"
orchestrationv2 "github.com/tech/sendico/pkg/proto/payments/orchestration/v2"
quotationv2 "github.com/tech/sendico/pkg/proto/payments/quotation/v2"
sharedv1 "github.com/tech/sendico/pkg/proto/payments/shared/v1"
"github.com/tech/sendico/server/interface/api/srequest"
"github.com/tech/sendico/server/interface/api/sresponse"
@@ -58,26 +60,41 @@ func (a *PaymentAPI) initiatePayment(r *http.Request, account *model.Account, to
}
}
var intent *sharedv1.PaymentIntent
quotationRef := strings.TrimSpace(payload.QuoteRef)
intentRef := metadataValue(payload.Metadata, "intent_ref")
if payload.Intent != nil {
applyCustomerIP(payload.Intent, r.RemoteAddr)
intent, err = mapPaymentIntent(payload.Intent)
intent, err := mapQuoteIntent(payload.Intent)
if err != nil {
return response.BadPayload(a.logger, a.Name(), err)
}
quoteResp, qErr := a.quotation.QuotePayment(ctx, &quotationv2.QuotePaymentRequest{
Meta: requestMeta(orgRef.Hex(), payload.IdempotencyKey),
IdempotencyKey: strings.TrimSpace(payload.IdempotencyKey),
Intent: intent,
InitiatorRef: initiatorRef(account),
})
if qErr != nil {
a.logger.Warn("Failed to quote payment before execution", zap.Error(qErr), mzap.ObjRef("organization_ref", orgRef))
return response.Auto(a.logger, a.Name(), qErr)
}
quotationRef = strings.TrimSpace(quoteResp.GetQuote().GetQuoteRef())
if quotationRef == "" {
return response.Auto(a.logger, a.Name(), merrors.DataConflict("quotation service returned empty quote_ref"))
}
if derived := strings.TrimSpace(quoteResp.GetQuote().GetIntentRef()); derived != "" {
intentRef = derived
}
}
req := &orchestratorv1.InitiatePaymentRequest{
Meta: &sharedv1.RequestMeta{
OrganizationRef: orgRef.Hex(),
},
IdempotencyKey: strings.TrimSpace(payload.IdempotencyKey),
Intent: intent,
QuoteRef: strings.TrimSpace(payload.QuoteRef),
Metadata: payload.Metadata,
req := &orchestrationv2.ExecutePaymentRequest{
Meta: requestMeta(orgRef.Hex(), payload.IdempotencyKey),
QuotationRef: quotationRef,
IntentRef: intentRef,
ClientPaymentRef: metadataValue(payload.Metadata, "client_payment_ref"),
}
resp, err := a.execution.InitiatePayment(ctx, req)
resp, err := a.execution.ExecutePayment(ctx, req)
if err != nil {
a.logger.Warn("Failed to initiate payment", zap.Error(err), mzap.ObjRef("organization_ref", orgRef))
return response.Auto(a.logger, a.Name(), err)
@@ -101,3 +118,29 @@ func decodeInitiatePayload(r *http.Request) (*srequest.InitiatePayment, error) {
}
return payload, nil
}
func requestMeta(organizationRef string, idempotencyKey string) *sharedv1.RequestMeta {
return &sharedv1.RequestMeta{
OrganizationRef: strings.TrimSpace(organizationRef),
Trace: &tracev1.TraceContext{
IdempotencyKey: strings.TrimSpace(idempotencyKey),
},
}
}
func metadataValue(meta map[string]string, key string) string {
if len(meta) == 0 {
return ""
}
return strings.TrimSpace(meta[strings.TrimSpace(key)])
}
func initiatorRef(account *model.Account) string {
if account == nil {
return ""
}
if account.ID != bson.NilObjectID {
return account.ID.Hex()
}
return strings.TrimSpace(account.Login)
}

View File

@@ -8,8 +8,7 @@ import (
"github.com/tech/sendico/pkg/api/http/response"
"github.com/tech/sendico/pkg/merrors"
"github.com/tech/sendico/pkg/model"
orchestratorv1 "github.com/tech/sendico/pkg/proto/payments/orchestration/v1"
sharedv1 "github.com/tech/sendico/pkg/proto/payments/shared/v1"
orchestrationv2 "github.com/tech/sendico/pkg/proto/payments/orchestration/v2"
"github.com/tech/sendico/server/interface/api/srequest"
"github.com/tech/sendico/server/interface/api/sresponse"
mutil "github.com/tech/sendico/server/internal/mutil/param"
@@ -40,22 +39,24 @@ func (a *PaymentAPI) initiatePaymentsByQuote(r *http.Request, account *model.Acc
return response.BadPayload(a.logger, a.Name(), err)
}
req := &orchestratorv1.InitiatePaymentsRequest{
Meta: &sharedv1.RequestMeta{
OrganizationRef: orgRef.Hex(),
},
IdempotencyKey: strings.TrimSpace(payload.IdempotencyKey),
QuoteRef: strings.TrimSpace(payload.QuoteRef),
Metadata: payload.Metadata,
req := &orchestrationv2.ExecutePaymentRequest{
Meta: requestMeta(orgRef.Hex(), payload.IdempotencyKey),
QuotationRef: strings.TrimSpace(payload.QuoteRef),
IntentRef: metadataValue(payload.Metadata, "intent_ref"),
ClientPaymentRef: metadataValue(payload.Metadata, "client_payment_ref"),
}
resp, err := a.execution.InitiatePayments(ctx, req)
resp, err := a.execution.ExecutePayment(ctx, req)
if err != nil {
a.logger.Warn("Failed to initiate batch payments", zap.Error(err), zap.String("organization_ref", orgRef.Hex()))
return response.Auto(a.logger, a.Name(), err)
}
return sresponse.PaymentsResponse(a.logger, resp.GetPayments(), token)
payments := make([]*orchestrationv2.Payment, 0, 1)
if payment := resp.GetPayment(); payment != nil {
payments = append(payments, payment)
}
return sresponse.PaymentsResponse(a.logger, payments, token)
}
func decodeInitiatePaymentsPayload(r *http.Request) (*srequest.InitiatePayments, error) {

View File

@@ -8,8 +8,7 @@ import (
"github.com/tech/sendico/pkg/api/http/response"
"github.com/tech/sendico/pkg/merrors"
"github.com/tech/sendico/pkg/model"
quotationv1 "github.com/tech/sendico/pkg/proto/payments/quotation/v1"
sharedv1 "github.com/tech/sendico/pkg/proto/payments/shared/v1"
quotationv2 "github.com/tech/sendico/pkg/proto/payments/quotation/v2"
"github.com/tech/sendico/server/interface/api/srequest"
"github.com/tech/sendico/server/interface/api/sresponse"
mutil "github.com/tech/sendico/server/internal/mutil/param"
@@ -46,18 +45,18 @@ func (a *PaymentAPI) quotePayment(r *http.Request, account *model.Account, token
}
applyCustomerIP(&payload.Intent, r.RemoteAddr)
intent, err := mapPaymentIntent(&payload.Intent)
intent, err := mapQuoteIntent(&payload.Intent)
if err != nil {
a.logger.Debug("Failed to map payment intent", zap.Error(err), mutil.PLog(a.oph, r))
return response.BadPayload(a.logger, a.Name(), err)
}
req := &quotationv1.QuotePaymentRequest{
Meta: &sharedv1.RequestMeta{
OrganizationRef: orgRef.Hex(),
},
req := &quotationv2.QuotePaymentRequest{
Meta: requestMeta(orgRef.Hex(), payload.IdempotencyKey),
IdempotencyKey: payload.IdempotencyKey,
Intent: intent,
PreviewOnly: payload.PreviewOnly,
InitiatorRef: initiatorRef(account),
}
resp, err := a.quotation.QuotePayment(ctx, req)
@@ -97,10 +96,10 @@ func (a *PaymentAPI) quotePayments(r *http.Request, account *model.Account, toke
return response.Auto(a.logger, a.Name(), err)
}
intents := make([]*sharedv1.PaymentIntent, 0, len(payload.Intents))
intents := make([]*quotationv2.QuoteIntent, 0, len(payload.Intents))
for i := range payload.Intents {
applyCustomerIP(&payload.Intents[i], r.RemoteAddr)
intent, err := mapPaymentIntent(&payload.Intents[i])
intent, err := mapQuoteIntent(&payload.Intents[i])
if err != nil {
a.logger.Debug("Failed to map payment intent", zap.Error(err), mutil.PLog(a.oph, r))
return response.BadPayload(a.logger, a.Name(), err)
@@ -108,13 +107,12 @@ func (a *PaymentAPI) quotePayments(r *http.Request, account *model.Account, toke
intents = append(intents, intent)
}
req := &quotationv1.QuotePaymentsRequest{
Meta: &sharedv1.RequestMeta{
OrganizationRef: orgRef.Hex(),
},
req := &quotationv2.QuotePaymentsRequest{
Meta: requestMeta(orgRef.Hex(), payload.IdempotencyKey),
IdempotencyKey: payload.IdempotencyKey,
Intents: intents,
PreviewOnly: payload.PreviewOnly,
InitiatorRef: initiatorRef(account),
}
resp, err := a.quotation.QuotePayments(ctx, req)

View File

@@ -18,8 +18,8 @@ import (
msgconsumer "github.com/tech/sendico/pkg/messaging/consumer"
"github.com/tech/sendico/pkg/mlogger"
"github.com/tech/sendico/pkg/mservice"
orchestratorv1 "github.com/tech/sendico/pkg/proto/payments/orchestration/v1"
quotationv1 "github.com/tech/sendico/pkg/proto/payments/quotation/v1"
orchestrationv2 "github.com/tech/sendico/pkg/proto/payments/orchestration/v2"
quotationv2 "github.com/tech/sendico/pkg/proto/payments/quotation/v2"
eapi "github.com/tech/sendico/server/interface/api"
mutil "github.com/tech/sendico/server/internal/mutil/param"
"go.mongodb.org/mongo-driver/v2/bson"
@@ -30,15 +30,14 @@ import (
)
type executionClient interface {
InitiatePayments(ctx context.Context, req *orchestratorv1.InitiatePaymentsRequest) (*orchestratorv1.InitiatePaymentsResponse, error)
InitiatePayment(ctx context.Context, req *orchestratorv1.InitiatePaymentRequest) (*orchestratorv1.InitiatePaymentResponse, error)
ListPayments(ctx context.Context, req *orchestratorv1.ListPaymentsRequest) (*orchestratorv1.ListPaymentsResponse, error)
ExecutePayment(ctx context.Context, req *orchestrationv2.ExecutePaymentRequest) (*orchestrationv2.ExecutePaymentResponse, error)
ListPayments(ctx context.Context, req *orchestrationv2.ListPaymentsRequest) (*orchestrationv2.ListPaymentsResponse, error)
Close() error
}
type quotationClient interface {
QuotePayment(ctx context.Context, req *quotationv1.QuotePaymentRequest) (*quotationv1.QuotePaymentResponse, error)
QuotePayments(ctx context.Context, req *quotationv1.QuotePaymentsRequest) (*quotationv1.QuotePaymentsResponse, error)
QuotePayment(ctx context.Context, req *quotationv2.QuotePaymentRequest) (*quotationv2.QuotePaymentResponse, error)
QuotePayments(ctx context.Context, req *quotationv2.QuotePaymentsRequest) (*quotationv2.QuotePaymentsResponse, error)
Close() error
}
@@ -203,7 +202,7 @@ func (c *quotationClientConfig) setDefaults() {
type grpcQuotationClient struct {
conn *grpc.ClientConn
client quotationv1.QuotationServiceClient
client quotationv2.QuotationServiceClient
callTimeout time.Duration
}
@@ -230,7 +229,7 @@ func newQuotationClient(ctx context.Context, cfg quotationClientConfig, opts ...
}
return &grpcQuotationClient{
conn: conn,
client: quotationv1.NewQuotationServiceClient(conn),
client: quotationv2.NewQuotationServiceClient(conn),
callTimeout: cfg.CallTimeout,
}, nil
}
@@ -242,13 +241,13 @@ func (c *grpcQuotationClient) Close() error {
return c.conn.Close()
}
func (c *grpcQuotationClient) QuotePayment(ctx context.Context, req *quotationv1.QuotePaymentRequest) (*quotationv1.QuotePaymentResponse, error) {
func (c *grpcQuotationClient) QuotePayment(ctx context.Context, req *quotationv2.QuotePaymentRequest) (*quotationv2.QuotePaymentResponse, error) {
callCtx, cancel := c.callContext(ctx)
defer cancel()
return c.client.QuotePayment(callCtx, req)
}
func (c *grpcQuotationClient) QuotePayments(ctx context.Context, req *quotationv1.QuotePaymentsRequest) (*quotationv1.QuotePaymentsResponse, error) {
func (c *grpcQuotationClient) QuotePayments(ctx context.Context, req *quotationv2.QuotePaymentsRequest) (*quotationv2.QuotePaymentsResponse, error) {
callCtx, cancel := c.callContext(ctx)
defer cancel()
return c.client.QuotePayments(callCtx, req)