Skip to content

Commit

Permalink
SEPA Direct Debit Core Support (#109)
Browse files Browse the repository at this point in the history
* Fix Rates property

* Fix LocalSchemes property

* Add SEPA Direct Debit Core Support
  • Loading branch information
armando-rodriguez-cko authored Apr 16, 2024
1 parent 6aba3bf commit ed5b46b
Show file tree
Hide file tree
Showing 9 changed files with 139 additions and 4 deletions.
1 change: 1 addition & 0 deletions common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ const (
Card InstrumentType = "card"
BankAccount InstrumentType = "bank_account"
Token InstrumentType = "token"
Sepa InstrumentType = "sepa"
CardToken InstrumentType = "card_token"
)

Expand Down
2 changes: 1 addition & 1 deletion forex/forex.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ type (
RatesResponse struct {
Product string `json:"product,omitempty"`
Source Source `json:"source,omitempty"`
Rates []Rate `json:"currency_pairs,omitempty"`
Rates []Rate `json:"rates,omitempty"`
InvalidCurrencyPairs []string `json:"invalid_currency_pairs,omitempty"`
}
)
Expand Down
51 changes: 51 additions & 0 deletions instruments/nas/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package nas
import (
"net/http"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
Expand All @@ -11,6 +12,7 @@ import (
"github.com/checkout/checkout-sdk-go/configuration"
"github.com/checkout/checkout-sdk-go/errors"
"github.com/checkout/checkout-sdk-go/mocks"
"github.com/checkout/checkout-sdk-go/payments"
)

const (
Expand Down Expand Up @@ -71,6 +73,17 @@ func TestCreate(t *testing.T) {
HttpMetadata: mocks.HttpMetadataStatusCreated,
CreateBankAccountInstrumentResponse: &bankAccount,
}

sepa = CreateSepaInstrumentResponse{
Type: common.Sepa,
Id: "src_wmlfc3zyhqzehihu7giusaaawu",
Fingerprint: "vnsdrvikkvre3dtrjjvlm5du4q",
}

createSepaResponse = CreateInstrumentResponse{
HttpMetadata: mocks.HttpMetadataStatusCreated,
CreateSepaInstrumentResponse: &sepa,
}
)

cases := []struct {
Expand Down Expand Up @@ -126,6 +139,29 @@ func TestCreate(t *testing.T) {
assert.Equal(t, bankAccount.Id, response.CreateBankAccountInstrumentResponse.Id)
},
},
{
name: "when request is for sepa instrument then create sepa instrument",
request: getCreateSepaInstrumentRequest(),
getAuthorization: func(m *mock.Mock) mock.Call {
return *m.On("GetAuthorization", mock.Anything).
Return(&configuration.SdkAuthorization{}, nil)
},
apiPost: func(m *mock.Mock) mock.Call {
return *m.On("Post", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).
Return(nil).
Run(func(args mock.Arguments) {
respMapping := args.Get(3).(*CreateInstrumentResponse)
*respMapping = createSepaResponse
})
},
checker: func(response *CreateInstrumentResponse, err error) {
assert.Nil(t, err)
assert.NotNil(t, response)
assert.Equal(t, http.StatusCreated, response.HttpMetadata.StatusCode)
assert.NotNil(t, response.CreateSepaInstrumentResponse)
assert.Equal(t, sepa.Id, response.CreateSepaInstrumentResponse.Id)
},
},
{
name: "when credentials invalid then return error",
getAuthorization: func(m *mock.Mock) mock.Call {
Expand Down Expand Up @@ -199,6 +235,21 @@ func getCreateTokenInstrumentRequest() *createTokenInstrumentRequest {
return r
}

func getCreateSepaInstrumentRequest() *createSepaInstrumentRequest {
time := time.Now()

r := NewCreateSepaInstrumentRequest()
r.InstrumentData = &InstrumentData{
AccountNumber: "FR2810096000509685512959O86",
Country: common.GB,
Currency: common.GBP,
PaymentType: payments.Recurring,
MandateId: "1234567890",
DateOfSignature: &time,
}
return r
}

func getCreateBankAccountInstrumentRequest() *createBankAccountInstrumentRequest {
r := NewCreateBankAccountInstrumentRequest()
r.AccountType = common.Savings
Expand Down
26 changes: 26 additions & 0 deletions instruments/nas/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ type (
AccountHolder *common.AccountHolder `json:"account_holder" binding:"required"`
Customer *CreateCustomerInstrumentRequest `json:"customer,omitempty"`
}

createSepaInstrumentRequest struct {
Type common.InstrumentType `json:"type" binding:"required"`
InstrumentData *InstrumentData `json:"instrument_data,omitempty"`
AccountHolder *common.AccountHolder `json:"account_holder" binding:"required"`
}
)

func NewCreateBankAccountInstrumentRequest() *createBankAccountInstrumentRequest {
Expand All @@ -46,11 +52,18 @@ func NewCreateTokenInstrumentRequest() *createTokenInstrumentRequest {
}
}

func NewCreateSepaInstrumentRequest() *createSepaInstrumentRequest {
return &createSepaInstrumentRequest{
Type: common.Sepa,
}
}

type (
CreateInstrumentResponse struct {
HttpMetadata common.HttpMetadata
CreateBankAccountInstrumentResponse *CreateBankAccountInstrumentResponse
CreateTokenInstrumentResponse *CreateTokenInstrumentResponse
CreateSepaInstrumentResponse *CreateSepaInstrumentResponse
AlternativeResponse *common.AlternativeResponse
}

Expand Down Expand Up @@ -88,6 +101,13 @@ type (
ProductId string `json:"product_id,omitempty"`
ProductType string `json:"product_type,omitempty"`
}

CreateSepaInstrumentResponse struct {
Type common.InstrumentType `json:"type" binding:"required"`
// common
Id string `json:"id,omitempty"`
Fingerprint string `json:"fingerprint,omitempty"`
}
)

func (s *CreateInstrumentResponse) UnmarshalJSON(data []byte) error {
Expand All @@ -109,6 +129,12 @@ func (s *CreateInstrumentResponse) UnmarshalJSON(data []byte) error {
return nil
}
s.CreateTokenInstrumentResponse = &response
case string(common.Sepa):
var response CreateSepaInstrumentResponse
if err := json.Unmarshal(data, &response); err != nil {
return nil
}
s.CreateSepaInstrumentResponse = &response
default:
var response common.AlternativeResponse
if err := json.Unmarshal(data, &response); err != nil {
Expand Down
19 changes: 19 additions & 0 deletions instruments/nas/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package nas

import (
"encoding/json"
"time"

"github.com/checkout/checkout-sdk-go/common"
"github.com/checkout/checkout-sdk-go/instruments"
Expand All @@ -16,6 +17,7 @@ type (
GetInstrumentResponse struct {
HttpMetadata common.HttpMetadata
GetCardInstrumentResponse *GetCardInstrumentResponse
GetSepaInstrumentResponse *GetSepaInstrumentResponse
GetBankAccountInstrumentResponse *GetBankAccountInstrumentResponse
AlternativeResponse *common.AlternativeResponse
}
Expand All @@ -42,6 +44,17 @@ type (
ProductType string `json:"product_type,omitempty"`
}

GetSepaInstrumentResponse struct {
Type common.InstrumentType `json:"type" binding:"required"`
Id string `json:"id,omitempty"`
Fingerprint string `json:"fingerprint,omitempty"`
CreatedOn *time.Time `json:"created_on,omitempty"`
ModifiedOn *time.Time `json:"modified_on,omitempty"`
VaultId string `json:"vault_id,omitempty"`
InstrumentData *InstrumentData `json:"instrument_data,omitempty"`
AccountHolder *common.AccountHolder `json:"account_holder,omitempty"`
}

GetBankAccountInstrumentResponse struct {
Type common.InstrumentType `json:"type" binding:"required"`
Id string `json:"id,omitempty"`
Expand Down Expand Up @@ -114,6 +127,12 @@ func (s *GetInstrumentResponse) UnmarshalJSON(data []byte) error {
return nil
}
s.GetCardInstrumentResponse = &response
case string(common.Sepa):
var response GetSepaInstrumentResponse
if err := json.Unmarshal(data, &response); err != nil {
return nil
}
s.GetSepaInstrumentResponse = &response
default:
var response common.AlternativeResponse
if err := json.Unmarshal(data, &response); err != nil {
Expand Down
12 changes: 12 additions & 0 deletions instruments/nas/instuments.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package nas

import (
"time"

"github.com/checkout/checkout-sdk-go/common"
"github.com/checkout/checkout-sdk-go/payments"
)

type PaymentNetwork string
Expand All @@ -15,6 +18,15 @@ const (
Swift PaymentNetwork = "swift"
)

type InstrumentData struct {
AccountNumber string `json:"account_number,omitempty"`
Country common.Country `json:"country,omitempty"`
Currency common.Currency `json:"currency,omitempty"`
PaymentType payments.PaymentType `json:"payment_type,omitempty"`
MandateId string `json:"mandate_id,omitempty"`
DateOfSignature *time.Time `json:"date_of_signature,omitempty"`
}

type CreateCustomerInstrumentRequest struct {
Id string `json:"id,omitempty"`
Email string `json:"email,omitempty"`
Expand Down
2 changes: 1 addition & 1 deletion metadata/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ type (
Scheme string `json:"scheme,omitempty"`
// Deprecated: This property will be removed in the future, and should not be used. Use LocalSchemes instead.
SchemeLocal SchemeLocalType `json:"scheme_local,omitempty"`
LocalSchemes SchemeLocalType `json:"local_schemes,omitempty"`
LocalSchemes []SchemeLocalType `json:"local_schemes,omitempty"`
CardType common.CardType `json:"card_type,omitempty"`
CardCategory common.CardCategory `json:"card_category,omitempty"`
Currency common.Currency `json:"currency,omitempty"`
Expand Down
1 change: 1 addition & 0 deletions payments/nas/payments.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ type (
Items []payments.Product `json:"items,omitempty"`
Retry *payments.PaymentRetryRequest `json:"retry,omitempty"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
Instruction *PaymentInstruction `json:"instruction,omitempty"`
}

PayoutRequest struct {
Expand Down
29 changes: 27 additions & 2 deletions test/instruments_test.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package test

import (
"github.com/stretchr/testify/assert"
"net/http"
"testing"

"github.com/stretchr/testify/assert"

"github.com/checkout/checkout-sdk-go/common"
"github.com/checkout/checkout-sdk-go/errors"
"github.com/checkout/checkout-sdk-go/instruments/nas"
"github.com/checkout/checkout-sdk-go/payments"
"github.com/checkout/checkout-sdk-go/tokens"
)

Expand All @@ -18,6 +18,7 @@ var (

func TestSetupInstrument(t *testing.T) {
cardTokenResponse := RequestCardToken(t)
_ = createSepaInstrument(t)
instrumentToken = createTokenInstrument(t, cardTokenResponse)
}

Expand Down Expand Up @@ -211,6 +212,30 @@ func TestShouldDeleteInstrument(t *testing.T) {
}
}

func createSepaInstrument(t *testing.T) *nas.CreateSepaInstrumentResponse {
request := nas.NewCreateSepaInstrumentRequest()
request.InstrumentData = &nas.InstrumentData{
AccountNumber: "FR7630006000011234567890189",
Country: common.FR,
Currency: common.EUR,
PaymentType: payments.Recurring,
}
request.AccountHolder = &common.AccountHolder{
FirstName: "Ali",
LastName: "Farid",
BillingAddress: Address(),
Phone: Phone(),
}

response, err := DefaultApi().Instruments.Create(request)
assert.Nil(t, err)
assert.NotNil(t, response.CreateSepaInstrumentResponse)
assert.Equal(t, common.Sepa, response.CreateSepaInstrumentResponse.Type)
assert.NotEmpty(t, response.CreateSepaInstrumentResponse.Id)
assert.NotEmpty(t, response.CreateSepaInstrumentResponse.Fingerprint)
return response.CreateSepaInstrumentResponse
}

func createTokenInstrument(t *testing.T, token *tokens.CardTokenResponse) *nas.CreateTokenInstrumentResponse {
request := nas.NewCreateTokenInstrumentRequest()
request.Token = token.Token
Expand Down

0 comments on commit ed5b46b

Please sign in to comment.