outbox for gateways
This commit is contained in:
@@ -18,6 +18,7 @@ import (
|
||||
type Client interface {
|
||||
CreatePaymentMethod(ctx context.Context, req *methodsv1.CreatePaymentMethodRequest) (*methodsv1.CreatePaymentMethodResponse, error)
|
||||
GetPaymentMethod(ctx context.Context, req *methodsv1.GetPaymentMethodRequest) (*methodsv1.GetPaymentMethodResponse, error)
|
||||
GetPaymentMethodPrivate(ctx context.Context, req *methodsv1.GetPaymentMethodPrivateRequest) (*methodsv1.GetPaymentMethodPrivateResponse, error)
|
||||
UpdatePaymentMethod(ctx context.Context, req *methodsv1.UpdatePaymentMethodRequest) (*methodsv1.UpdatePaymentMethodResponse, error)
|
||||
DeletePaymentMethod(ctx context.Context, req *methodsv1.DeletePaymentMethodRequest) (*methodsv1.DeletePaymentMethodResponse, error)
|
||||
SetPaymentMethodArchived(ctx context.Context, req *methodsv1.SetPaymentMethodArchivedRequest) (*methodsv1.SetPaymentMethodArchivedResponse, error)
|
||||
@@ -28,6 +29,7 @@ type Client interface {
|
||||
type grpcPaymentMethodsClient interface {
|
||||
CreatePaymentMethod(ctx context.Context, in *methodsv1.CreatePaymentMethodRequest, opts ...grpc.CallOption) (*methodsv1.CreatePaymentMethodResponse, error)
|
||||
GetPaymentMethod(ctx context.Context, in *methodsv1.GetPaymentMethodRequest, opts ...grpc.CallOption) (*methodsv1.GetPaymentMethodResponse, error)
|
||||
GetPaymentMethodPrivate(ctx context.Context, in *methodsv1.GetPaymentMethodPrivateRequest, opts ...grpc.CallOption) (*methodsv1.GetPaymentMethodPrivateResponse, error)
|
||||
UpdatePaymentMethod(ctx context.Context, in *methodsv1.UpdatePaymentMethodRequest, opts ...grpc.CallOption) (*methodsv1.UpdatePaymentMethodResponse, error)
|
||||
DeletePaymentMethod(ctx context.Context, in *methodsv1.DeletePaymentMethodRequest, opts ...grpc.CallOption) (*methodsv1.DeletePaymentMethodResponse, error)
|
||||
SetPaymentMethodArchived(ctx context.Context, in *methodsv1.SetPaymentMethodArchivedRequest, opts ...grpc.CallOption) (*methodsv1.SetPaymentMethodArchivedResponse, error)
|
||||
@@ -106,6 +108,12 @@ func (c *paymentMethodsClient) GetPaymentMethod(ctx context.Context, req *method
|
||||
return c.client.GetPaymentMethod(callCtx, req)
|
||||
}
|
||||
|
||||
func (c *paymentMethodsClient) GetPaymentMethodPrivate(ctx context.Context, req *methodsv1.GetPaymentMethodPrivateRequest) (*methodsv1.GetPaymentMethodPrivateResponse, error) {
|
||||
callCtx, cancel := c.callContext(ctx)
|
||||
defer cancel()
|
||||
return c.client.GetPaymentMethodPrivate(callCtx, req)
|
||||
}
|
||||
|
||||
func (c *paymentMethodsClient) UpdatePaymentMethod(ctx context.Context, req *methodsv1.UpdatePaymentMethodRequest) (*methodsv1.UpdatePaymentMethodResponse, error) {
|
||||
callCtx, cancel := c.callContext(ctx)
|
||||
defer cancel()
|
||||
|
||||
@@ -48,5 +48,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-20260209200024-4cfbd4190f57 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260217215200-42d3e9bedb6d // indirect
|
||||
)
|
||||
|
||||
@@ -208,8 +208,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=
|
||||
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/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||
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/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=
|
||||
|
||||
@@ -51,7 +51,7 @@ func (i *Imp) Start() error {
|
||||
|
||||
permissionsDB := cfg.PermissionsDatabase
|
||||
if permissionsDB == nil {
|
||||
i.logger.Info("permissions_database is not configured, falling back to database settings")
|
||||
i.logger.Info("Permissions_database is not configured, falling back to database settings")
|
||||
permissionsDB = cfg.Database
|
||||
}
|
||||
|
||||
|
||||
168
api/payments/methods/internal/service/methods/get_private.go
Normal file
168
api/payments/methods/internal/service/methods/get_private.go
Normal file
@@ -0,0 +1,168 @@
|
||||
package methods
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
pkgmodel "github.com/tech/sendico/pkg/model"
|
||||
methodsv1 "github.com/tech/sendico/pkg/proto/payments/methods/v1"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
)
|
||||
|
||||
const (
|
||||
paymentTypeAccount pkgmodel.PaymentType = 8
|
||||
maxPrivateMethodResolutionDepth = 8
|
||||
)
|
||||
|
||||
func (s *Service) GetPaymentMethodPrivate(ctx context.Context, req *methodsv1.GetPaymentMethodPrivateRequest) (*methodsv1.GetPaymentMethodPrivateResponse, error) {
|
||||
if req == nil {
|
||||
return autoError[methodsv1.GetPaymentMethodPrivateResponse](ctx, s.logger, merrors.InvalidArgument("request is required"))
|
||||
}
|
||||
if s.pmstore == nil {
|
||||
return autoError[methodsv1.GetPaymentMethodPrivateResponse](ctx, s.logger, errStoreUnavailable)
|
||||
}
|
||||
|
||||
if req.GetEndpoint() == methodsv1.PrivateEndpoint_PRIVATE_ENDPOINT_UNSPECIFIED {
|
||||
return autoError[methodsv1.GetPaymentMethodPrivateResponse](ctx, s.logger, merrors.InvalidArgument("endpoint is required", "endpoint"))
|
||||
}
|
||||
|
||||
organizationRef, err := parseObjectID(req.GetOrganizationRef(), "organization_ref")
|
||||
if err != nil {
|
||||
return autoError[methodsv1.GetPaymentMethodPrivateResponse](ctx, s.logger, err)
|
||||
}
|
||||
|
||||
var resolved *pkgmodel.PaymentMethod
|
||||
switch req.GetSelector().(type) {
|
||||
case *methodsv1.GetPaymentMethodPrivateRequest_PaymentMethodRef:
|
||||
methodRef, err := parseObjectID(req.GetPaymentMethodRef(), "payment_method_ref")
|
||||
if err != nil {
|
||||
return autoError[methodsv1.GetPaymentMethodPrivateResponse](ctx, s.logger, err)
|
||||
}
|
||||
resolved, err = s.resolvePrivateByMethodRef(ctx, organizationRef, methodRef, req.GetEndpoint(), 0)
|
||||
if err != nil {
|
||||
return autoError[methodsv1.GetPaymentMethodPrivateResponse](ctx, s.logger, err)
|
||||
}
|
||||
case *methodsv1.GetPaymentMethodPrivateRequest_PayeeRef:
|
||||
payeeRef, err := parseObjectID(req.GetPayeeRef(), "payee_ref")
|
||||
if err != nil {
|
||||
return autoError[methodsv1.GetPaymentMethodPrivateResponse](ctx, s.logger, err)
|
||||
}
|
||||
resolved, err = s.resolvePrivateByRecipientRef(ctx, organizationRef, payeeRef, req.GetEndpoint(), 0)
|
||||
if err != nil {
|
||||
return autoError[methodsv1.GetPaymentMethodPrivateResponse](ctx, s.logger, err)
|
||||
}
|
||||
default:
|
||||
return autoError[methodsv1.GetPaymentMethodPrivateResponse](ctx, s.logger, merrors.InvalidArgument(
|
||||
"selector must include payment_method_ref or payee_ref",
|
||||
"selector",
|
||||
))
|
||||
}
|
||||
|
||||
record, err := encodePaymentMethodRecord(resolved)
|
||||
if err != nil {
|
||||
return autoError[methodsv1.GetPaymentMethodPrivateResponse](ctx, s.logger, err)
|
||||
}
|
||||
|
||||
return &methodsv1.GetPaymentMethodPrivateResponse{
|
||||
PaymentMethodRecord: record,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Service) resolvePrivateByMethodRef(
|
||||
ctx context.Context,
|
||||
organizationRef bson.ObjectID,
|
||||
methodRef bson.ObjectID,
|
||||
endpoint methodsv1.PrivateEndpoint,
|
||||
depth int,
|
||||
) (*pkgmodel.PaymentMethod, error) {
|
||||
method, err := s.pmstore.GetPrivate(ctx, methodRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.resolvePrivateMethod(ctx, organizationRef, method, endpoint, depth)
|
||||
}
|
||||
|
||||
func (s *Service) resolvePrivateByRecipientRef(
|
||||
ctx context.Context,
|
||||
organizationRef bson.ObjectID,
|
||||
recipientRef bson.ObjectID,
|
||||
endpoint methodsv1.PrivateEndpoint,
|
||||
depth int,
|
||||
) (*pkgmodel.PaymentMethod, error) {
|
||||
items, err := s.pmstore.ListPrivate(ctx, organizationRef, recipientRef, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(items) == 0 {
|
||||
return nil, merrors.InvalidArgument("no payment methods available for recipient")
|
||||
}
|
||||
|
||||
selected := pickPreferredPrivateMethod(items, endpoint)
|
||||
if selected == nil {
|
||||
return nil, merrors.InvalidArgument("no routable payment methods available for recipient")
|
||||
}
|
||||
return s.resolvePrivateMethod(ctx, organizationRef, selected, endpoint, depth)
|
||||
}
|
||||
|
||||
func (s *Service) resolvePrivateMethod(
|
||||
ctx context.Context,
|
||||
organizationRef bson.ObjectID,
|
||||
method *pkgmodel.PaymentMethod,
|
||||
endpoint methodsv1.PrivateEndpoint,
|
||||
depth int,
|
||||
) (*pkgmodel.PaymentMethod, error) {
|
||||
if method == nil {
|
||||
return nil, merrors.InvalidArgument("payment method is required")
|
||||
}
|
||||
if depth >= maxPrivateMethodResolutionDepth {
|
||||
return nil, merrors.InvalidArgument("payment method resolution depth exceeded")
|
||||
}
|
||||
|
||||
if methodIsAccount(method) {
|
||||
if method.RecipientRef.IsZero() {
|
||||
return nil, merrors.InvalidArgument("account payment method recipient_ref is required")
|
||||
}
|
||||
return s.resolvePrivateByRecipientRef(ctx, organizationRef, method.RecipientRef, endpoint, depth+1)
|
||||
}
|
||||
return method, nil
|
||||
}
|
||||
|
||||
func methodIsAccount(method *pkgmodel.PaymentMethod) bool {
|
||||
if method == nil {
|
||||
return false
|
||||
}
|
||||
return method.Type == paymentTypeAccount
|
||||
}
|
||||
|
||||
func pickPreferredPrivateMethod(items []pkgmodel.PaymentMethod, endpoint methodsv1.PrivateEndpoint) *pkgmodel.PaymentMethod {
|
||||
switch endpoint {
|
||||
case methodsv1.PrivateEndpoint_PRIVATE_ENDPOINT_SOURCE:
|
||||
return pickMainThenAnyNonAccount(items)
|
||||
case methodsv1.PrivateEndpoint_PRIVATE_ENDPOINT_DESTINATION:
|
||||
return pickMainThenAnyNonAccount(items)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func pickMainThenAnyNonAccount(items []pkgmodel.PaymentMethod) *pkgmodel.PaymentMethod {
|
||||
for i := range items {
|
||||
if items[i].IsMain && !methodIsAccount(&items[i]) {
|
||||
return &items[i]
|
||||
}
|
||||
}
|
||||
for i := range items {
|
||||
if !methodIsAccount(&items[i]) {
|
||||
return &items[i]
|
||||
}
|
||||
}
|
||||
for i := range items {
|
||||
if items[i].IsMain {
|
||||
return &items[i]
|
||||
}
|
||||
}
|
||||
if len(items) == 0 {
|
||||
return nil
|
||||
}
|
||||
return &items[0]
|
||||
}
|
||||
Reference in New Issue
Block a user