Merge pull request 'improved storing' (#456) from mntx-452 into main
All checks were successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
All checks were successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
Reviewed-on: #456
This commit was merged in pull request #456.
This commit is contained in:
@@ -51,13 +51,13 @@ func (s *cardPayoutStore) FindByPaymentID(_ context.Context, id string) (*model.
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *cardPayoutStore) Upsert(_ context.Context, record *model.CardPayout) error {
|
func (s *cardPayoutStore) Upsert(_ context.Context, record *model.CardPayout) error {
|
||||||
s.data[record.PayoutID] = record
|
s.data[record.PaymentRef] = record
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save is a helper for tests to pre-populate data.
|
// Save is a helper for tests to pre-populate data.
|
||||||
func (s *cardPayoutStore) Save(state *model.CardPayout) {
|
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.
|
// Get is a helper for tests to retrieve data.
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ func (p *cardPayoutProcessor) Submit(ctx context.Context, req *mntxv1.CardPayout
|
|||||||
Base: storable.Base{
|
Base: storable.Base{
|
||||||
ID: bson.NilObjectID,
|
ID: bson.NilObjectID,
|
||||||
},
|
},
|
||||||
PayoutID: strings.TrimSpace(req.GetPayoutId()),
|
PaymentRef: strings.TrimSpace(req.GetPayoutId()),
|
||||||
OperationRef: strings.TrimSpace(req.GetOperationRef()),
|
OperationRef: strings.TrimSpace(req.GetOperationRef()),
|
||||||
IdempotencyKey: strings.TrimSpace(req.GetIdempotencyKey()),
|
IdempotencyKey: strings.TrimSpace(req.GetIdempotencyKey()),
|
||||||
IntentRef: strings.TrimSpace(req.GetIntentRef()),
|
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.
|
// 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() {
|
if !existing.CreatedAt.IsZero() {
|
||||||
state.CreatedAt = existing.CreatedAt
|
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 {
|
if e := p.updatePayoutStatus(ctx, state); e != nil {
|
||||||
p.logger.Warn("Failed to update payout status",
|
p.logger.Warn("Failed to update payout status",
|
||||||
zap.Error(e),
|
zap.Error(e),
|
||||||
zap.String("payout_id", state.PayoutID),
|
zap.String("payment_ref", state.PaymentRef),
|
||||||
zap.String("customer_id", state.CustomerID),
|
zap.String("customer_id", state.CustomerID),
|
||||||
zap.String("operation_ref", state.OperationRef),
|
zap.String("operation_ref", state.OperationRef),
|
||||||
zap.String("idempotency_key", state.IdempotencyKey),
|
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",
|
p.logger.Warn("Monetix payout submission failed",
|
||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
zap.String("payout_id", state.PayoutID),
|
zap.String("payment_ref", state.PaymentRef),
|
||||||
zap.String("customer_id", state.CustomerID),
|
zap.String("customer_id", state.CustomerID),
|
||||||
zap.String("operation_ref", state.OperationRef),
|
zap.String("operation_ref", state.OperationRef),
|
||||||
zap.String("idempotency_key", state.IdempotencyKey),
|
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 {
|
if err := p.updatePayoutStatus(ctx, state); err != nil {
|
||||||
p.logger.Warn("Failed to store payout",
|
p.logger.Warn("Failed to store payout",
|
||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
zap.String("payout_id", state.PayoutID),
|
zap.String("payment_ref", state.PaymentRef),
|
||||||
zap.String("customer_id", state.CustomerID),
|
zap.String("customer_id", state.CustomerID),
|
||||||
zap.String("operation_ref", state.OperationRef),
|
zap.String("operation_ref", state.OperationRef),
|
||||||
zap.String("idempotency_key", state.IdempotencyKey),
|
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",
|
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.String("status", string(state.Status)),
|
||||||
zap.Bool("accepted", result.Accepted),
|
zap.Bool("accepted", result.Accepted),
|
||||||
zap.String("provider_request_id", result.ProviderRequestID),
|
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()
|
now := p.clock.Now()
|
||||||
state := &model.CardPayout{
|
state := &model.CardPayout{
|
||||||
PayoutID: strings.TrimSpace(req.GetPayoutId()),
|
PaymentRef: strings.TrimSpace(req.GetPayoutId()),
|
||||||
OperationRef: strings.TrimSpace(req.GetOperationRef()),
|
OperationRef: strings.TrimSpace(req.GetOperationRef()),
|
||||||
IdempotencyKey: strings.TrimSpace(req.GetIdempotencyKey()),
|
IdempotencyKey: strings.TrimSpace(req.GetIdempotencyKey()),
|
||||||
ProjectID: projectID,
|
ProjectID: projectID,
|
||||||
@@ -245,7 +245,7 @@ func (p *cardPayoutProcessor) SubmitToken(ctx context.Context, req *mntxv1.CardT
|
|||||||
UpdatedAt: now,
|
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() {
|
if !existing.CreatedAt.IsZero() {
|
||||||
state.CreatedAt = existing.CreatedAt
|
state.CreatedAt = existing.CreatedAt
|
||||||
}
|
}
|
||||||
@@ -269,7 +269,7 @@ func (p *cardPayoutProcessor) SubmitToken(ctx context.Context, req *mntxv1.CardT
|
|||||||
_ = p.updatePayoutStatus(ctx, state)
|
_ = p.updatePayoutStatus(ctx, state)
|
||||||
|
|
||||||
p.logger.Warn("Monetix token payout submission failed",
|
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.String("customer_id", state.CustomerID),
|
||||||
zap.Error(err),
|
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",
|
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.String("status", string(state.Status)),
|
||||||
zap.Bool("accepted", result.Accepted),
|
zap.Bool("accepted", result.Accepted),
|
||||||
zap.String("provider_request_id", result.ProviderRequestID),
|
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",
|
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)),
|
zap.String("status", string(state.Status)),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -449,10 +449,10 @@ func (p *cardPayoutProcessor) ProcessCallback(ctx context.Context, payload []byt
|
|||||||
state := CardPayoutStateFromProto(p.clock, pbState)
|
state := CardPayoutStateFromProto(p.clock, pbState)
|
||||||
|
|
||||||
// Preserve CreatedAt + internal keys from existing record if present.
|
// 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",
|
p.logger.Warn("Failed to fetch payout state while processing callback",
|
||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
zap.String("payout_id", state.PayoutID),
|
zap.String("payment_ref", state.PaymentRef),
|
||||||
)
|
)
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
} else if existing != nil {
|
} else if existing != nil {
|
||||||
@@ -477,7 +477,7 @@ func (p *cardPayoutProcessor) ProcessCallback(ctx context.Context, payload []byt
|
|||||||
monetix.ObserveCallback(statusLabel)
|
monetix.ObserveCallback(statusLabel)
|
||||||
|
|
||||||
p.logger.Info("Monetix payout callback processed",
|
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("status", statusLabel),
|
||||||
zap.String("provider_code", state.ProviderCode),
|
zap.String("provider_code", state.ProviderCode),
|
||||||
zap.String("provider_message", state.ProviderMessage),
|
zap.String("provider_message", state.ProviderMessage),
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ func TestCardPayoutProcessor_Submit_Success(t *testing.T) {
|
|||||||
|
|
||||||
repo := newMockRepository()
|
repo := newMockRepository()
|
||||||
repo.payouts.Save(&model.CardPayout{
|
repo.payouts.Save(&model.CardPayout{
|
||||||
PayoutID: "payout-1",
|
PaymentRef: "payout-1",
|
||||||
CreatedAt: existingCreated,
|
CreatedAt: existingCreated,
|
||||||
})
|
})
|
||||||
|
|
||||||
httpClient := &http.Client{
|
httpClient := &http.Client{
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ func CardPayoutStateFromProto(clock clockpkg.Clock, p *mntxv1.CardPayoutState) *
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &model.CardPayout{
|
return &model.CardPayout{
|
||||||
PayoutID: p.PayoutId,
|
PaymentRef: p.PayoutId,
|
||||||
OperationRef: p.GetOperationRef(),
|
OperationRef: p.GetOperationRef(),
|
||||||
IntentRef: p.GetIntentRef(),
|
IntentRef: p.GetIntentRef(),
|
||||||
IdempotencyKey: p.GetIdempotencyKey(),
|
IdempotencyKey: p.GetIdempotencyKey(),
|
||||||
@@ -41,7 +41,7 @@ func CardPayoutStateFromProto(clock clockpkg.Clock, p *mntxv1.CardPayoutState) *
|
|||||||
|
|
||||||
func StateToProto(m *model.CardPayout) *mntxv1.CardPayoutState {
|
func StateToProto(m *model.CardPayout) *mntxv1.CardPayoutState {
|
||||||
return &mntxv1.CardPayoutState{
|
return &mntxv1.CardPayoutState{
|
||||||
PayoutId: m.PayoutID,
|
PayoutId: m.PaymentRef,
|
||||||
ProjectId: m.ProjectID,
|
ProjectId: m.ProjectID,
|
||||||
CustomerId: m.CustomerID,
|
CustomerId: m.CustomerID,
|
||||||
AmountMinor: m.AmountMinor,
|
AmountMinor: m.AmountMinor,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/tech/sendico/gateway/mntx/storage/model"
|
"github.com/tech/sendico/gateway/mntx/storage/model"
|
||||||
|
"github.com/tech/sendico/pkg/merrors"
|
||||||
paymentgateway "github.com/tech/sendico/pkg/messaging/notifications/paymentgateway"
|
paymentgateway "github.com/tech/sendico/pkg/messaging/notifications/paymentgateway"
|
||||||
pmodel "github.com/tech/sendico/pkg/model"
|
pmodel "github.com/tech/sendico/pkg/model"
|
||||||
"github.com/tech/sendico/pkg/mservice"
|
"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 {
|
switch t.Status {
|
||||||
case model.PayoutStatusFailed:
|
case model.PayoutStatusFailed:
|
||||||
return rail.OperationResultFailed
|
return rail.OperationResultFailed, nil
|
||||||
case model.PayoutStatusSuccess:
|
case model.PayoutStatusSuccess:
|
||||||
return rail.OperationResultSuccess
|
return rail.OperationResultSuccess, nil
|
||||||
case model.PayoutStatusCancelled:
|
case model.PayoutStatusCancelled:
|
||||||
return rail.OperationResultCancelled
|
return rail.OperationResultCancelled, nil
|
||||||
default:
|
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 {
|
func (p *cardPayoutProcessor) updatePayoutStatus(ctx context.Context, state *model.CardPayout) error {
|
||||||
if err := p.store.Payouts().Upsert(ctx, state); err != nil {
|
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),
|
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) {
|
if isFinalStatus(state) {
|
||||||
@@ -53,6 +54,13 @@ func (p *cardPayoutProcessor) emitTransferStatusEvent(payout *model.CardPayout)
|
|||||||
return
|
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{
|
exec := pmodel.PaymentGatewayExecution{
|
||||||
PaymentIntentID: payout.IntentRef,
|
PaymentIntentID: payout.IntentRef,
|
||||||
IdempotencyKey: payout.IdempotencyKey,
|
IdempotencyKey: payout.IdempotencyKey,
|
||||||
@@ -61,7 +69,7 @@ func (p *cardPayoutProcessor) emitTransferStatusEvent(payout *model.CardPayout)
|
|||||||
Currency: payout.Currency,
|
Currency: payout.Currency,
|
||||||
},
|
},
|
||||||
PaymentRef: payout.PaymentRef,
|
PaymentRef: payout.PaymentRef,
|
||||||
Status: toOpStatus(payout),
|
Status: status,
|
||||||
OperationRef: payout.OperationRef,
|
OperationRef: payout.OperationRef,
|
||||||
Error: payout.FailureReason,
|
Error: payout.FailureReason,
|
||||||
TransferRef: payout.GetID().Hex(),
|
TransferRef: payout.GetID().Hex(),
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
// CardPayout is a Mongo/JSON representation of proto CardPayout
|
// CardPayout is a Mongo/JSON representation of proto CardPayout
|
||||||
type CardPayout struct {
|
type CardPayout struct {
|
||||||
storable.Base `bson:",inline" json:",inline"`
|
storable.Base `bson:",inline" json:",inline"`
|
||||||
PayoutID string `bson:"payoutId" json:"payout_id"`
|
|
||||||
PaymentRef string `bson:"paymentRef" json:"payment_ref"`
|
PaymentRef string `bson:"paymentRef" json:"payment_ref"`
|
||||||
OperationRef string `bson:"operationRef" json:"operation_ref"`
|
OperationRef string `bson:"operationRef" json:"operation_ref"`
|
||||||
IdempotencyKey string `bson:"idempotencyKey" json:"idempotency_key"`
|
IdempotencyKey string `bson:"idempotencyKey" json:"idempotency_key"`
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import (
|
|||||||
const (
|
const (
|
||||||
payoutsCollection = "card_payouts"
|
payoutsCollection = "card_payouts"
|
||||||
payoutIdemField = "idempotencyKey"
|
payoutIdemField = "idempotencyKey"
|
||||||
payoutIdField = "payoutId"
|
payoutIdField = "paymentRef"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Payouts struct {
|
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.OperationRef = strings.TrimSpace(record.OperationRef)
|
||||||
record.PayoutID = strings.TrimSpace(record.PayoutID)
|
record.PaymentRef = strings.TrimSpace(record.PaymentRef)
|
||||||
record.CustomerID = strings.TrimSpace(record.CustomerID)
|
record.CustomerID = strings.TrimSpace(record.CustomerID)
|
||||||
record.ProviderCode = strings.TrimSpace(record.ProviderCode)
|
record.ProviderCode = strings.TrimSpace(record.ProviderCode)
|
||||||
record.ProviderPaymentID = strings.TrimSpace(record.ProviderPaymentID)
|
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 {
|
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),
|
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 err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
Reference in New Issue
Block a user