Skip to content

Commit

Permalink
Merge pull request #1 from amenski/main
Browse files Browse the repository at this point in the history
  • Loading branch information
isrugeek authored Jun 5, 2024
2 parents adbd195 + 283cefd commit 26aab68
Show file tree
Hide file tree
Showing 151 changed files with 12,877 additions and 4,897 deletions.
226 changes: 135 additions & 91 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,77 +6,109 @@
`-----' `--' `--' `--`--' | |-' `--`--' `-----' `--`--' `--' `--`--'
```

[![BUILD](https://github.com/yaphet17/chapa-java/actions/workflows/maven.yml/badge.svg)](https://github.com/yaphet17/chapa-java/actions/workflows/maven.yml/) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.github.yaphet17/Chapa/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.github.yaphet17/Chapa) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
Unofficial Java package for Chapa Payment Gateway.

Unofficial Java SDK for Chapa Payment Gateway.

## What's new in this version
- You no longer need to deal with `JSON` or `Map<String, Object>` responses. You can just treat response data as a Java object using specific response classes for each request type (e.g. payment initialization, payment verification).
- Better exception handling. The SDK will throw the newly added `ChapaException` on failed requests to Chapa API.
- Bug fixes and design improvements.
- Well-tested and documented code. Check out the Javadoc [here](https://yaphet17.github.io/chapa-java/).
## Features
- You can now implement `IChapaClient` interface and create your own custom implementation
to use your favorite HTTP client.
- Includes split payment feature added by Chapa. You can now get list of supported banks, create
sub-account and perform a split payment. See [Split Payment](https://developer.chapa.co/docs/split-payment/) documentation for more details.
- Additional utility methods to help you to generate a convenient token for your transactions, to map json string
to `PostData` object etc.

## Table of Contents
1. [Documentation](#documentation)
2. [Installation](#installation)
3. [Usage](#usage)
4. [Javadoc](https://yaphet17.github.io/chapa-java/)
5. [Contribution](#contribution)
6. [Example](#example)
7. [License](#license)
4. [Contribution](#contribution)
5. [Example](#example)
6. [License](#license)

## Documentation
Visit official [Chapa's API Documentation](https://developer.chapa.co/docs)
## Installation
Add the below maven dependency to your `pom.xml` file.
```xml
<dependency>
<groupId>io.github.yaphet17</groupId>
<artifactId>Chapa</artifactId>
<version>1.2.2</version>
<groupId>com.github.amenski</groupId>
<artifactId>chapa</artifactId>
<version>1.0.0</version>
</dependency>
```
Or add the below gradle dependency to your `build.gradle` file.
```groovy
implementation 'io.github.yaphet17:Chapa:1.2.2'
implementation 'com.github.amenski:chapa:1.0.0'
```

## Usage

> **Note** : This doc might not fully cover chapa-api. Please refer to the chapa developer doc for more. And contributions are welcome too. Thanks.

Instantiate a `Chapa` class.
```java
Chapa chapa = new Chapa("your-secrete-key");
Chapa chapa = new Chapa.ChapaBuilder()
.client(new ChapaClient()) // --> default implementation
.secretKey("secret-key")
.build();
```
Or if you want to use your own implementation of `ChapaClient` interface.
Or if you want to use your own implementation, implement the methods from `IChapaClient` interface.
```java
Chapa chapa = new Chapa("your-secrete-key", new MyCustomChapaClient());
```
Note: `MyCustomChapaClient` must implement `ChapaClient` interface.
import com.github.amenski.client.ChapaClient;

public class MyCustomChapaClient implements IChapaClient {
...
}


To initialize a transaction, you can specify your information by either using our `PostData` class.
Chapa chapa = new Chapa(new MyCustomChapaClient(), "secrete-key");
```

