mirror of
https://github.com/hanzo-fi/payments.git
synced 2026-10-30 20:31:20 +00:00
1393 lines
41 KiB
Go
1393 lines
41 KiB
Go
package storage
|
|
|
|
import (
|
|
"context"
|
|
"math/big"
|
|
"testing"
|
|
|
|
"github.com/formancehq/go-libs/v3/bun/bunpaginate"
|
|
"github.com/formancehq/go-libs/v3/logging"
|
|
"github.com/formancehq/go-libs/v3/pointer"
|
|
"github.com/formancehq/go-libs/v3/query"
|
|
"github.com/formancehq/go-libs/v3/time"
|
|
"github.com/formancehq/payments/internal/models"
|
|
"github.com/google/uuid"
|
|
"github.com/pkg/errors"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
var (
|
|
pID1 = models.PaymentID{
|
|
PaymentReference: models.PaymentReference{
|
|
Reference: "test1",
|
|
Type: models.PAYMENT_TYPE_TRANSFER,
|
|
},
|
|
ConnectorID: defaultConnector.ID,
|
|
}
|
|
|
|
pid2 = models.PaymentID{
|
|
PaymentReference: models.PaymentReference{
|
|
Reference: "test2",
|
|
Type: models.PAYMENT_TYPE_PAYIN,
|
|
},
|
|
ConnectorID: defaultConnector.ID,
|
|
}
|
|
|
|
pid3 = models.PaymentID{
|
|
PaymentReference: models.PaymentReference{
|
|
Reference: "test3",
|
|
Type: models.PAYMENT_TYPE_PAYOUT,
|
|
},
|
|
ConnectorID: defaultConnector.ID,
|
|
}
|
|
)
|
|
|
|
func defaultPaymentsRefunded() []models.Payment {
|
|
defaultAccounts := defaultAccounts()
|
|
return []models.Payment{
|
|
{
|
|
ID: pID1,
|
|
ConnectorID: defaultConnector.ID,
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-60 * time.Minute).UTC().Time,
|
|
Type: models.PAYMENT_TYPE_TRANSFER,
|
|
InitialAmount: big.NewInt(100),
|
|
Amount: big.NewInt(100),
|
|
Asset: "USD/2",
|
|
Scheme: models.PAYMENT_SCHEME_OTHER,
|
|
SourceAccountID: &defaultAccounts[0].ID,
|
|
DestinationAccountID: &defaultAccounts[1].ID,
|
|
Metadata: map[string]string{
|
|
"key1": "value1",
|
|
},
|
|
Adjustments: []models.PaymentAdjustment{
|
|
{
|
|
ID: models.PaymentAdjustmentID{
|
|
PaymentID: pID1,
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-60 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_SUCCEEDED,
|
|
},
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-60 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_SUCCEEDED,
|
|
Amount: big.NewInt(100),
|
|
Asset: pointer.For("USD/2"),
|
|
Raw: []byte(`{}`),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
ID: pID1,
|
|
ConnectorID: defaultConnector.ID,
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-59 * time.Minute).UTC().Time,
|
|
Type: models.PAYMENT_TYPE_TRANSFER,
|
|
InitialAmount: big.NewInt(100),
|
|
Amount: big.NewInt(100),
|
|
Asset: "USD/2",
|
|
Scheme: models.PAYMENT_SCHEME_OTHER,
|
|
SourceAccountID: &defaultAccounts[0].ID,
|
|
DestinationAccountID: &defaultAccounts[1].ID,
|
|
Metadata: map[string]string{
|
|
"key1": "value1",
|
|
},
|
|
Adjustments: []models.PaymentAdjustment{
|
|
{
|
|
ID: models.PaymentAdjustmentID{
|
|
PaymentID: pID1,
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-59 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_REFUNDED,
|
|
},
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-59 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_REFUNDED,
|
|
Amount: big.NewInt(10),
|
|
Asset: pointer.For("USD/2"),
|
|
Raw: []byte(`{}`),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
ID: pID1,
|
|
ConnectorID: defaultConnector.ID,
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-58 * time.Minute).UTC().Time,
|
|
Type: models.PAYMENT_TYPE_TRANSFER,
|
|
InitialAmount: big.NewInt(100),
|
|
Amount: big.NewInt(100),
|
|
Asset: "USD/2",
|
|
Scheme: models.PAYMENT_SCHEME_OTHER,
|
|
SourceAccountID: &defaultAccounts[0].ID,
|
|
DestinationAccountID: &defaultAccounts[1].ID,
|
|
Metadata: map[string]string{
|
|
"key1": "value1",
|
|
},
|
|
Adjustments: []models.PaymentAdjustment{
|
|
{
|
|
ID: models.PaymentAdjustmentID{
|
|
PaymentID: pID1,
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-58 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_REFUNDED,
|
|
},
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-58 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_REFUNDED,
|
|
Amount: big.NewInt(10),
|
|
Asset: pointer.For("USD/2"),
|
|
Raw: []byte(`{}`),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func defaultPayments() []models.Payment {
|
|
defaultAccounts := defaultAccounts()
|
|
return []models.Payment{
|
|
{
|
|
ID: pID1,
|
|
ConnectorID: defaultConnector.ID,
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-60 * time.Minute).UTC().Time,
|
|
Type: models.PAYMENT_TYPE_TRANSFER,
|
|
InitialAmount: big.NewInt(100),
|
|
Amount: big.NewInt(100),
|
|
Asset: "USD/2",
|
|
Scheme: models.PAYMENT_SCHEME_OTHER,
|
|
SourceAccountID: &defaultAccounts[0].ID,
|
|
DestinationAccountID: &defaultAccounts[1].ID,
|
|
Metadata: map[string]string{
|
|
"key1": "value1",
|
|
},
|
|
Adjustments: []models.PaymentAdjustment{
|
|
{
|
|
ID: models.PaymentAdjustmentID{
|
|
PaymentID: pID1,
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-60 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_SUCCEEDED,
|
|
},
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-60 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_SUCCEEDED,
|
|
Amount: big.NewInt(100),
|
|
Asset: pointer.For("USD/2"),
|
|
Raw: []byte(`{}`),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
ID: pid2,
|
|
ConnectorID: defaultConnector.ID,
|
|
Reference: "test2",
|
|
CreatedAt: now.Add(-30 * time.Minute).UTC().Time,
|
|
Type: models.PAYMENT_TYPE_PAYIN,
|
|
InitialAmount: big.NewInt(200),
|
|
Amount: big.NewInt(200),
|
|
Asset: "EUR/2",
|
|
Scheme: models.PAYMENT_SCHEME_OTHER,
|
|
DestinationAccountID: &defaultAccounts[0].ID,
|
|
Adjustments: []models.PaymentAdjustment{
|
|
{
|
|
ID: models.PaymentAdjustmentID{
|
|
PaymentID: pid2,
|
|
Reference: "test2",
|
|
CreatedAt: now.Add(-30 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_FAILED,
|
|
},
|
|
Reference: "test2",
|
|
CreatedAt: now.Add(-30 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_FAILED,
|
|
Amount: big.NewInt(200),
|
|
Asset: pointer.For("EUR/2"),
|
|
Raw: []byte(`{}`),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
ID: pid3,
|
|
ConnectorID: defaultConnector.ID,
|
|
Reference: "test3",
|
|
CreatedAt: now.Add(-55 * time.Minute).UTC().Time,
|
|
Type: models.PAYMENT_TYPE_PAYOUT,
|
|
InitialAmount: big.NewInt(300),
|
|
Amount: big.NewInt(300),
|
|
Asset: "DKK/2",
|
|
Scheme: models.PAYMENT_SCHEME_A2A,
|
|
SourceAccountID: &defaultAccounts[1].ID,
|
|
Adjustments: []models.PaymentAdjustment{
|
|
{
|
|
ID: models.PaymentAdjustmentID{
|
|
PaymentID: pid3,
|
|
Reference: "another_reference",
|
|
CreatedAt: now.Add(-55 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_PENDING,
|
|
},
|
|
Reference: "another_reference",
|
|
CreatedAt: now.Add(-55 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_PENDING,
|
|
Amount: big.NewInt(300),
|
|
Asset: pointer.For("DKK/2"),
|
|
Raw: []byte(`{}`),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func upsertPayments(t *testing.T, ctx context.Context, storage Storage, payments []models.Payment) {
|
|
require.NoError(t, storage.PaymentsUpsert(ctx, payments))
|
|
}
|
|
|
|
func TestPaymentsUpsert(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ctx := logging.TestingContext()
|
|
store := newStore(t)
|
|
defer store.Close()
|
|
|
|
upsertConnector(t, ctx, store, defaultConnector)
|
|
upsertAccounts(t, ctx, store, defaultAccounts())
|
|
upsertPayments(t, ctx, store, defaultPayments())
|
|
|
|
t.Run("upsert with unknown connector", func(t *testing.T) {
|
|
connector := models.ConnectorID{
|
|
Reference: uuid.New(),
|
|
Provider: "unknown",
|
|
}
|
|
payments := defaultPayments()
|
|
p := payments[0]
|
|
p.ID = models.PaymentID{
|
|
PaymentReference: models.PaymentReference{
|
|
Reference: "test4",
|
|
Type: models.PAYMENT_TYPE_PAYOUT,
|
|
},
|
|
ConnectorID: connector,
|
|
}
|
|
p.ConnectorID = connector
|
|
|
|
err := store.PaymentsUpsert(ctx, []models.Payment{p})
|
|
require.Error(t, err)
|
|
})
|
|
|
|
t.Run("upsert with same id", func(t *testing.T) {
|
|
payments := defaultPayments()
|
|
p := payments[2]
|
|
p.Amount = big.NewInt(200)
|
|
p.Scheme = models.PAYMENT_SCHEME_A2A
|
|
upsertPayments(t, ctx, store, []models.Payment{p})
|
|
|
|
// should not have changed
|
|
actual, err := store.PaymentsGet(ctx, p.ID)
|
|
require.NoError(t, err)
|
|
|
|
comparePayments(t, payments[2], *actual)
|
|
})
|
|
|
|
t.Run("upsert with different adjustments", func(t *testing.T) {
|
|
p := models.Payment{
|
|
ID: pid3,
|
|
ConnectorID: defaultConnector.ID,
|
|
Reference: "test3",
|
|
CreatedAt: now.Add(-55 * time.Minute).UTC().Time,
|
|
Type: models.PAYMENT_TYPE_PAYOUT,
|
|
InitialAmount: big.NewInt(300),
|
|
Amount: big.NewInt(300),
|
|
Asset: "DKK/2",
|
|
Scheme: models.PAYMENT_SCHEME_A2A,
|
|
SourceAccountID: &defaultAccounts()[1].ID,
|
|
Adjustments: []models.PaymentAdjustment{
|
|
{
|
|
ID: models.PaymentAdjustmentID{
|
|
PaymentID: pid3,
|
|
Reference: "another_reference2",
|
|
CreatedAt: now.Add(-45 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_SUCCEEDED,
|
|
},
|
|
Reference: "another_reference2",
|
|
CreatedAt: now.Add(-45 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_SUCCEEDED,
|
|
Amount: big.NewInt(300),
|
|
Asset: pointer.For("DKK/2"),
|
|
Metadata: map[string]string{},
|
|
Raw: []byte(`{}`),
|
|
},
|
|
{
|
|
ID: models.PaymentAdjustmentID{
|
|
PaymentID: pid3,
|
|
Reference: "another_reference",
|
|
CreatedAt: now.Add(-55 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_PENDING,
|
|
},
|
|
Reference: "another_reference",
|
|
CreatedAt: now.Add(-55 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_PENDING,
|
|
Amount: big.NewInt(300),
|
|
Asset: pointer.For("DKK/2"),
|
|
Raw: []byte(`{}`),
|
|
},
|
|
},
|
|
}
|
|
|
|
upsertPayments(t, ctx, store, []models.Payment{p})
|
|
|
|
actual, err := store.PaymentsGet(ctx, p.ID)
|
|
require.NoError(t, err)
|
|
comparePayments(t, p, *actual)
|
|
})
|
|
|
|
t.Run("upsert with refund", func(t *testing.T) {
|
|
p := models.Payment{
|
|
ID: pID1,
|
|
ConnectorID: defaultConnector.ID,
|
|
InitialAmount: big.NewInt(0),
|
|
Amount: big.NewInt(0),
|
|
Adjustments: []models.PaymentAdjustment{
|
|
{
|
|
ID: models.PaymentAdjustmentID{
|
|
PaymentID: pID1,
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-20 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_REFUNDED,
|
|
},
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-20 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_REFUNDED,
|
|
Amount: big.NewInt(50),
|
|
Asset: pointer.For("USD/2"),
|
|
Raw: []byte(`{}`),
|
|
},
|
|
},
|
|
}
|
|
|
|
upsertPayments(t, ctx, store, []models.Payment{p})
|
|
|
|
actual, err := store.PaymentsGet(ctx, p.ID)
|
|
require.NoError(t, err)
|
|
|
|
expectedPayments := models.Payment{
|
|
ID: pID1,
|
|
ConnectorID: defaultConnector.ID,
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-60 * time.Minute).UTC().Time,
|
|
Type: models.PAYMENT_TYPE_TRANSFER,
|
|
InitialAmount: big.NewInt(100),
|
|
Amount: big.NewInt(50),
|
|
Asset: "USD/2",
|
|
Scheme: models.PAYMENT_SCHEME_OTHER,
|
|
Status: models.PAYMENT_STATUS_REFUNDED,
|
|
SourceAccountID: &defaultAccounts()[0].ID,
|
|
DestinationAccountID: &defaultAccounts()[1].ID,
|
|
Metadata: map[string]string{
|
|
"key1": "value1",
|
|
},
|
|
Adjustments: []models.PaymentAdjustment{
|
|
{
|
|
ID: models.PaymentAdjustmentID{
|
|
PaymentID: pID1,
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-20 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_REFUNDED,
|
|
},
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-20 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_REFUNDED,
|
|
Amount: big.NewInt(50),
|
|
Asset: pointer.For("USD/2"),
|
|
Raw: []byte(`{}`),
|
|
},
|
|
{
|
|
ID: models.PaymentAdjustmentID{
|
|
PaymentID: pID1,
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-60 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_SUCCEEDED,
|
|
},
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-60 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_SUCCEEDED,
|
|
Amount: big.NewInt(100),
|
|
Asset: pointer.For("USD/2"),
|
|
Raw: []byte(`{}`),
|
|
},
|
|
},
|
|
}
|
|
|
|
comparePayments(t, expectedPayments, *actual)
|
|
})
|
|
|
|
t.Run("upsert with reversed refund", func(t *testing.T) {
|
|
p := models.Payment{
|
|
ID: pID1,
|
|
ConnectorID: defaultConnector.ID,
|
|
InitialAmount: big.NewInt(0),
|
|
Amount: big.NewInt(0),
|
|
Adjustments: []models.PaymentAdjustment{
|
|
{
|
|
ID: models.PaymentAdjustmentID{
|
|
PaymentID: pID1,
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-10 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_REFUND_REVERSED,
|
|
},
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-10 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_REFUND_REVERSED,
|
|
Amount: big.NewInt(50),
|
|
Asset: pointer.For("USD/2"),
|
|
Raw: []byte(`{}`),
|
|
},
|
|
},
|
|
}
|
|
|
|
upsertPayments(t, ctx, store, []models.Payment{p})
|
|
|
|
actual, err := store.PaymentsGet(ctx, p.ID)
|
|
require.NoError(t, err)
|
|
|
|
expectedPayments := models.Payment{
|
|
ID: pID1,
|
|
ConnectorID: defaultConnector.ID,
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-60 * time.Minute).UTC().Time,
|
|
Type: models.PAYMENT_TYPE_TRANSFER,
|
|
InitialAmount: big.NewInt(100),
|
|
Amount: big.NewInt(100),
|
|
Asset: "USD/2",
|
|
Scheme: models.PAYMENT_SCHEME_OTHER,
|
|
Status: models.PAYMENT_STATUS_REFUNDED,
|
|
SourceAccountID: &defaultAccounts()[0].ID,
|
|
DestinationAccountID: &defaultAccounts()[1].ID,
|
|
Metadata: map[string]string{
|
|
"key1": "value1",
|
|
},
|
|
Adjustments: []models.PaymentAdjustment{
|
|
{
|
|
ID: models.PaymentAdjustmentID{
|
|
PaymentID: pID1,
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-10 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_REFUND_REVERSED,
|
|
},
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-10 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_REFUND_REVERSED,
|
|
Amount: big.NewInt(50),
|
|
Asset: pointer.For("USD/2"),
|
|
Raw: []byte(`{}`),
|
|
},
|
|
{
|
|
ID: models.PaymentAdjustmentID{
|
|
PaymentID: pID1,
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-20 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_REFUNDED,
|
|
},
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-20 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_REFUNDED,
|
|
Amount: big.NewInt(50),
|
|
Asset: pointer.For("USD/2"),
|
|
Raw: []byte(`{}`),
|
|
},
|
|
{
|
|
ID: models.PaymentAdjustmentID{
|
|
PaymentID: pID1,
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-60 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_SUCCEEDED,
|
|
},
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-60 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_SUCCEEDED,
|
|
Amount: big.NewInt(100),
|
|
Asset: pointer.For("USD/2"),
|
|
Raw: []byte(`{}`),
|
|
},
|
|
},
|
|
}
|
|
|
|
comparePayments(t, expectedPayments, *actual)
|
|
})
|
|
|
|
t.Run("upsert with amount adjustment", func(t *testing.T) {
|
|
p := models.Payment{
|
|
ID: pID1,
|
|
ConnectorID: defaultConnector.ID,
|
|
InitialAmount: big.NewInt(0),
|
|
Amount: big.NewInt(0),
|
|
Adjustments: []models.PaymentAdjustment{
|
|
{
|
|
ID: models.PaymentAdjustmentID{
|
|
PaymentID: pID1,
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-5 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_AMOUNT_ADJUSTEMENT,
|
|
},
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-5 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_AMOUNT_ADJUSTEMENT,
|
|
Amount: big.NewInt(150),
|
|
Asset: pointer.For("USD/2"),
|
|
Raw: []byte(`{}`),
|
|
},
|
|
},
|
|
}
|
|
|
|
upsertPayments(t, ctx, store, []models.Payment{p})
|
|
|
|
actual, err := store.PaymentsGet(ctx, p.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, big.NewInt(150), actual.InitialAmount)
|
|
})
|
|
|
|
t.Run("upsert with capture", func(t *testing.T) {
|
|
p := models.Payment{
|
|
ID: pID1,
|
|
ConnectorID: defaultConnector.ID,
|
|
InitialAmount: big.NewInt(0),
|
|
Amount: big.NewInt(0),
|
|
Adjustments: []models.PaymentAdjustment{
|
|
{
|
|
ID: models.PaymentAdjustmentID{
|
|
PaymentID: pID1,
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-3 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_CAPTURE,
|
|
},
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-3 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_CAPTURE,
|
|
Amount: big.NewInt(50),
|
|
Asset: pointer.For("USD/2"),
|
|
Raw: []byte(`{}`),
|
|
},
|
|
},
|
|
}
|
|
|
|
upsertPayments(t, ctx, store, []models.Payment{p})
|
|
|
|
actual, err := store.PaymentsGet(ctx, p.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, big.NewInt(150), actual.Amount)
|
|
})
|
|
}
|
|
|
|
func TestPaymentsUpsertRefunded(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ctx := logging.TestingContext()
|
|
store := newStore(t)
|
|
defer store.Close()
|
|
|
|
upsertConnector(t, ctx, store, defaultConnector)
|
|
upsertAccounts(t, ctx, store, defaultAccounts())
|
|
upsertPayments(t, ctx, store, defaultPaymentsRefunded())
|
|
|
|
actual, err := store.PaymentsGet(ctx, pID1)
|
|
require.NoError(t, err)
|
|
// two refunds in the same batch, should be 100 - 10 - 10 = 80
|
|
require.Equal(t, big.NewInt(80), actual.Amount)
|
|
}
|
|
|
|
func TestPaymentsUpdateMetadata(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ctx := logging.TestingContext()
|
|
store := newStore(t)
|
|
defer store.Close()
|
|
|
|
upsertConnector(t, ctx, store, defaultConnector)
|
|
upsertAccounts(t, ctx, store, defaultAccounts())
|
|
upsertPayments(t, ctx, store, defaultPayments())
|
|
|
|
t.Run("update metadata of unknown payment", func(t *testing.T) {
|
|
require.Error(t, store.PaymentsUpdateMetadata(ctx, models.PaymentID{
|
|
PaymentReference: models.PaymentReference{Reference: "unknown", Type: models.PAYMENT_TYPE_TRANSFER},
|
|
ConnectorID: defaultConnector.ID,
|
|
}, map[string]string{}))
|
|
})
|
|
|
|
t.Run("update existing metadata", func(t *testing.T) {
|
|
metadata := map[string]string{
|
|
"key1": "changed",
|
|
}
|
|
payments := defaultPayments()
|
|
require.NoError(t, store.PaymentsUpdateMetadata(ctx, payments[0].ID, metadata))
|
|
|
|
actual, err := store.PaymentsGet(ctx, payments[0].ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, len(metadata), len(actual.Metadata))
|
|
for k, v := range metadata {
|
|
_, ok := actual.Metadata[k]
|
|
require.True(t, ok)
|
|
require.Equal(t, v, actual.Metadata[k])
|
|
}
|
|
})
|
|
|
|
t.Run("add new metadata", func(t *testing.T) {
|
|
metadata := map[string]string{
|
|
"key2": "value2",
|
|
"key3": "value3",
|
|
}
|
|
|
|
payments := defaultPayments()
|
|
require.NoError(t, store.PaymentsUpdateMetadata(ctx, payments[1].ID, metadata))
|
|
|
|
actual, err := store.PaymentsGet(ctx, payments[1].ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, len(metadata), len(actual.Metadata))
|
|
for k, v := range metadata {
|
|
_, ok := actual.Metadata[k]
|
|
require.True(t, ok)
|
|
require.Equal(t, v, actual.Metadata[k])
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestPaymentsGet(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ctx := logging.TestingContext()
|
|
store := newStore(t)
|
|
defer store.Close()
|
|
|
|
upsertConnector(t, ctx, store, defaultConnector)
|
|
upsertAccounts(t, ctx, store, defaultAccounts())
|
|
upsertPayments(t, ctx, store, defaultPayments())
|
|
|
|
t.Run("get unknown payment", func(t *testing.T) {
|
|
_, err := store.PaymentsGet(ctx, models.PaymentID{
|
|
PaymentReference: models.PaymentReference{Reference: "unknown", Type: models.PAYMENT_TYPE_TRANSFER},
|
|
ConnectorID: defaultConnector.ID,
|
|
})
|
|
require.Error(t, err)
|
|
require.ErrorIs(t, err, ErrNotFound)
|
|
})
|
|
|
|
t.Run("get existing payments", func(t *testing.T) {
|
|
for _, p := range defaultPayments() {
|
|
actual, err := store.PaymentsGet(ctx, p.ID)
|
|
require.NoError(t, err)
|
|
comparePayments(t, p, *actual)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestPaymentsGetMultipleAdjustmentsLastStatus(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ctx := logging.TestingContext()
|
|
store := newStore(t)
|
|
defer store.Close()
|
|
|
|
upsertConnector(t, ctx, store, defaultConnector)
|
|
upsertAccounts(t, ctx, store, defaultAccounts())
|
|
|
|
p := models.Payment{
|
|
ID: pID1,
|
|
ConnectorID: defaultConnector.ID,
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-60 * time.Minute).UTC().Time,
|
|
Type: models.PAYMENT_TYPE_TRANSFER,
|
|
InitialAmount: big.NewInt(100),
|
|
Amount: big.NewInt(100),
|
|
Asset: "USD/2",
|
|
Scheme: models.PAYMENT_SCHEME_OTHER,
|
|
SourceAccountID: &defaultAccounts()[0].ID,
|
|
DestinationAccountID: &defaultAccounts()[1].ID,
|
|
Metadata: map[string]string{
|
|
"key1": "value1",
|
|
},
|
|
Adjustments: []models.PaymentAdjustment{
|
|
{
|
|
ID: models.PaymentAdjustmentID{
|
|
PaymentID: pID1,
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-55 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_CAPTURE,
|
|
},
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-55 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_CAPTURE,
|
|
Amount: big.NewInt(100),
|
|
Asset: pointer.For("USD/2"),
|
|
Raw: []byte(`{}`),
|
|
},
|
|
{
|
|
ID: models.PaymentAdjustmentID{
|
|
PaymentID: pID1,
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-60 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_AUTHORISATION,
|
|
},
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-60 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_AUTHORISATION,
|
|
Amount: big.NewInt(100),
|
|
Asset: pointer.For("USD/2"),
|
|
Raw: []byte(`{}`),
|
|
},
|
|
},
|
|
}
|
|
|
|
upsertPayments(t, ctx, store, []models.Payment{p})
|
|
|
|
actual, err := store.PaymentsGet(ctx, p.ID)
|
|
require.NoError(t, err)
|
|
require.Len(t, actual.Adjustments, 2)
|
|
require.Equal(t, models.PAYMENT_STATUS_CAPTURE, actual.Status)
|
|
}
|
|
|
|
func TestPaymentsDeleteFromConnectorID(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ctx := logging.TestingContext()
|
|
store := newStore(t)
|
|
defer store.Close()
|
|
|
|
upsertConnector(t, ctx, store, defaultConnector)
|
|
upsertAccounts(t, ctx, store, defaultAccounts())
|
|
upsertPayments(t, ctx, store, defaultPayments())
|
|
|
|
t.Run("delete from unknown connector", func(t *testing.T) {
|
|
require.NoError(t, store.PaymentsDeleteFromConnectorID(ctx, models.ConnectorID{
|
|
Reference: uuid.New(),
|
|
Provider: "unknown",
|
|
}))
|
|
|
|
for _, p := range defaultPayments() {
|
|
actual, err := store.PaymentsGet(ctx, p.ID)
|
|
require.NoError(t, err)
|
|
comparePayments(t, p, *actual)
|
|
}
|
|
})
|
|
|
|
t.Run("delete from existing connector", func(t *testing.T) {
|
|
require.NoError(t, store.PaymentsDeleteFromConnectorID(ctx, defaultConnector.ID))
|
|
|
|
for _, p := range defaultPayments() {
|
|
_, err := store.PaymentsGet(ctx, p.ID)
|
|
require.Error(t, err)
|
|
require.ErrorIs(t, err, ErrNotFound)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestPaymentsListSorting(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ctx := logging.TestingContext()
|
|
store := newStore(t)
|
|
defer store.Close()
|
|
|
|
upsertConnector(t, ctx, store, defaultConnector)
|
|
upsertAccounts(t, ctx, store, defaultAccounts())
|
|
|
|
p := models.Payment{
|
|
ID: pID1,
|
|
ConnectorID: defaultConnector.ID,
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-60 * time.Minute).UTC().Time,
|
|
Type: models.PAYMENT_TYPE_TRANSFER,
|
|
InitialAmount: big.NewInt(100),
|
|
Amount: big.NewInt(100),
|
|
Asset: "USD/2",
|
|
Scheme: models.PAYMENT_SCHEME_OTHER,
|
|
SourceAccountID: &defaultAccounts()[0].ID,
|
|
DestinationAccountID: &defaultAccounts()[1].ID,
|
|
Metadata: map[string]string{
|
|
"key1": "value1",
|
|
},
|
|
Adjustments: []models.PaymentAdjustment{
|
|
{
|
|
ID: models.PaymentAdjustmentID{
|
|
PaymentID: pID1,
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-60 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_PENDING,
|
|
},
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-60 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_PENDING,
|
|
Amount: big.NewInt(100),
|
|
Asset: pointer.For("USD/2"),
|
|
Raw: []byte(`{}`),
|
|
},
|
|
{
|
|
ID: models.PaymentAdjustmentID{
|
|
PaymentID: pID1,
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-60 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_SUCCEEDED,
|
|
},
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-60 * time.Minute).UTC().Time,
|
|
Status: models.PAYMENT_STATUS_SUCCEEDED,
|
|
Amount: big.NewInt(100),
|
|
Asset: pointer.For("USD/2"),
|
|
Raw: []byte(`{}`),
|
|
},
|
|
},
|
|
}
|
|
|
|
upsertPayments(t, ctx, store, []models.Payment{p})
|
|
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(1),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 1)
|
|
require.False(t, cursor.HasMore)
|
|
require.Empty(t, cursor.Previous)
|
|
require.Empty(t, cursor.Next)
|
|
|
|
require.Equal(t, models.PAYMENT_STATUS_SUCCEEDED, cursor.Data[0].Status)
|
|
}
|
|
|
|
func TestPaymentsList(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ctx := logging.TestingContext()
|
|
store := newStore(t)
|
|
defer store.Close()
|
|
|
|
upsertConnector(t, ctx, store, defaultConnector)
|
|
upsertAccounts(t, ctx, store, defaultAccounts())
|
|
upsertPayments(t, ctx, store, defaultPayments())
|
|
|
|
dps := []models.Payment{
|
|
{
|
|
ID: pID1,
|
|
ConnectorID: defaultConnector.ID,
|
|
Reference: "test1",
|
|
CreatedAt: now.Add(-60 * time.Minute).UTC().Time,
|
|
Type: models.PAYMENT_TYPE_TRANSFER,
|
|
InitialAmount: big.NewInt(100),
|
|
Amount: big.NewInt(100),
|
|
Asset: "USD/2",
|
|
Scheme: models.PAYMENT_SCHEME_OTHER,
|
|
Status: models.PAYMENT_STATUS_SUCCEEDED,
|
|
SourceAccountID: &defaultAccounts()[0].ID,
|
|
DestinationAccountID: &defaultAccounts()[1].ID,
|
|
Metadata: map[string]string{
|
|
"key1": "value1",
|
|
},
|
|
},
|
|
{
|
|
ID: pid2,
|
|
ConnectorID: defaultConnector.ID,
|
|
Reference: "test2",
|
|
CreatedAt: now.Add(-30 * time.Minute).UTC().Time,
|
|
Type: models.PAYMENT_TYPE_PAYIN,
|
|
InitialAmount: big.NewInt(200),
|
|
Amount: big.NewInt(200),
|
|
Asset: "EUR/2",
|
|
Scheme: models.PAYMENT_SCHEME_OTHER,
|
|
Status: models.PAYMENT_STATUS_FAILED,
|
|
DestinationAccountID: &defaultAccounts()[0].ID,
|
|
},
|
|
{
|
|
ID: pid3,
|
|
ConnectorID: defaultConnector.ID,
|
|
Reference: "test3",
|
|
CreatedAt: now.Add(-55 * time.Minute).UTC().Time,
|
|
Type: models.PAYMENT_TYPE_PAYOUT,
|
|
InitialAmount: big.NewInt(300),
|
|
Amount: big.NewInt(300),
|
|
Asset: "DKK/2",
|
|
Scheme: models.PAYMENT_SCHEME_A2A,
|
|
Status: models.PAYMENT_STATUS_PENDING,
|
|
SourceAccountID: &defaultAccounts()[1].ID,
|
|
},
|
|
}
|
|
|
|
t.Run("wrong query builder operator when listing with reference", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Lt("reference", "test1")),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.Error(t, err)
|
|
require.Nil(t, cursor)
|
|
assert.True(t, errors.Is(err, ErrValidation))
|
|
assert.Regexp(t, "reference", err.Error())
|
|
})
|
|
|
|
t.Run("list payments by reference", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Match("reference", "test1")),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 1)
|
|
require.False(t, cursor.HasMore)
|
|
comparePayments(t, dps[0], cursor.Data[0])
|
|
})
|
|
|
|
t.Run("list payments by unknown reference", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Match("reference", "unknown")),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 0)
|
|
require.False(t, cursor.HasMore)
|
|
})
|
|
|
|
t.Run("list payments by id", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Match("id", dps[0].ID.String())),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 1)
|
|
require.False(t, cursor.HasMore)
|
|
comparePayments(t, dps[0], cursor.Data[0])
|
|
})
|
|
|
|
t.Run("list payments by unknown id", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Match("id", "unknown")),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 0)
|
|
require.False(t, cursor.HasMore)
|
|
})
|
|
|
|
t.Run("list payments by connector_id", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Match("connector_id", defaultConnector.ID.String())),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 3)
|
|
require.False(t, cursor.HasMore)
|
|
comparePayments(t, dps[1], cursor.Data[0])
|
|
comparePayments(t, dps[2], cursor.Data[1])
|
|
comparePayments(t, dps[0], cursor.Data[2])
|
|
})
|
|
|
|
t.Run("list payments by unknown connector_id", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Match("connector_id", "unknown")),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 0)
|
|
require.False(t, cursor.HasMore)
|
|
})
|
|
|
|
t.Run("list payments by type", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Match("type", "PAYOUT")),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 1)
|
|
require.False(t, cursor.HasMore)
|
|
comparePayments(t, dps[2], cursor.Data[0])
|
|
})
|
|
|
|
t.Run("list payments by unknown type", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Match("type", "UNKNOWN")),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 0)
|
|
require.False(t, cursor.HasMore)
|
|
})
|
|
|
|
t.Run("list payments by asset", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Match("asset", "EUR/2")),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 1)
|
|
require.False(t, cursor.HasMore)
|
|
comparePayments(t, dps[1], cursor.Data[0])
|
|
})
|
|
|
|
t.Run("list payments by unknown asset", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Match("asset", "UNKNOWN")),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 0)
|
|
require.False(t, cursor.HasMore)
|
|
})
|
|
|
|
t.Run("list payments by scheme", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Match("scheme", "OTHER")),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 2)
|
|
require.False(t, cursor.HasMore)
|
|
comparePayments(t, dps[1], cursor.Data[0])
|
|
comparePayments(t, dps[0], cursor.Data[1])
|
|
})
|
|
|
|
t.Run("list payments by unknown scheme", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Match("scheme", "UNKNOWN")),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 0)
|
|
require.False(t, cursor.HasMore)
|
|
})
|
|
|
|
t.Run("list payments by status", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Match("status", "PENDING")),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 1)
|
|
require.False(t, cursor.HasMore)
|
|
comparePayments(t, dps[2], cursor.Data[0])
|
|
})
|
|
|
|
t.Run("list payments by unknown status", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Match("status", "UNKNOWN")),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 0)
|
|
require.False(t, cursor.HasMore)
|
|
})
|
|
|
|
t.Run("list payments by source account id", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Match("source_account_id", defaultAccounts()[0].ID.String())),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 1)
|
|
require.False(t, cursor.HasMore)
|
|
comparePayments(t, dps[0], cursor.Data[0])
|
|
})
|
|
|
|
t.Run("list payments by unknown source account id", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Match("source_account_id", "unknown")),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 0)
|
|
require.False(t, cursor.HasMore)
|
|
})
|
|
|
|
t.Run("list payments by destination account id", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Match("destination_account_id", defaultAccounts()[0].ID.String())),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 1)
|
|
require.False(t, cursor.HasMore)
|
|
comparePayments(t, dps[1], cursor.Data[0])
|
|
})
|
|
|
|
t.Run("list payments by unknown destination account id", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Match("destination_account_id", "unknown")),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 0)
|
|
require.False(t, cursor.HasMore)
|
|
})
|
|
|
|
t.Run("list payments by amount", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Match("amount", 200)),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 1)
|
|
require.False(t, cursor.HasMore)
|
|
comparePayments(t, dps[1], cursor.Data[0])
|
|
})
|
|
|
|
t.Run("list payments by unknown amount", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Match("amount", 0)),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 0)
|
|
require.False(t, cursor.HasMore)
|
|
})
|
|
|
|
t.Run("list payments by initial_amount", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Match("initial_amount", 300)),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 1)
|
|
require.False(t, cursor.HasMore)
|
|
comparePayments(t, dps[2], cursor.Data[0])
|
|
})
|
|
|
|
t.Run("list payments by unknown initial_amount", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Match("initial_amount", 0)),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 0)
|
|
require.False(t, cursor.HasMore)
|
|
})
|
|
|
|
t.Run("wrong query builder operator when listing by metadata", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Lt("metadata[key1]", "value1")),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.Error(t, err)
|
|
require.Nil(t, cursor)
|
|
})
|
|
|
|
t.Run("list payments by metadata", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Match("metadata[key1]", "value1")),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 1)
|
|
require.False(t, cursor.HasMore)
|
|
comparePayments(t, dps[0], cursor.Data[0])
|
|
})
|
|
|
|
t.Run("list payments by unknown metadata", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Match("metadata[key1]", "unknown")),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 0)
|
|
require.False(t, cursor.HasMore)
|
|
})
|
|
|
|
t.Run("list payments by unknown metadata 2", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Match("metadata[unknown]", "unknown")),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 0)
|
|
require.False(t, cursor.HasMore)
|
|
})
|
|
|
|
t.Run("unknown query builder key when listing", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(15).
|
|
WithQueryBuilder(query.Match("unknown", "unknown")),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.Error(t, err)
|
|
require.Nil(t, cursor)
|
|
})
|
|
|
|
t.Run("list payments test cursor", func(t *testing.T) {
|
|
q := NewListPaymentsQuery(
|
|
bunpaginate.NewPaginatedQueryOptions(PaymentQuery{}).
|
|
WithPageSize(1),
|
|
)
|
|
|
|
cursor, err := store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 1)
|
|
require.True(t, cursor.HasMore)
|
|
require.Empty(t, cursor.Previous)
|
|
require.NotEmpty(t, cursor.Next)
|
|
comparePayments(t, dps[1], cursor.Data[0])
|
|
|
|
err = bunpaginate.UnmarshalCursor(cursor.Next, &q)
|
|
require.NoError(t, err)
|
|
cursor, err = store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 1)
|
|
require.True(t, cursor.HasMore)
|
|
require.NotEmpty(t, cursor.Previous)
|
|
require.NotEmpty(t, cursor.Next)
|
|
comparePayments(t, dps[2], cursor.Data[0])
|
|
|
|
err = bunpaginate.UnmarshalCursor(cursor.Next, &q)
|
|
require.NoError(t, err)
|
|
cursor, err = store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 1)
|
|
require.False(t, cursor.HasMore)
|
|
require.NotEmpty(t, cursor.Previous)
|
|
require.Empty(t, cursor.Next)
|
|
comparePayments(t, dps[0], cursor.Data[0])
|
|
|
|
err = bunpaginate.UnmarshalCursor(cursor.Previous, &q)
|
|
require.NoError(t, err)
|
|
cursor, err = store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 1)
|
|
require.True(t, cursor.HasMore)
|
|
require.NotEmpty(t, cursor.Previous)
|
|
require.NotEmpty(t, cursor.Next)
|
|
comparePayments(t, dps[2], cursor.Data[0])
|
|
|
|
err = bunpaginate.UnmarshalCursor(cursor.Previous, &q)
|
|
require.NoError(t, err)
|
|
cursor, err = store.PaymentsList(ctx, q)
|
|
require.NoError(t, err)
|
|
require.Len(t, cursor.Data, 1)
|
|
require.True(t, cursor.HasMore)
|
|
require.Empty(t, cursor.Previous)
|
|
require.NotEmpty(t, cursor.Next)
|
|
comparePayments(t, dps[1], cursor.Data[0])
|
|
})
|
|
}
|
|
|
|
func comparePayments(t *testing.T, expected, actual models.Payment) {
|
|
require.Equal(t, expected.ID, actual.ID)
|
|
require.Equal(t, expected.ConnectorID, actual.ConnectorID)
|
|
require.Equal(t, expected.Reference, actual.Reference)
|
|
require.Equal(t, expected.CreatedAt, actual.CreatedAt)
|
|
require.Equal(t, expected.Type, actual.Type)
|
|
require.Equal(t, expected.InitialAmount, actual.InitialAmount)
|
|
require.Equal(t, expected.Amount, actual.Amount)
|
|
require.Equal(t, expected.Asset, actual.Asset)
|
|
require.Equal(t, expected.Scheme, actual.Scheme)
|
|
|
|
switch {
|
|
case expected.SourceAccountID == nil:
|
|
require.Nil(t, actual.SourceAccountID)
|
|
default:
|
|
require.NotNil(t, actual.SourceAccountID)
|
|
require.Equal(t, *expected.SourceAccountID, *actual.SourceAccountID)
|
|
}
|
|
|
|
switch {
|
|
case expected.DestinationAccountID == nil:
|
|
require.Nil(t, actual.DestinationAccountID)
|
|
default:
|
|
require.NotNil(t, actual.DestinationAccountID)
|
|
require.Equal(t, *expected.DestinationAccountID, *actual.DestinationAccountID)
|
|
}
|
|
|
|
require.Equal(t, len(expected.Metadata), len(actual.Metadata))
|
|
for k, v := range expected.Metadata {
|
|
_, ok := actual.Metadata[k]
|
|
require.True(t, ok)
|
|
require.Equal(t, v, actual.Metadata[k])
|
|
}
|
|
|
|
require.Equal(t, len(expected.Adjustments), len(actual.Adjustments))
|
|
for i := range expected.Adjustments {
|
|
comparePaymentAdjustments(t, expected.Adjustments[i], actual.Adjustments[i])
|
|
}
|
|
}
|
|
|
|
func comparePaymentAdjustments(t *testing.T, expected, actual models.PaymentAdjustment) {
|
|
require.Equal(t, expected.ID, actual.ID)
|
|
require.Equal(t, expected.CreatedAt, actual.CreatedAt)
|
|
require.Equal(t, expected.Status, actual.Status)
|
|
require.Equal(t, expected.Amount, actual.Amount)
|
|
require.Equal(t, expected.Asset, actual.Asset)
|
|
}
|