From 905cb63fdfb8bac18b82bf642a2e0c4ccd969e9a Mon Sep 17 00:00:00 2001 From: Paul Nicolas Date: Tue, 28 Jan 2025 09:46:37 +0100 Subject: [PATCH 1/3] fix(currencycloud): use entity id and entity type for payments --- .../currencycloud/client/transactions.go | 18 +++++++------ .../plugins/public/currencycloud/payments.go | 26 ++++++++++++++----- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/internal/connectors/plugins/public/currencycloud/client/transactions.go b/internal/connectors/plugins/public/currencycloud/client/transactions.go index 3105b3c57..6418e9572 100644 --- a/internal/connectors/plugins/public/currencycloud/client/transactions.go +++ b/internal/connectors/plugins/public/currencycloud/client/transactions.go @@ -12,14 +12,16 @@ import ( //nolint:tagliatelle // allow different styled tags in client type Transaction struct { - ID string `json:"id"` - AccountID string `json:"account_id"` - Currency string `json:"currency"` - Type string `json:"type"` - Status string `json:"status"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - Action string `json:"action"` + ID string `json:"id"` + AccountID string `json:"account_id"` + Currency string `json:"currency"` + Type string `json:"type"` + Status string `json:"status"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + Action string `json:"action"` + RelatedEntityType string `json:"related_entity_type"` + RelatedEntityID string `json:"related_entity_id"` Amount json.Number `json:"amount"` } diff --git a/internal/connectors/plugins/public/currencycloud/payments.go b/internal/connectors/plugins/public/currencycloud/payments.go index 415901d6e..829884181 100644 --- a/internal/connectors/plugins/public/currencycloud/payments.go +++ b/internal/connectors/plugins/public/currencycloud/payments.go @@ -118,10 +118,14 @@ func transactionToPayment(transaction client.Transaction) (*models.PSPPayment, e return nil, err } - paymentType := matchTransactionType(transaction.Type) + paymentType := matchTransactionType(transaction.RelatedEntityType, transaction.Type) + reference := transaction.RelatedEntityID + if reference == "" { + reference = transaction.ID + } payment := &models.PSPPayment{ - Reference: transaction.ID, + Reference: reference, CreatedAt: transaction.CreatedAt, Type: paymentType, Amount: amount, @@ -141,13 +145,23 @@ func transactionToPayment(transaction client.Transaction) (*models.PSPPayment, e return payment, nil } -func matchTransactionType(transactionType string) models.PaymentType { - switch transactionType { - case "credit": +func matchTransactionType(entityType string, transactionType string) models.PaymentType { + switch entityType { + case "inbound_funds": return models.PAYMENT_TYPE_PAYIN - case "debit": + case "payment": return models.PAYMENT_TYPE_PAYOUT + case "transfer", "balance_transfer": + return models.PAYMENT_TYPE_TRANSFER + default: + switch transactionType { + case "credit": + return models.PAYMENT_TYPE_PAYIN + case "debit": + return models.PAYMENT_TYPE_PAYOUT + } } + return models.PAYMENT_TYPE_OTHER } From 559f0d576540ac02391dedfaa2420ab63efaa5a4 Mon Sep 17 00:00:00 2001 From: Paul Nicolas Date: Tue, 28 Jan 2025 10:18:03 +0100 Subject: [PATCH 2/3] fix(currencycloud): fix useless contact fetch and missing reason --- .../public/currencycloud/client/payouts.go | 5 ++-- .../plugins/public/currencycloud/payouts.go | 7 +----- .../public/currencycloud/payouts_test.go | 24 ++----------------- 3 files changed, 6 insertions(+), 30 deletions(-) diff --git a/internal/connectors/plugins/public/currencycloud/client/payouts.go b/internal/connectors/plugins/public/currencycloud/client/payouts.go index fcd0988cd..e518a4c59 100644 --- a/internal/connectors/plugins/public/currencycloud/client/payouts.go +++ b/internal/connectors/plugins/public/currencycloud/client/payouts.go @@ -13,20 +13,21 @@ import ( ) type PayoutRequest struct { - OnBehalfOf string `json:"on_behalf_of"` BeneficiaryID string `json:"beneficiary_id"` Currency string `json:"currency"` Amount json.Number `json:"amount"` Reference string `json:"reference"` + Reason string `json:"reason"` UniqueRequestID string `json:"unique_request_id"` } func (pr *PayoutRequest) ToFormData() url.Values { form := url.Values{} - form.Set("on_behalf_of", pr.OnBehalfOf) form.Set("beneficiary_id", pr.BeneficiaryID) form.Set("currency", pr.Currency) form.Set("amount", pr.Amount.String()) + form.Set("reason", pr.Reason) + form.Set("payment_type", "regular") form.Set("reference", pr.Reference) if pr.UniqueRequestID != "" { form.Set("unique_request_id", pr.UniqueRequestID) diff --git a/internal/connectors/plugins/public/currencycloud/payouts.go b/internal/connectors/plugins/public/currencycloud/payouts.go index 4b3b7e41f..c67119474 100644 --- a/internal/connectors/plugins/public/currencycloud/payouts.go +++ b/internal/connectors/plugins/public/currencycloud/payouts.go @@ -37,17 +37,12 @@ func (p *Plugin) createPayout(ctx context.Context, pi models.PSPPaymentInitiatio return models.PSPPayment{}, fmt.Errorf("failed to get string amount from big int: %v: %w", err, models.ErrInvalidRequest) } - contact, err := p.client.GetContactID(ctx, pi.SourceAccount.Reference) - if err != nil { - return models.PSPPayment{}, err - } - resp, err := p.client.InitiatePayout(ctx, &client.PayoutRequest{ - OnBehalfOf: contact.ID, BeneficiaryID: pi.DestinationAccount.Reference, Currency: curr, Amount: json.Number(amount), Reference: pi.Description, + Reason: pi.Description, UniqueRequestID: pi.Reference, }) if err != nil { diff --git a/internal/connectors/plugins/public/currencycloud/payouts_test.go b/internal/connectors/plugins/public/currencycloud/payouts_test.go index 91ff3a5a7..e89274934 100644 --- a/internal/connectors/plugins/public/currencycloud/payouts_test.go +++ b/internal/connectors/plugins/public/currencycloud/payouts_test.go @@ -99,34 +99,17 @@ var _ = Describe("CurrencyCloud Plugin Payouts Creation", func() { Expect(resp).To(Equal(models.CreatePayoutResponse{})) }) - It("should return an error - get contactID error", func(ctx SpecContext) { - req := models.CreatePayoutRequest{ - PaymentInitiation: samplePSPPaymentInitiation, - } - - m.EXPECT().GetContactID(gomock.Any(), samplePSPPaymentInitiation.SourceAccount.Reference). - Return(nil, errors.New("test error")) - - resp, err := plg.CreatePayout(ctx, req) - Expect(err).ToNot(BeNil()) - Expect(err).To(MatchError("test error")) - Expect(resp).To(Equal(models.CreatePayoutResponse{})) - }) - It("should return an error - initiate payout error", func(ctx SpecContext) { req := models.CreatePayoutRequest{ PaymentInitiation: samplePSPPaymentInitiation, } - m.EXPECT().GetContactID(gomock.Any(), samplePSPPaymentInitiation.SourceAccount.Reference). - Return(&client.Contact{ID: "1"}, nil) - m.EXPECT().InitiatePayout(gomock.Any(), &client.PayoutRequest{ - OnBehalfOf: "1", BeneficiaryID: samplePSPPaymentInitiation.DestinationAccount.Reference, Currency: "EUR", Amount: "1.00", Reference: samplePSPPaymentInitiation.Description, + Reason: samplePSPPaymentInitiation.Description, UniqueRequestID: samplePSPPaymentInitiation.Reference, }).Return(nil, errors.New("test error")) @@ -141,9 +124,6 @@ var _ = Describe("CurrencyCloud Plugin Payouts Creation", func() { PaymentInitiation: samplePSPPaymentInitiation, } - m.EXPECT().GetContactID(gomock.Any(), samplePSPPaymentInitiation.SourceAccount.Reference). - Return(&client.Contact{ID: "1"}, nil) - trResponse := client.PayoutResponse{ ID: "test1", Amount: "1.00", @@ -154,11 +134,11 @@ var _ = Describe("CurrencyCloud Plugin Payouts Creation", func() { CreatedAt: now, } m.EXPECT().InitiatePayout(gomock.Any(), &client.PayoutRequest{ - OnBehalfOf: "1", BeneficiaryID: samplePSPPaymentInitiation.DestinationAccount.Reference, Currency: "EUR", Amount: "1.00", Reference: samplePSPPaymentInitiation.Description, + Reason: samplePSPPaymentInitiation.Description, UniqueRequestID: samplePSPPaymentInitiation.Reference, }).Return(&trResponse, nil) From 4c03e05d5db88c8ef1a0b6b1f193545f41a64475 Mon Sep 17 00:00:00 2001 From: Paul Nicolas Date: Tue, 28 Jan 2025 10:49:15 +0100 Subject: [PATCH 3/3] chore(currencycloud): add tests --- .../public/currencycloud/payments_test.go | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/internal/connectors/plugins/public/currencycloud/payments_test.go b/internal/connectors/plugins/public/currencycloud/payments_test.go index 91a02faa3..0c85f4422 100644 --- a/internal/connectors/plugins/public/currencycloud/payments_test.go +++ b/internal/connectors/plugins/public/currencycloud/payments_test.go @@ -385,3 +385,56 @@ func comparePSPPayments(t *testing.T, a, b models.PSPPayment) { require.Equal(t, v, b.Metadata[k]) } } + +func TestMatchTransactionType(t *testing.T) { + tests := []struct { + entityType string + transactionType string + expectedPaymentType models.PaymentType + }{ + { + entityType: "inbound_funds", + transactionType: "credit", + expectedPaymentType: models.PAYMENT_TYPE_PAYIN, + }, + { + entityType: "payment", + transactionType: "debit", + expectedPaymentType: models.PAYMENT_TYPE_PAYOUT, + }, + { + entityType: "transfer", + transactionType: "debit", + expectedPaymentType: models.PAYMENT_TYPE_TRANSFER, + }, + { + entityType: "balance_transfer", + transactionType: "debit", + expectedPaymentType: models.PAYMENT_TYPE_TRANSFER, + }, + { + entityType: "unknown", + transactionType: "unknown", + expectedPaymentType: models.PAYMENT_TYPE_OTHER, + }, + { + entityType: "unknown", + transactionType: "credit", + expectedPaymentType: models.PAYMENT_TYPE_PAYIN, + }, + { + entityType: "unknown", + transactionType: "debit", + expectedPaymentType: models.PAYMENT_TYPE_PAYOUT, + }, + } + + for _, test := range tests { + t.Run(test.entityType+"-"+test.transactionType, func(t *testing.T) { + t.Parallel() + + paymentType := matchTransactionType(test.entityType, test.transactionType) + require.Equal(t, test.expectedPaymentType, paymentType) + }) + } +}