Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: update failed tests and replace pointers by value #5

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 51 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,31 @@
<h1 align="center">
<div align="center">
<a href="https://chapa.co/" target="_blank">
<img src="./docs/logo.png" width="320" alt="Nest Logo"/>
<img src="./docs/logo.png" width="320" alt="Chapa Logo"/>
</a>
<p align="center">Go SDK for chapa</p>
</div>
</h1>

![build-workflow](https://github.com/Yinebeb-01/chapa-go/actions/workflows/test.yml/badge.svg)
![build-workflow](https://github.com/yinebebt/chapa-go/actions/workflows/test.yml/badge.svg)

Unofficial Golang SDK for Chapa ET API

### Todo:
- [ ] We could add nice validations on demand.
- [ ] Add implementation for the remaining API endpoints.
### Todo

- [ ] We could add nice validations on demand.
- [ ] Add implementation for the remaining API endpoints.

### Usage
##### 1. Installation
```

#### 1. Installation

```bash
go get github.com/Chapa-Et/chapa-go
```

###### API_KEY
##### API_KEY

Add your `API_KEY: CHASECK_xxxxxxxxxxxxxxxx` inside `config.yaml` file.
If you want to run the githb action on your forked repository, you have to create a secrete key named `API_KEY`.

Expand All @@ -41,6 +44,7 @@ If you want to run the githb action on your forked repository, you have to creat
```

##### 3. Accept Payments

```go
request := &chapaAPI.PaymentRequest{
Amount: 10,
Expand All @@ -67,6 +71,7 @@ If you want to run the githb action on your forked repository, you have to creat
```

##### 4. Verify Payment Transactions

```go
response, err := chapaAPI.Verify("your-txn-ref")
if err != nil {
Expand All @@ -78,42 +83,46 @@ If you want to run the githb action on your forked repository, you have to creat
```

##### 5. Transfer to bank

```go
request := &BankTransfer{
AccountName: "Yinebeb Tariku",
AccountNumber: "34264263",
Amount: 10,
BeneficiaryName: "Yinebeb Tariku",
Currency: "ETB",
Reference: "3264063st01",
BankCode: "32735b19-bb36-4cd7-b226-fb7451cd98f0",
}
response, err := chapaAPI.TransferToBank(request)
fmt.Printf("transfer response: %+v\n", response)
AccountName: "Yinebeb Tariku",
AccountNumber: "34264263",
Amount: 10,
BeneficiaryName: "Yinebeb Tariku",
Currency: "ETB",
Reference: "3264063st01",
BankCode: "32735b19-bb36-4cd7-b226-fb7451cd98f0",
}
response, err := chapaAPI.TransferToBank(request)
fmt.Printf("transfer response: %+v\n", response)
```

##### 6. Get transactions
```go
response, err := chapaAPI.getTransactions()
fmt.Printf("transactions response: %+v\n", response)

```go
response, err := chapaAPI.getTransactions()
fmt.Printf("transactions response: %+v\n", response)
```

##### 7. Get banks
```go
response, err := chapaAPI.getBanks()
fmt.Printf("banks response: %+v\n", response)

```go
response, err := chapaAPI.getBanks()
fmt.Printf("banks response: %+v\n", response)
```

##### 8. Bulk transfer
```go
bulkData := BulkData{
AccountName: "Leul Abay Ejigu",
AccountNumber: "1000212482106",
Amount: 10,
Reference: "3241342142sfdd",
BankCode: "946",
}

```go
bulkData := BulkData{
AccountName: "Leul Abay Ejigu",
AccountNumber: "1000212482106",
Amount: 10,
Reference: "3241342142sfdd",
BankCode: "946",
}

request := &BulkTransferRequest{
Title: "Transfer to leul",
Expand All @@ -126,12 +135,16 @@ If you want to run the githb action on your forked repository, you have to creat
```

### Resources
- https://developer.chapa.co/docs/overview/

- <https://developer.chapa.co/docs/overview/>

### Quirks

Suggestions on how to improve the API:

- Introduction of `status codes` would be a nice to have in the future. Status codes are better than the `message` in a way considering there are so many reasons a transaction could fail.
e.g
e.g

```shell
1001: Success
4001: DuplicateTransaction
Expand All @@ -142,6 +155,9 @@ e.g
5001: GatewayError
5002: RejectedByGateway
```

Just an example!

### Contributions

- Highly welcome
21 changes: 10 additions & 11 deletions chapa.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"io"
"log"
"net/http"
"time"

"github.com/spf13/viper"
)
Expand All @@ -25,9 +24,9 @@ type API interface {
PaymentRequest(request *PaymentRequest) (*PaymentResponse, error)
Verify(txnRef string) (*VerifyResponse, error)
TransferToBank(request *BankTransfer) (*BankTransferResponse, error)
getTransactions() (*TransactionsResponse, error)
getBanks() (*BanksResponse, error)
bulkTransfer(*BulkTransferRequest) (*BulkTransferResponse, error)
GetTransactions() (*TransactionsResponse, error)
GetBanks() (*BanksResponse, error)
BulkTransfer(*BulkTransferRequest) (*BulkTransferResponse, error)
}

type chapa struct {
Expand All @@ -39,7 +38,7 @@ func New() API {
return &chapa{
apiKey: viper.GetString("API_KEY"),
client: &http.Client{
Timeout: 1 * time.Minute,
Timeout: viper.GetDuration("TIME_OUT"),
},
}
}
Expand All @@ -48,7 +47,7 @@ func (c *chapa) PaymentRequest(request *PaymentRequest) (*PaymentResponse, error
var err error
if err = request.Validate(); err != nil {
err := fmt.Errorf("invalid input %v", err)
log.Printf("error %v input %v", err.Error(), request)
log.Printf("warning %v input %v", err.Error(), request)
return &PaymentResponse{}, err
}

Expand Down Expand Up @@ -124,7 +123,7 @@ func (c *chapa) TransferToBank(request *BankTransfer) (*BankTransferResponse, er
var err error
if err = request.Validate(); err != nil {
err := fmt.Errorf("invalid input %v", err)
log.Printf("error %v input %v", err, request)
log.Printf("warning %v input %v", err, request)
return nil, err
}

Expand Down Expand Up @@ -166,7 +165,7 @@ func (c *chapa) TransferToBank(request *BankTransfer) (*BankTransferResponse, er
return &response, nil
}

func (c *chapa) getTransactions() (*TransactionsResponse, error) {
func (c *chapa) GetTransactions() (*TransactionsResponse, error) {
req, err := http.NewRequest(http.MethodGet, transactionsV1APIURL, nil)
if err != nil {
log.Printf("error %v", err)
Expand Down Expand Up @@ -198,7 +197,7 @@ func (c *chapa) getTransactions() (*TransactionsResponse, error) {
return &response, nil
}

func (c *chapa) getBanks() (*BanksResponse, error) {
func (c *chapa) GetBanks() (*BanksResponse, error) {
req, err := http.NewRequest(http.MethodGet, banksV1APIURL, nil)
if err != nil {
log.Printf("error %v", err)
Expand Down Expand Up @@ -230,11 +229,11 @@ func (c *chapa) getBanks() (*BanksResponse, error) {
return &response, nil
}

func (c *chapa) bulkTransfer(request *BulkTransferRequest) (*BulkTransferResponse, error) {
func (c *chapa) BulkTransfer(request *BulkTransferRequest) (*BulkTransferResponse, error) {
var err error
if err = request.Validate(); err != nil {
err := fmt.Errorf("invalid input %v", err)
log.Printf("error %v input %v", err, request)
log.Printf("warning %v input %v", err, request)
return nil, err
}

Expand Down
53 changes: 26 additions & 27 deletions chapa_example_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"log"
"sync"
"time"

"github.com/shopspring/decimal"
)

// Placeholder data
Expand All @@ -21,34 +23,34 @@ var (
Customers = []Customer{
{
ID: 1002,
FirstName: &firstName1,
LastName: &lastName1,
Email: &email1,
FirstName: firstName1,
LastName: lastName1,
Email: email1,
},
{
ID: 1032,
FirstName: &firstName2,
LastName: &lastName2,
Email: &email2,
FirstName: firstName2,
LastName: lastName2,
Email: email2,
},
}

transactions = []Transaction{
{
TransID: RandomString(10),
Amount: "10.00",
Amount: decimal.NewFromInt(10),
Charge: "0.35",
Currency: "ETB",
CreatedAt: time.Now().String(),
Customer: &Customers[0],
Customer: Customers[0],
},
{
TransID: RandomString(10),
Amount: "20.00",
Amount: decimal.NewFromInt(20),
Charge: "0.40",
Currency: "ETB",
CreatedAt: time.Now().String(),
Customer: &Customers[0],
Customer: Customers[0],
},
}
)
Expand All @@ -74,7 +76,7 @@ func NewExamplePaymentService(
}
}

func (s *AppExamplePaymentService) Checkout(ctx context.Context, CustomerID int64, form *CheckoutForm) (*Transaction, error) {
func (s *AppExamplePaymentService) Checkout(ctx context.Context, CustomerID int64, form CheckoutForm) (*Transaction, error) {

Customer, err := s.CustomerByID(ctx, CustomerID)
if err != nil {
Expand All @@ -84,9 +86,9 @@ func (s *AppExamplePaymentService) Checkout(ctx context.Context, CustomerID int6
invoice := &PaymentRequest{
Amount: form.Amount,
Currency: form.Currency,
Email: *Customer.Email,
FirstName: *Customer.FirstName,
LastName: *Customer.LastName,
Email: Customer.Email,
FirstName: Customer.FirstName,
LastName: Customer.LastName,
CallbackURL: "https://webhook.site/077164d6-29cb-40df-ba29-8a00e59a7e60",
TransactionRef: RandomString(10),
}
Expand All @@ -97,42 +99,39 @@ func (s *AppExamplePaymentService) Checkout(ctx context.Context, CustomerID int6
}

if response.Status != "success" {

// log the response
log.Printf("[ERROR] Failed to checkout Customer request response = [%+v]", response)

return &Transaction{}, fmt.Errorf("failed to checkout err = %v", response.Message)
}

transaction := Transaction{
TransID: invoice.TransactionRef,
Amount: fmt.Sprintf("%.2f", form.Amount),
Amount: form.Amount,
Currency: form.Currency,
Customer: Customer,
Status: PendingTransactionStatus,
CreatedAt: time.Now().String(),
}

err = s.saveTransaction(ctx, transaction)
err = s.SaveTransaction(ctx, transaction)
if err != nil {
return &Transaction{}, nil
return &Transaction{}, err
}

return &transaction, nil
}

func (s *AppExamplePaymentService) ListTransactions(ctx context.Context) (*TransactionList, error) {
func (s *AppExamplePaymentService) ListTransactions(_ context.Context) (TransactionList, error) {

// validations here

transactionList := &TransactionList{
transactionList := TransactionList{
Transactions: transactions,
}

return transactionList, nil
}

func (s *AppExamplePaymentService) saveTransaction(ctx context.Context, transaction Transaction) error {
func (s *AppExamplePaymentService) SaveTransaction(_ context.Context, transaction Transaction) error {

s.mu.Lock()
defer s.mu.Unlock()
Expand All @@ -142,14 +141,14 @@ func (s *AppExamplePaymentService) saveTransaction(ctx context.Context, transact
return nil
}

// CustomerByID - normally you'd fetch Customer from the db
func (s *AppExamplePaymentService) CustomerByID(ctx context.Context, CustomerID int64) (*Customer, error) {
// CustomerByID you'd fetch Customer from the db
func (s *AppExamplePaymentService) CustomerByID(_ context.Context, CustomerID int64) (Customer, error) {

for index := range Customers {
if Customers[index].ID == CustomerID {
return &Customers[index], nil
return Customers[index], nil
}
}

return &Customer{}, errors.New("Customer not found")
return Customer{}, errors.New("Customer not found")
}
Loading
Loading