Note: Starting from version 1.1.0 you have to specify customization fields as a `Map<String, String>` object.
## Retries (with ExponentialBackoff)
To add retries to clients, use `RetrierRetrofitClientProvider`. This class allows configuring 3 retries if a call fails.
Provides retrofit client to make calls to chapa api. <br>
Retry will be done with an <a href="https://en.wikipedia.org/wiki/Exponential_backoff">ExponentialBackoff</a> strategy.<br>
<pre>
Example usage:
public class CustomChapaClient implements IChapaClient {
private String baseUrl = "https://api.chapa.co/v1/";
private ChapaClientApi chapaClientApi;
.
.
private void buildApiClient() {
if (isBlank(baseUrl)) throw new ChapaException("Unable to create a client. Api baseUrl can't be empty");
chapaClientApi = new RetrierRetrofitClientProvider().buildClient(ChapaClientApi.class, baseUrl);
}
}
</pre>


To initialize a transaction, you simply need to specify your information by either using our `PostData` class.

```java
Customization customization = new Customization()
.setTitle("E-commerce")
.setDescription("It is time to pay")
.setLogo("https://mylogo.com/log.png");
.setTitle("E-commerce")
.setDescription("It is time to pay")
.setLogo("https://mylogo.com/log.png");
PostData postData = new PostData()
.setAmount(new BigDecimal("100"))
.setCurrency("ETB")
.setFirstName("Abebe")
.setLastName("Bikila")
.setEmail("abebe@bikila")
.setTxRef(Util.generateToken())
.setCallbackUrl("https://chapa.co")
.setReturnUrl("https://chapa.co")
.setSubAccountId("testSubAccountId")
.setCustomization(customization);
.setAmount(new BigDecimal("100"))
.setCurrency("ETB")
.setFirstName("Abebe")
.setLastName("Bikila")
.setEmail("abebe@bikila.com")
.setTxRef(UUID.randomUUID().toString())
.setCallbackUrl("https://chapa.co")
.setReturnUrl("https://chapa.co")
.setSubAccountId("testSubAccountId")
.setCustomization(customization);

...

chapa.initialize(postData);
```
Or, you can use a string JSON data.
Or, as a string JSON data.
```java
String formData = " { " +
String postDataString = " { " +
"'amount': '100', " +
"'currency': 'ETB'," +
"'email': 'abebe@bikila.com'," +
Expand All @@ -91,35 +123,34 @@ String formData = " { " +
" 'customization[logo]':'https://mylogo.com/log.png'" +
" }" +
" }";

chapa.initialize(postDataString)
```
Initialize payment
Intitialize payment
```java
InitializeResponseData responseData = chapa.initialize(postData);
// Get the response message
System.out.println(responseData.getMessage());
// Get the checkout URL from the response JSON
System.out.println(responseData.getData().getCheckOutUrl());
// Get the raw response JSON
System.out.println(responseData.getRawJson());
InitializeResponseData responseData = chapa.initialize(postData)
```
Verify payment
```java
// Get the verification response data
VerifyResponseData verifyResponseData = chapa.verify("tx-myecommerce12345");
VerifyResponseData actualResponseData = chapa.verify("tx-ref");
```
Get the list of banks
Get list of banks
```java
List<Bank> banks = chapa.getBanks();
```
To create a subaccount, you can specify your information by either using our `Subaccount` class.
```java
SubAccount subAccount = new SubAccount()
.setBusinessName("Abebe Suq")
.setAccountName("Abebe Bikila")
.setAccountNumber("0123456789")
.setBankCode("96e41186-29ba-4e30-b013-2ca36d7e7025")
.setSplitType(SplitType.PERCENTAGE)
.setSplitValue(0.2);
SubAccount subAccount = new SubAccountDto()
.setBusinessName("Abebe Suq")
.setAccountName("Abebe Bikila")
.setAccountNumber("0123456789")
.setBankCode("001")
.setSplitType(SplitTypeEnum.PERCENTAGE)
.setSplitValue(0.2);

...

SubAccountResponseData response = chapa.createSubAccount(subAccountDto);
```
Or, you can use a string JSON data.
```java
Expand All @@ -131,68 +162,81 @@ String subAccount = " { " +
"'split_type': 'percentage'," +
"'split_value': '0.2'" +
" }";

...

SubAccountResponseData actualResponse = chapa.createSubAccount(subAccount);
```
Create subaccount
```java
SubAccountResponseData subAccountResponseData = chapa.createSubAccount(subAccount);
// Get SubAccount id from the response JSOn
System.out.println(subAccountResponseData.getData().getSubAccountId());
SubAccountResponseData actualResponse = chapa.createSubAccount(subAccountDto);
```
## Example
```java
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
package com.github.amenski.chapa;

import com.github.amenski.Chapa;
import com.github.amenski.client.ChapaClient;
import com.github.amenski.ChapaException;
import com.github.amenski.model.Customization;
import com.github.amenski.model.PostData;
import com.github.amenski.model.ResponseBanks;
import com.github.amenski.model.SplitTypeEnum;
import com.github.amenski.model.SubAccountDto;

import io.github.yaphet17.chapa.Chapa;
import io.github.yaphet17.chapa.PostData;
import io.github.yaphet17.chapa.SubAccount;
import io.github.yaphet17.chapa.SplitType;
import io.github.yaphet17.chapa.Bank;
import java.math.BigDecimal;
import java.util.UUID;

public class ChapaExample {

public static void main(String[] args) {
Chapa chapa = new Chapa("your-secrete-key");

Customization customization = new Customization()
public static void main(String[] args) throws ChapaException {
Chapa chapa = new Chapa.ChapaBuilder()
.client(new ChapaClient())
.secretKey("CHASECK_TEST-...")
.build();

Customization customization = new Customization()
.setTitle("E-commerce")
.setDescription("It is time to pay")
.setLogo("https://mylogo.com/log.png");

PostData postData = new PostData()
PostData postData = new PostData()
.setAmount(new BigDecimal("100"))
.setCurrency("ETB")
.setFirstName("Abebe")
.setLastName("Bikila")
.setEmail("abebe@bikila")
.setTxRef(Util.generateToken())
.setEmail("abebe@bikila.com")
.setTxRef(UUID.randomUUID().toString())
.setCallbackUrl("https://chapa.co")
.setReturnUrl("https://chapa.co")
.setSubAccountId("testSubAccountId")
.setCustomization(customization);
SubAccount subAccount = new SubAccount()

SubAccountDto subAccountDto = new SubAccountDto()
.setBusinessName("Abebe Suq")
.setAccountName("Abebe Bikila")
.setAccountNumber("0123456789")
.setBankCode("96e41186-29ba-4e30-b013-2ca36d7e7025")
.setSplitType(SplitType.PERCENTAGE)
.setBankCode("853d0598-9c01-41ab-ac99-48eab4da1513")
.setSplitType(SplitTypeEnum.PERCENTAGE)
.setSplitValue(0.2);


InitializeResponseData responseData = chapa.initialize(postData);
VerifyResponseData verifyResponseData = chapa.verify("tx-myecommerce12345");
SubAccountResponseData subAccountResponseData = chapa.createSubAccount(subAccount);

}
}
// list of banks
ResponseBanks banks = chapa.getBanks();
if ((banks == null || banks.getData() == null)) {
System.out.println("Create SubAccount response: " + banks);
} else {
banks.getData().forEach(System.out::println);
}
// create subaccount
System.out.println("Create SubAccount response: " + chapa.createSubAccount(subAccountDto));
// initialize payment
System.out.println("Initialize response: " + chapa.initialize(postData));
// verify payment
System.out.println("Verify response: " + chapa.verify(postData.getTxRef()));
}
}
```
## Contribution
If you find any bugs or have any suggestions, please feel free to open an issue or pull request.
Please feel free to open an issue or pull request.

