From f2938daddd7bca965cf7e59592dcf8fd18b1f32e Mon Sep 17 00:00:00 2001 From: Stephan D Date: Tue, 10 Feb 2026 13:36:45 +0100 Subject: [PATCH] improved storing --- .../service/gateway/card_payout_store_test.go | 4 +-- .../service/gateway/card_processor.go | 28 +++++++++---------- .../service/gateway/card_processor_test.go | 4 +-- .../mntx/internal/service/gateway/helpers.go | 4 +-- .../service/gateway/transfer_notifications.go | 22 ++++++++++----- api/gateway/mntx/storage/model/state.go | 1 - .../mntx/storage/mongo/store/payouts.go | 6 ++-- 7 files changed, 38 insertions(+), 31 deletions(-) diff --git a/api/gateway/mntx/internal/service/gateway/card_payout_store_test.go b/api/gateway/mntx/internal/service/gateway/card_payout_store_test.go index 33889fe4..e9254ca9 100644 --- a/api/gateway/mntx/internal/service/gateway/card_payout_store_test.go +++ b/api/gateway/mntx/internal/service/gateway/card_payout_store_test.go @@ -51,13 +51,13 @@ func (s *cardPayoutStore) FindByPaymentID(_ context.Context, id string) (*model. } func (s *cardPayoutStore) Upsert(_ context.Context, record *model.CardPayout) error { - s.data[record.PayoutID] = record + s.data[record.PaymentRef] = record return nil } // Save is a helper for tests to pre-populate data. func (s *cardPayoutStore) Save(state *model.CardPayout) { - s.data[state.PayoutID] = state + s.data[state.PaymentRef] = state } // Get is a helper for tests to retrieve data. diff --git a/api/gateway/mntx/internal/service/gateway/card_processor.go b/api/gateway/mntx/internal/service/gateway/card_processor.go index f5486e1a..db2ba940 100644 --- a/api/gateway/mntx/internal/service/gateway/card_processor.go +++ b/api/gateway/mntx/internal/service/gateway/card_processor.go @@ -92,7 +92,7 @@ func (p *cardPayoutProcessor) Submit(ctx context.Context, req *mntxv1.CardPayout Base: storable.Base{ ID: bson.NilObjectID, }, - PayoutID: strings.TrimSpace(req.GetPayoutId()), + PaymentRef: strings.TrimSpace(req.GetPayoutId()), OperationRef: strings.TrimSpace(req.GetOperationRef()), IdempotencyKey: strings.TrimSpace(req.GetIdempotencyKey()), IntentRef: strings.TrimSpace(req.GetIntentRef()), @@ -106,7 +106,7 @@ func (p *cardPayoutProcessor) Submit(ctx context.Context, req *mntxv1.CardPayout } // Keep CreatedAt/refs if record already exists. - if existing, err := p.store.Payouts().FindByPaymentID(ctx, state.PayoutID); err == nil && existing != nil { + if existing, err := p.store.Payouts().FindByPaymentID(ctx, state.PaymentRef); err == nil && existing != nil { if !existing.CreatedAt.IsZero() { state.CreatedAt = existing.CreatedAt } @@ -130,7 +130,7 @@ func (p *cardPayoutProcessor) Submit(ctx context.Context, req *mntxv1.CardPayout if e := p.updatePayoutStatus(ctx, state); e != nil { p.logger.Warn("Failed to update payout status", zap.Error(e), - zap.String("payout_id", state.PayoutID), + zap.String("payment_ref", state.PaymentRef), zap.String("customer_id", state.CustomerID), zap.String("operation_ref", state.OperationRef), zap.String("idempotency_key", state.IdempotencyKey), @@ -141,7 +141,7 @@ func (p *cardPayoutProcessor) Submit(ctx context.Context, req *mntxv1.CardPayout p.logger.Warn("Monetix payout submission failed", zap.Error(err), - zap.String("payout_id", state.PayoutID), + zap.String("payment_ref", state.PaymentRef), zap.String("customer_id", state.CustomerID), zap.String("operation_ref", state.OperationRef), zap.String("idempotency_key", state.IdempotencyKey), @@ -166,7 +166,7 @@ func (p *cardPayoutProcessor) Submit(ctx context.Context, req *mntxv1.CardPayout if err := p.updatePayoutStatus(ctx, state); err != nil { p.logger.Warn("Failed to store payout", zap.Error(err), - zap.String("payout_id", state.PayoutID), + zap.String("payment_ref", state.PaymentRef), zap.String("customer_id", state.CustomerID), zap.String("operation_ref", state.OperationRef), zap.String("idempotency_key", state.IdempotencyKey), @@ -183,7 +183,7 @@ func (p *cardPayoutProcessor) Submit(ctx context.Context, req *mntxv1.CardPayout } p.logger.Info("Card payout submission stored", - zap.String("payout_id", state.PayoutID), + zap.String("payment_ref", state.PaymentRef), zap.String("status", string(state.Status)), zap.Bool("accepted", result.Accepted), zap.String("provider_request_id", result.ProviderRequestID), @@ -233,7 +233,7 @@ func (p *cardPayoutProcessor) SubmitToken(ctx context.Context, req *mntxv1.CardT now := p.clock.Now() state := &model.CardPayout{ - PayoutID: strings.TrimSpace(req.GetPayoutId()), + PaymentRef: strings.TrimSpace(req.GetPayoutId()), OperationRef: strings.TrimSpace(req.GetOperationRef()), IdempotencyKey: strings.TrimSpace(req.GetIdempotencyKey()), ProjectID: projectID, @@ -245,7 +245,7 @@ func (p *cardPayoutProcessor) SubmitToken(ctx context.Context, req *mntxv1.CardT UpdatedAt: now, } - if existing, err := p.store.Payouts().FindByPaymentID(ctx, state.PayoutID); err == nil && existing != nil { + if existing, err := p.store.Payouts().FindByPaymentID(ctx, state.PaymentRef); err == nil && existing != nil { if !existing.CreatedAt.IsZero() { state.CreatedAt = existing.CreatedAt } @@ -269,7 +269,7 @@ func (p *cardPayoutProcessor) SubmitToken(ctx context.Context, req *mntxv1.CardT _ = p.updatePayoutStatus(ctx, state) p.logger.Warn("Monetix token payout submission failed", - zap.String("payout_id", state.PayoutID), + zap.String("payment_ref", state.PaymentRef), zap.String("customer_id", state.CustomerID), zap.Error(err), ) @@ -301,7 +301,7 @@ func (p *cardPayoutProcessor) SubmitToken(ctx context.Context, req *mntxv1.CardT } p.logger.Info("Card token payout submission stored", - zap.String("payout_id", state.PayoutID), + zap.String("payment_ref", state.PaymentRef), zap.String("status", string(state.Status)), zap.Bool("accepted", result.Accepted), zap.String("provider_request_id", result.ProviderRequestID), @@ -396,7 +396,7 @@ func (p *cardPayoutProcessor) Status(ctx context.Context, payoutID string) (*mnt } p.logger.Info("Card payout status resolved", - zap.String("payout_id", state.PayoutID), + zap.String("payment_ref", state.PaymentRef), zap.String("status", string(state.Status)), ) @@ -449,10 +449,10 @@ func (p *cardPayoutProcessor) ProcessCallback(ctx context.Context, payload []byt state := CardPayoutStateFromProto(p.clock, pbState) // Preserve CreatedAt + internal keys from existing record if present. - if existing, err := p.store.Payouts().FindByPaymentID(ctx, state.PayoutID); err != nil { + if existing, err := p.store.Payouts().FindByPaymentID(ctx, state.PaymentRef); err != nil { p.logger.Warn("Failed to fetch payout state while processing callback", zap.Error(err), - zap.String("payout_id", state.PayoutID), + zap.String("payment_ref", state.PaymentRef), ) return http.StatusInternalServerError, err } else if existing != nil { @@ -477,7 +477,7 @@ func (p *cardPayoutProcessor) ProcessCallback(ctx context.Context, payload []byt monetix.ObserveCallback(statusLabel) p.logger.Info("Monetix payout callback processed", - zap.String("payout_id", state.PayoutID), + zap.String("payment_ref", state.PaymentRef), zap.String("status", statusLabel), zap.String("provider_code", state.ProviderCode), zap.String("provider_message", state.ProviderMessage), diff --git a/api/gateway/mntx/internal/service/gateway/card_processor_test.go b/api/gateway/mntx/internal/service/gateway/card_processor_test.go index 126f093b..e1342ab1 100644 --- a/api/gateway/mntx/internal/service/gateway/card_processor_test.go +++ b/api/gateway/mntx/internal/service/gateway/card_processor_test.go @@ -44,8 +44,8 @@ func TestCardPayoutProcessor_Submit_Success(t *testing.T) { repo := newMockRepository() repo.payouts.Save(&model.CardPayout{ - PayoutID: "payout-1", - CreatedAt: existingCreated, + PaymentRef: "payout-1", + CreatedAt: existingCreated, }) httpClient := &http.Client{ diff --git a/api/gateway/mntx/internal/service/gateway/helpers.go b/api/gateway/mntx/internal/service/gateway/helpers.go index 0c2078f1..13311b52 100644 --- a/api/gateway/mntx/internal/service/gateway/helpers.go +++ b/api/gateway/mntx/internal/service/gateway/helpers.go @@ -22,7 +22,7 @@ func CardPayoutStateFromProto(clock clockpkg.Clock, p *mntxv1.CardPayoutState) * } return &model.CardPayout{ - PayoutID: p.PayoutId, + PaymentRef: p.PayoutId, OperationRef: p.GetOperationRef(), IntentRef: p.GetIntentRef(), IdempotencyKey: p.GetIdempotencyKey(), @@ -41,7 +41,7 @@ func CardPayoutStateFromProto(clock clockpkg.Clock, p *mntxv1.CardPayoutState) * func StateToProto(m *model.CardPayout) *mntxv1.CardPayoutState { return &mntxv1.CardPayoutState{ - PayoutId: m.PayoutID, + PayoutId: m.PaymentRef, ProjectId: m.ProjectID, CustomerId: m.CustomerID, AmountMinor: m.AmountMinor, diff --git a/api/gateway/mntx/internal/service/gateway/transfer_notifications.go b/api/gateway/mntx/internal/service/gateway/transfer_notifications.go index 5fb6b901..29078d28 100644 --- a/api/gateway/mntx/internal/service/gateway/transfer_notifications.go +++ b/api/gateway/mntx/internal/service/gateway/transfer_notifications.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/tech/sendico/gateway/mntx/storage/model" + "github.com/tech/sendico/pkg/merrors" paymentgateway "github.com/tech/sendico/pkg/messaging/notifications/paymentgateway" pmodel "github.com/tech/sendico/pkg/model" "github.com/tech/sendico/pkg/mservice" @@ -23,23 +24,23 @@ func isFinalStatus(t *model.CardPayout) bool { } } -func toOpStatus(t *model.CardPayout) rail.OperationResult { +func toOpStatus(t *model.CardPayout) (rail.OperationResult, error) { switch t.Status { case model.PayoutStatusFailed: - return rail.OperationResultFailed + return rail.OperationResultFailed, nil case model.PayoutStatusSuccess: - return rail.OperationResultSuccess + return rail.OperationResultSuccess, nil case model.PayoutStatusCancelled: - return rail.OperationResultCancelled + return rail.OperationResultCancelled, nil default: - panic(fmt.Sprintf("unexpected transfer status, %s", t.Status)) + return rail.OperationResultFailed, merrors.InvalidArgument(fmt.Sprintf("unexpected transfer status, %s", t.Status), "t.Status") } } func (p *cardPayoutProcessor) updatePayoutStatus(ctx context.Context, state *model.CardPayout) error { if err := p.store.Payouts().Upsert(ctx, state); err != nil { p.logger.Warn("Failed to update transfer status", zap.Error(err), mzap.ObjRef("payout_ref", state.ID), - zap.String("transfer_ref", state.PayoutID), zap.String("status", string(state.Status)), + zap.String("payment_ref", state.PaymentRef), zap.String("status", string(state.Status)), ) } if isFinalStatus(state) { @@ -53,6 +54,13 @@ func (p *cardPayoutProcessor) emitTransferStatusEvent(payout *model.CardPayout) return } + status, err := toOpStatus(payout) + if err != nil { + p.logger.Warn("Failed to convert payout status to operation status for transfer status event", zap.Error(err), + mzap.ObjRef("payout_ref", payout.ID), zap.String("payment_ref", payout.PaymentRef), zap.String("status", string(payout.Status))) + return + } + exec := pmodel.PaymentGatewayExecution{ PaymentIntentID: payout.IntentRef, IdempotencyKey: payout.IdempotencyKey, @@ -61,7 +69,7 @@ func (p *cardPayoutProcessor) emitTransferStatusEvent(payout *model.CardPayout) Currency: payout.Currency, }, PaymentRef: payout.PaymentRef, - Status: toOpStatus(payout), + Status: status, OperationRef: payout.OperationRef, Error: payout.FailureReason, TransferRef: payout.GetID().Hex(), diff --git a/api/gateway/mntx/storage/model/state.go b/api/gateway/mntx/storage/model/state.go index 70a9996e..be91e760 100644 --- a/api/gateway/mntx/storage/model/state.go +++ b/api/gateway/mntx/storage/model/state.go @@ -9,7 +9,6 @@ import ( // CardPayout is a Mongo/JSON representation of proto CardPayout type CardPayout struct { storable.Base `bson:",inline" json:",inline"` - PayoutID string `bson:"payoutId" json:"payout_id"` PaymentRef string `bson:"paymentRef" json:"payment_ref"` OperationRef string `bson:"operationRef" json:"operation_ref"` IdempotencyKey string `bson:"idempotencyKey" json:"idempotency_key"` diff --git a/api/gateway/mntx/storage/mongo/store/payouts.go b/api/gateway/mntx/storage/mongo/store/payouts.go index dc0d799e..183d9d9f 100644 --- a/api/gateway/mntx/storage/mongo/store/payouts.go +++ b/api/gateway/mntx/storage/mongo/store/payouts.go @@ -18,7 +18,7 @@ import ( const ( payoutsCollection = "card_payouts" payoutIdemField = "idempotencyKey" - payoutIdField = "payoutId" + payoutIdField = "paymentRef" ) type Payouts struct { @@ -74,7 +74,7 @@ func (p *Payouts) Upsert(ctx context.Context, record *model.CardPayout) error { } record.OperationRef = strings.TrimSpace(record.OperationRef) - record.PayoutID = strings.TrimSpace(record.PayoutID) + record.PaymentRef = strings.TrimSpace(record.PaymentRef) record.CustomerID = strings.TrimSpace(record.CustomerID) record.ProviderCode = strings.TrimSpace(record.ProviderCode) record.ProviderPaymentID = strings.TrimSpace(record.ProviderPaymentID) @@ -86,7 +86,7 @@ func (p *Payouts) Upsert(ctx context.Context, record *model.CardPayout) error { if err := p.repository.Upsert(ctx, record); err != nil { p.logger.Warn("Failed to upsert payout record", zap.Error(err), mzap.ObjRef("payout_ref", record.ID), - zap.String("operation_ref", record.OperationRef), zap.String("payment_ref", record.PayoutID)) + zap.String("operation_ref", record.OperationRef), zap.String("payment_ref", record.PaymentRef)) return err } return nil -- 2.49.1