Skip to content

Commit

Permalink
Add sync withdrawal reqeust
Browse files Browse the repository at this point in the history
  • Loading branch information
AchoArnold committed Sep 11, 2022
1 parent 206f541 commit 06bb6ac
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 13 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ vendor/
# Temp file on windows
$path

utilities_service_test.go
*e2e_test.go
21 changes: 21 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,27 @@ func (client *Client) Withdraw(ctx context.Context, params *WithdrawParams) (*Wi
return &withdrawResponse, response, nil
}

// WithdrawSync transfers money to a mobile number and waits for the transaction to be completed.
// POST /withdraw/
// API Doc: https://documenter.getpostman.com/view/2391374/T1LV8PVA#885dbde0-b0dd-4514-a0f9-f84fc83df12d
func (client *Client) WithdrawSync(ctx context.Context, params *WithdrawParams) (*Transaction, *Response, error) {
transaction, response, err := client.Withdraw(ctx, params)
if err != nil {
return nil, response, err
}

// wait for completion in 2 minutes
counter := 1
for {
status, response, err := client.Transaction.Get(ctx, transaction.Reference)
if err != nil || !status.IsPending() || ctx.Err() != nil || counter == 12 {
return status, response, err
}
time.Sleep(10 * time.Second)
counter++
}
}

// newRequest creates an API request. A relative URL can be provided in uri,
// in which case it is resolved relative to the BaseURL of the Client.
// URI's should always be specified without a preceding slash.
Expand Down
39 changes: 39 additions & 0 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,42 @@ func TestClient_Withdraw(t *testing.T) {
// Teardown
server.Close()
}

