bettter message reaction and pending payments persistence
This commit is contained in:
@@ -19,26 +19,23 @@ import (
|
||||
)
|
||||
|
||||
type fakePaymentsStore struct {
|
||||
mu sync.Mutex
|
||||
executions map[string]*storagemodel.PaymentExecution
|
||||
mu sync.Mutex
|
||||
records map[string]*storagemodel.PaymentRecord
|
||||
}
|
||||
|
||||
func (f *fakePaymentsStore) FindByIdempotencyKey(_ context.Context, key string) (*storagemodel.PaymentExecution, error) {
|
||||
func (f *fakePaymentsStore) FindByIdempotencyKey(_ context.Context, key string) (*storagemodel.PaymentRecord, error) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
return f.executions[key], nil
|
||||
return f.records[key], nil
|
||||
}
|
||||
|
||||
func (f *fakePaymentsStore) InsertExecution(_ context.Context, exec *storagemodel.PaymentExecution) error {
|
||||
func (f *fakePaymentsStore) Upsert(_ context.Context, record *storagemodel.PaymentRecord) error {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
if f.executions == nil {
|
||||
f.executions = map[string]*storagemodel.PaymentExecution{}
|
||||
if f.records == nil {
|
||||
f.records = map[string]*storagemodel.PaymentRecord{}
|
||||
}
|
||||
if _, ok := f.executions[exec.IdempotencyKey]; ok {
|
||||
return storage.ErrDuplicate
|
||||
}
|
||||
f.executions[exec.IdempotencyKey] = exec
|
||||
f.records[record.IdempotencyKey] = record
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -147,6 +144,16 @@ func TestOnIntentCreatesConfirmationRequest(t *testing.T) {
|
||||
if req.SourceService != string(mservice.PaymentGateway) || req.Rail != "card" {
|
||||
t.Fatalf("unexpected source/rail: %#v", req)
|
||||
}
|
||||
record := repo.payments.records["idem-1"]
|
||||
if record == nil {
|
||||
t.Fatalf("expected pending payment to be stored")
|
||||
}
|
||||
if record.Status != storagemodel.PaymentStatusPending {
|
||||
t.Fatalf("expected pending status, got %q", record.Status)
|
||||
}
|
||||
if record.RequestedMoney == nil || record.RequestedMoney.Amount != "10.50" {
|
||||
t.Fatalf("requested money not stored correctly: %#v", record.RequestedMoney)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntentFromSubmitTransferUsesSourceMoney(t *testing.T) {
|
||||
@@ -180,7 +187,14 @@ func TestConfirmationResultPersistsExecutionAndReply(t *testing.T) {
|
||||
OutgoingLeg: "card",
|
||||
RequestedMoney: &paymenttypes.Money{Amount: "5", Currency: "EUR"},
|
||||
}
|
||||
svc.trackIntent("idem-2", intent)
|
||||
_ = repo.payments.Upsert(context.Background(), &storagemodel.PaymentRecord{
|
||||
IdempotencyKey: "idem-2",
|
||||
PaymentIntentID: intent.PaymentIntentID,
|
||||
QuoteRef: intent.QuoteRef,
|
||||
OutgoingLeg: intent.OutgoingLeg,
|
||||
RequestedMoney: intent.RequestedMoney,
|
||||
Status: storagemodel.PaymentStatusPending,
|
||||
})
|
||||
|
||||
result := &model.ConfirmationResult{
|
||||
RequestID: "idem-2",
|
||||
@@ -191,11 +205,15 @@ func TestConfirmationResultPersistsExecutionAndReply(t *testing.T) {
|
||||
if err := svc.onConfirmationResult(context.Background(), result); err != nil {
|
||||
t.Fatalf("onConfirmationResult error: %v", err)
|
||||
}
|
||||
if repo.payments.executions["idem-2"] == nil {
|
||||
t.Fatalf("expected payment execution to be stored")
|
||||
record := repo.payments.records["idem-2"]
|
||||
if record == nil {
|
||||
t.Fatalf("expected payment record to be stored")
|
||||
}
|
||||
if repo.payments.executions["idem-2"].ExecutedMoney == nil || repo.payments.executions["idem-2"].ExecutedMoney.Amount != "5" {
|
||||
t.Fatalf("executed money not stored correctly")
|
||||
if record.Status != storagemodel.PaymentStatusExecuted {
|
||||
t.Fatalf("expected executed status, got %q", record.Status)
|
||||
}
|
||||
if record.ExecutedMoney == nil || record.ExecutedMoney.Amount != "5" {
|
||||
t.Fatalf("executed money not stored correctly: %#v", record.ExecutedMoney)
|
||||
}
|
||||
if repo.tg.records["idem-2"] == nil || repo.tg.records["idem-2"].RawReply.Text != "5 EUR" {
|
||||
t.Fatalf("telegram reply not stored correctly")
|
||||
@@ -214,7 +232,14 @@ func TestClarifiedResultPersistsExecution(t *testing.T) {
|
||||
OutgoingLeg: "card",
|
||||
RequestedMoney: &paymenttypes.Money{Amount: "12", Currency: "USD"},
|
||||
}
|
||||
svc.trackIntent("idem-clarified", intent)
|
||||
_ = repo.payments.Upsert(context.Background(), &storagemodel.PaymentRecord{
|
||||
IdempotencyKey: "idem-clarified",
|
||||
PaymentIntentID: intent.PaymentIntentID,
|
||||
QuoteRef: intent.QuoteRef,
|
||||
OutgoingLeg: intent.OutgoingLeg,
|
||||
RequestedMoney: intent.RequestedMoney,
|
||||
Status: storagemodel.PaymentStatusPending,
|
||||
})
|
||||
|
||||
result := &model.ConfirmationResult{
|
||||
RequestID: "idem-clarified",
|
||||
@@ -225,15 +250,16 @@ func TestClarifiedResultPersistsExecution(t *testing.T) {
|
||||
if err := svc.onConfirmationResult(context.Background(), result); err != nil {
|
||||
t.Fatalf("onConfirmationResult error: %v", err)
|
||||
}
|
||||
if repo.payments.executions["idem-clarified"] == nil {
|
||||
t.Fatalf("expected payment execution to be stored")
|
||||
record := repo.payments.records["idem-clarified"]
|
||||
if record == nil || record.Status != storagemodel.PaymentStatusExecuted {
|
||||
t.Fatalf("expected payment executed status, got %#v", record)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIdempotencyPreventsDuplicateWrites(t *testing.T) {
|
||||
logger := mloggerfactory.NewLogger(false)
|
||||
repo := &fakeRepo{payments: &fakePaymentsStore{executions: map[string]*storagemodel.PaymentExecution{
|
||||
"idem-3": {IdempotencyKey: "idem-3"},
|
||||
repo := &fakeRepo{payments: &fakePaymentsStore{records: map[string]*storagemodel.PaymentRecord{
|
||||
"idem-3": {IdempotencyKey: "idem-3", Status: storagemodel.PaymentStatusPending},
|
||||
}}, tg: &fakeTelegramStore{}}
|
||||
prod := &captureProducer{}
|
||||
svc := NewService(logger, repo, prod, nil, Config{Rail: "card"})
|
||||
@@ -265,7 +291,14 @@ func TestTimeoutDoesNotPersistExecution(t *testing.T) {
|
||||
OutgoingLeg: "card",
|
||||
RequestedMoney: &paymenttypes.Money{Amount: "8", Currency: "USD"},
|
||||
}
|
||||
svc.trackIntent("idem-4", intent)
|
||||
_ = repo.payments.Upsert(context.Background(), &storagemodel.PaymentRecord{
|
||||
IdempotencyKey: "idem-4",
|
||||
PaymentIntentID: intent.PaymentIntentID,
|
||||
QuoteRef: intent.QuoteRef,
|
||||
OutgoingLeg: intent.OutgoingLeg,
|
||||
RequestedMoney: intent.RequestedMoney,
|
||||
Status: storagemodel.PaymentStatusPending,
|
||||
})
|
||||
|
||||
result := &model.ConfirmationResult{
|
||||
RequestID: "idem-4",
|
||||
@@ -274,8 +307,9 @@ func TestTimeoutDoesNotPersistExecution(t *testing.T) {
|
||||
if err := svc.onConfirmationResult(context.Background(), result); err != nil {
|
||||
t.Fatalf("onConfirmationResult error: %v", err)
|
||||
}
|
||||
if repo.payments.executions["idem-4"] != nil {
|
||||
t.Fatalf("expected no execution record for timeout")
|
||||
record := repo.payments.records["idem-4"]
|
||||
if record == nil || record.Status != storagemodel.PaymentStatusExpired {
|
||||
t.Fatalf("expected expired status for timeout, got %#v", record)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,7 +325,14 @@ func TestRejectedDoesNotPersistExecution(t *testing.T) {
|
||||
OutgoingLeg: "card",
|
||||
RequestedMoney: &paymenttypes.Money{Amount: "3", Currency: "USD"},
|
||||
}
|
||||
svc.trackIntent("idem-reject", intent)
|
||||
_ = repo.payments.Upsert(context.Background(), &storagemodel.PaymentRecord{
|
||||
IdempotencyKey: "idem-reject",
|
||||
PaymentIntentID: intent.PaymentIntentID,
|
||||
QuoteRef: intent.QuoteRef,
|
||||
OutgoingLeg: intent.OutgoingLeg,
|
||||
RequestedMoney: intent.RequestedMoney,
|
||||
Status: storagemodel.PaymentStatusPending,
|
||||
})
|
||||
|
||||
result := &model.ConfirmationResult{
|
||||
RequestID: "idem-reject",
|
||||
@@ -301,8 +342,9 @@ func TestRejectedDoesNotPersistExecution(t *testing.T) {
|
||||
if err := svc.onConfirmationResult(context.Background(), result); err != nil {
|
||||
t.Fatalf("onConfirmationResult error: %v", err)
|
||||
}
|
||||
if repo.payments.executions["idem-reject"] != nil {
|
||||
t.Fatalf("expected no execution record for rejection")
|
||||
record := repo.payments.records["idem-reject"]
|
||||
if record == nil || record.Status != storagemodel.PaymentStatusExpired {
|
||||
t.Fatalf("expected expired status for rejection, got %#v", record)
|
||||
}
|
||||
if repo.tg.records["idem-reject"] == nil {
|
||||
t.Fatalf("expected raw reply to be stored for rejection")
|
||||
|
||||
Reference in New Issue
Block a user