## License
This open-source library is licensed under the terms of the MIT License.

Enjoy!
MIT
41 changes: 41 additions & 0 deletions doc/allclasses-frame.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_392) on Mon Feb 05 08:31:18 CET 2024 -->
<title>All Classes</title>
<meta name="date" content="2024-02-05">
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="Style">
<script type="text/javascript" src="script.js"></script>
</head>
<body>
<h1 class="bar">All&nbsp;Classes</h1>
<div class="indexContainer">
<ul>
<li><a href="com/github/amenski/model/Bank.html" title="class in com.github.amenski.model" target="classFrame">Bank</a></li>
<li><a href="com/github/amenski/Chapa.html" title="class in com.github.amenski" target="classFrame">Chapa</a></li>
<li><a href="com/github/amenski/Chapa.ChapaBuilder.html" title="class in com.github.amenski" target="classFrame">Chapa.ChapaBuilder</a></li>
<li><a href="com/github/amenski/client/ChapaClient.html" title="class in com.github.amenski.client" target="classFrame">ChapaClient</a></li>
<li><a href="com/github/amenski/client/ChapaClientApi.html" title="interface in com.github.amenski.client" target="classFrame"><span class="interfaceName">ChapaClientApi</span></a></li>
<li><a href="com/github/amenski/exception/ChapaException.html" title="class in com.github.amenski.exception" target="classFrame">ChapaException</a></li>
<li><a href="com/github/amenski/model/Customization.html" title="class in com.github.amenski.model" target="classFrame">Customization</a></li>
<li><a href="com/github/amenski/client/provider/DefaultRetrofitClientProvider.html" title="class in com.github.amenski.client.provider" target="classFrame">DefaultRetrofitClientProvider</a></li>
<li><a href="com/github/amenski/client/IChapaClient.html" title="interface in com.github.amenski.client" target="classFrame"><span class="interfaceName">IChapaClient</span></a></li>
<li><a href="com/github/amenski/model/InitializeResponseData.html" title="class in com.github.amenski.model" target="classFrame">InitializeResponseData</a></li>
<li><a href="com/github/amenski/model/InitializeResponseData.Data.html" title="class in com.github.amenski.model" target="classFrame">InitializeResponseData.Data</a></li>
<li><a href="com/github/amenski/utility/LocalDateTimeDeserializer.html" title="class in com.github.amenski.utility" target="classFrame">LocalDateTimeDeserializer</a></li>
<li><a href="com/github/amenski/model/PostData.html" title="class in com.github.amenski.model" target="classFrame">PostData</a></li>
<li><a href="com/github/amenski/model/ResponseBanks.html" title="class in com.github.amenski.model" target="classFrame">ResponseBanks</a></li>
<li><a href="com/github/amenski/model/ResponseData.html" title="class in com.github.amenski.model" target="classFrame">ResponseData</a></li>
<li><a href="com/github/amenski/client/provider/RetrierRetrofitClientProvider.html" title="class in com.github.amenski.client.provider" target="classFrame">RetrierRetrofitClientProvider</a></li>
<li><a href="com/github/amenski/client/provider/RetrofitClientProvider.html" title="interface in com.github.amenski.client.provider" target="classFrame"><span class="interfaceName">RetrofitClientProvider</span></a></li>
<li><a href="com/github/amenski/model/SplitTypeEnum.html" title="enum in com.github.amenski.model" target="classFrame">SplitTypeEnum</a></li>
<li><a href="com/github/amenski/utility/StringUtils.html" title="class in com.github.amenski.utility" target="classFrame">StringUtils</a></li>
<li><a href="com/github/amenski/model/SubAccountDto.html" title="class in com.github.amenski.model" target="classFrame">SubAccountDto</a></li>
<li><a href="com/github/amenski/model/SubAccountResponseData.html" title="class in com.github.amenski.model" target="classFrame">SubAccountResponseData</a></li>
<li><a href="com/github/amenski/utility/Util.html" title="class in com.github.amenski.utility" target="classFrame">Util</a></li>
<li><a href="com/github/amenski/model/VerifyResponseData.html" title="class in com.github.amenski.model" target="classFrame">VerifyResponseData</a></li>
</ul>
</div>
</body>
</html>
Loading

0 comments on commit 26aab68

Please sign in to comment.