func TestClient_WithdrawSync(t *testing.T) {
// Setup
t.Parallel()

// Arrange
requests := make([]*http.Request, 0)
responses := [][]byte{stubs.PostTokenResponse(), stubs.PostWithdrawResponse(), stubs.GetPendingTransactionResponse(), stubs.GetSuccessfulTransactionResponse()}
server := helpers.MakeRequestCapturingTestServer(http.StatusOK, responses, &requests)
client := New(WithEnvironment(Environment(server.URL)))

// Act
transaction, _, err := client.WithdrawSync(context.Background(), &WithdrawParams{
Amount: 100,
To: "2376XXXXXXXX",
Description: "Test",
ExternalReference: nil,
})

// Assert
assert.Nil(t, err)

assert.GreaterOrEqual(t, len(requests), 4)
assert.Equal(t, &Transaction{
Reference: "bcedde9b-62a7-4421-96ac-2e6179552a1a",
Status: "SUCCESSFUL",
Amount: 1,
Currency: "XAF",
Operator: "MTN",
Code: "CP201027T00005",
OperatorReference: "1880106956",
}, transaction)

assert.True(t, transaction.IsSuccessfull())
assert.False(t, transaction.IsPending())

// Teardown
server.Close()
}
62 changes: 60 additions & 2 deletions internal/stubs/api_responses.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ func PostCollectResponse() string {
}`
}

// GetTransactionResponse is a dummy JSON response for the Transaction Status
func GetTransactionResponse() []byte {
// GetPendingTransactionResponse is a dummy JSON response for the Transaction Status
func GetPendingTransactionResponse() []byte {
return []byte(`
{
"reference": "bcedde9b-62a7-4421-96ac-2e6179552a1a",
Expand All @@ -34,6 +34,54 @@ func GetTransactionResponse() []byte {
}`)
}

// GetSuccessfulTransactionResponse is a dummy JSON response for the Transaction Status
func GetSuccessfulTransactionResponse() []byte {
return []byte(`
{
"reference": "bcedde9b-62a7-4421-96ac-2e6179552a1a",
"status": "SUCCESSFUL",
"amount": 1,
"currency": "XAF",
"operator": "MTN",
"code": "CP201027T00005",
"operator_reference": "1880106956"
}`)
}

// GetPendingAirtimeTransactionResponse is a dummy JSON response for a pending airtime transaction
func GetPendingAirtimeTransactionResponse() []byte {
return []byte(`
{
"reference": "971e32ae-bb5a-420a-a38a-c2931536609f",
"external_reference": "5577006791947779410",
"status": "PENDING",
"amount": 100,
"currency": "XAF",
"operator": "ORANGE_CM",
"code": "CP220804U0649K",
"type": "AIRTIME",
"reason": ""
}
`)
}

// GetSuccessfullAirtimeTransactionResponse is a dummy JSON response for a successful airtime transaction
func GetSuccessfullAirtimeTransactionResponse() []byte {
return []byte(`
{
"reference": "971e32ae-bb5a-420a-a38a-c2931536609f",
"external_reference": "5577006791947779410",
"status": "SUCCESSFUL",
"amount": 100,
"currency": "XAF",
"operator": "ORANGE_CM",
"code": "CP220804U0649K",
"type": "AIRTIME",
"reason": ""
}
`)
}

// GetBalanceResponse is a dummy JSON response for the transaction balance
func GetBalanceResponse() string {
return `
Expand All @@ -46,6 +94,16 @@ func GetBalanceResponse() string {
`
}

// PostTransferResponse is a dummy JSON response for airtime transfer requests
func PostTransferResponse() []byte {
return []byte(`
{
"reference":"26676007-1c31-46d7-9c71-acb031cf0de4",
"status":"PENDING"
}
`)
}

// PostWithdrawResponse is a dummy JSON response for withdraw requests
func PostWithdrawResponse() []byte {
return []byte(`
Expand Down
10 changes: 10 additions & 0 deletions transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,13 @@ type Transaction struct {
Code string `json:"code"`
OperatorReference string `json:"operator_reference"`
}

// IsPending checks if a transaction is pending
func (transaction *Transaction) IsPending() bool {
return transaction.Status == "PENDING"
}

// IsSuccessfull checks if a transaction is successfull
func (transaction *Transaction) IsSuccessfull() bool {
return transaction.Status == "SUCCESSFUL"
}
2 changes: 1 addition & 1 deletion transaction_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func TestTransactionService_Get(t *testing.T) {

// Arrange
requests := make([]*http.Request, 0)
responses := [][]byte{stubs.PostTokenResponse(), stubs.GetTransactionResponse()}
responses := [][]byte{stubs.PostTokenResponse(), stubs.GetPendingTransactionResponse()}
server := helpers.MakeRequestCapturingTestServer(http.StatusOK, responses, &requests)
client := New(WithEnvironment(Environment(server.URL)))
reference := "bcedde9b-62a7-4421-96ac-2e6179552a1a"
Expand Down
18 changes: 9 additions & 9 deletions utilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ type AirtimeTransferResponse struct {

// UtilitiesTransaction represent a utility transaction
type UtilitiesTransaction struct {
Reference string `json:"reference"`
ExternalReference string `json:"external_reference"`
Status string `json:"status"`
Amount float64 `json:"amount"`
Currency string `json:"currency"`
Operator string `json:"operator"`
Code string `json:"code"`
Type string `json:"type"`
Reason interface{} `json:"reason"`
Reference string `json:"reference"`
ExternalReference string `json:"external_reference"`
Status string `json:"status"`
Amount float64 `json:"amount"`
Currency string `json:"currency"`
Operator string `json:"operator"`
Code string `json:"code"`
Type string `json:"type"`
Reason string `json:"reason"`
}

// IsPending checks if a transaction is pending
Expand Down
51 changes: 51 additions & 0 deletions utilities_service_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package campay

import (
"context"
"net/http"
"testing"

"github.com/NdoleStudio/campay-go-sdk/internal/helpers"
"github.com/NdoleStudio/campay-go-sdk/internal/stubs"
"github.com/stretchr/testify/assert"
)

func TestUtilitiesService_AirtimeTransferSync(t *testing.T) {
// Setup
t.Parallel()

// Arrange
requests := make([]*http.Request, 0)
responses := [][]byte{stubs.PostTokenResponse(), stubs.PostTransferResponse(), stubs.GetPendingAirtimeTransactionResponse(), stubs.GetSuccessfullAirtimeTransactionResponse()}
server := helpers.MakeRequestCapturingTestServer(http.StatusOK, responses, &requests)
client := New(WithEnvironment(Environment(server.URL)))

// Act
transaction, _, err := client.Utilities.AirtimeTransferSync(context.Background(), &AirtimeTransferParams{
Amount: "100",
To: "2376XXXXXXXXX",
ExternalReference: "5577006791947779410",
})

// Assert
assert.Nil(t, err)

assert.GreaterOrEqual(t, len(requests), 4)
assert.Equal(t, &UtilitiesTransaction{
Reference: "971e32ae-bb5a-420a-a38a-c2931536609f",
ExternalReference: "5577006791947779410",
Status: "SUCCESSFUL",
Amount: 100,
Currency: "XAF",
Operator: "ORANGE_CM",
Code: "CP220804U0649K",
Type: "AIRTIME",
Reason: "",
}, transaction)

assert.True(t, transaction.IsSuccessfull())
assert.False(t, transaction.IsPending())

// Teardown
server.Close()
}

0 comments on commit 06bb6ac

Please sign in to comment.