improved storing

This commit is contained in:
Stephan D
2026-02-10 13:36:45 +01:00
parent 461a340b08
commit f2938daddd
7 changed files with 38 additions and 31 deletions

View File

@@ -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.

View File

@@ -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),

View File

@@ -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{

View File

@@ -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,

View File

@@ -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(),

View File

@@ -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"`

View File

@@ -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