diff --git a/.travis.yml b/.travis.yml
index cd6ad7b..11364b7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,10 +11,6 @@ matrix:
- jdk: openjdk10
- jdk: oraclejdk11
- jdk: openjdk11
- - jdk: oraclejdk-ea
- - jdk: openjdk-ea
- allow_failures:
- - jdk: oraclejdk-ea
- jdk: openjdk-ea
notifications:
diff --git a/AUTHORS.md b/AUTHORS.md
new file mode 100644
index 0000000..e390f12
--- /dev/null
+++ b/AUTHORS.md
@@ -0,0 +1,7 @@
+Authors
+=======
+
+* Moses Mugisha
+* Ray Besiga
+
+For [Sparkplug](http://sparkpl.ug)
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..2d83f26
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,8 @@
+
+Changelog
+=========
+
+0.1.0 (2018-10-29)
+------------------
+
+* First release on Maven
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..333c768
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,177 @@
+# Contributing
+
+First off, thank you for considering contributing to this Python MTN MoMo Library. It's people like you that make it such a great tool. Contributions are welcome, and they are greatly appreciated!
+
+## Where do I go from here?
+
+If you've noticed a bug or have a question that doesn't belong on the
+[Spectrum](https://spectrum.chat/momo-api-developers/) or [Stack Overflow](https://stackoverflow.com/), [search the issue tracker](https://github.com/sparkplug/momoapi-java/issues) to see if
+someone else in the community has already created a ticket. If not, go ahead and
+[make one](https://github.com/sparkplug/momoapi-java/issues/new/choose)!
+
+
+
+## Fork & create a branch
+
+If there is something you think you can fix, then fork the [repo](https://github.com/sparkplug/momoapi-java) and create a branch with a descriptive name.
+
+A good branch name would be (where issue #32 is the ticket you're working on):
+
+```sh
+git checkout -b 32-add-swahili-translations
+```
+
+## Get the test suite running
+
+This library has a comprehensive test suite, which can be run using the `tox` command:
+
+To view all test environments
+
+```sh
+$ ./gradlew test
+```
+
+## Bugs and Fixes
+
+### Did you find a bug?
+
+* **Ensure the bug was not already reported** by [searching all issues](https://github.com/sparkplug/momoapi-java/issues).
+
+* If you're unable to find an open issue addressing the problem,
+ [open a new one](https://github.com/sparkplug/momoapi-java/issues/new/choose). Be sure to include a **title and clear
+ description**, as much relevant information as possible, and a **code sample**
+ or an **executable test case** demonstrating the expected behavior that is not
+ occurring.
+
+* If possible, use the relevant bug report templates to create the issue.
+ Make the necessary changes to demonstrate the issue, and **paste the content into the
+ issue description**
+
+### Implement your fix or feature
+
+At this point, you're ready to make your changes! Feel free to ask for help;
+everyone is a beginner at first :smile_cat:
+
+If you are proposing a feature:
+
+* Explain in detail how it would work.
+* Keep the scope as narrow as possible, to make it easier to implement.
+* Remember that this is a volunteer-driven project, and that code contributions are welcome :)
+
+If you would like to send us feedback, simply [file an issue](https://github.com/sparkplug/momoapi-python/issues/new/choose).
+
+## Local Development
+
+To set up `momoapi-java` for local development:
+
+1. Fork the repo. Look for the "Fork" button in the Github UI.
+2. Clone your fork locally:
+
+```sh
+git clone https://github.com/your_name_here/momoapi-java.git
+```
+
+3. Create a branch for local development:
+```sh
+git checkout -b name-of-your-bugfix-or-feature
+```
+
+Now you can make your changes locally.
+
+4. When you're done making changes, run all the checks, doc builder and spell checker with `tox`.
+```sh
+tox
+```
+Make sure Tox is installed by following the instructions [here](http://tox.readthedocs.io/en/latest/install.html)
+
+5. Commit your changes and push your branch to GitHub::
+
+```sh
+git add .
+git commit -m "Your detailed description of your changes."
+git push origin name-of-your-bugfix-or-feature
+```
+
+6. Submit a pull request through the GitHub website.
+
+## Pull Request Guidelines
+
+### Make a Pull Request
+
+At this point, you should switch back to your master branch and make sure it's
+up to date with `momoapi-java`'s master branch:
+
+```sh
+git remote add upstream https://github.com/sparkplug/momoapi-java.git
+git checkout master
+git pull upstream master
+```
+
+Then update your feature branch from your local copy of master, and push it!
+
+```sh
+git checkout 32-add-swahili-translations
+git rebase master
+git push --set-upstream origin 32-add-swahili-translations
+```
+
+Finally, go to GitHub and make a Pull Request :D
+
+TravisCI will run our test suite against all supported Python versions. We care
+about quality, so your PR won't be merged until all tests pass. It's unlikely,
+but it's possible that your changes pass tests in one Python version but fail in
+another. In that case, you'll have to setup your development environment to use your Python version, and investigate what's going on!
+
+### Keeping your Pull Request updated
+
+If a maintainer asks you to "rebase" your PR, they're saying that a lot of code has changed, and that you need to update your branch so it's easier to merge.
+
+To learn more about rebasing in Git, there are a lot of [good](https://www.atlassian.com/git/tutorials/rewriting-history/git-rebase) [resources](https://git-scm.com/book/en/v2/Git-Branching-Rebasing) but here's the suggested workflow:
+
+```sh
+git checkout 32-add-swahili-translations
+git pull --rebase upstream master
+git push --force-with-lease 32-add-swahili-translations
+```
+
+### Merging a PR (maintainers only)
+
+A PR can only be merged into master by a maintainer if:
+
+* It is passing CI.
+* It has been approved by at least one maintainers. If it was a maintainer who opened the PR, only one extra approval is needed.
+* It has no requested changes.
+* It is up to date with current master.
+
+Any maintainer is allowed to merge a PR if all of these conditions are met.
+
+### Shipping a release (maintainers only)
+
+Maintainers need to do the following to push out a release:
+
+* Make sure all pull requests are in and that changelog is current
+* Update version and changelog with new version number using semver
+* If it's not a patch level release, create a stable branch for that release,
+ otherwise switch to the stable branch corresponding to the patch release you
+ want to ship:
+
+ ```sh
+ git checkout master
+ git fetch momoapi-java
+ git rebase momoapi-java/master
+ # If the release is 2.1.x then this should be: 2-1-stable
+ git checkout -b N-N-stable
+ git push momoapi-java N-N-stable:N-N-stable
+ ```
+
+Before you make a Pull Request, make sure of the following:
+
+1. Make sure your tests pass. Run `tox` beforehand.
+2. Update documentation where necessary.
+3. Note changes to `CHANGELOG.md`.
+4. Add yourself to `AUTHORS.md`.
+
+## Improvements
+
+This library could always use more documentation, whether as part of the official docs, in docstrings, or even in blog posts and articles. We look forward to add them to our RESOURCES file.
+
diff --git a/README.md b/README.md
index 4edcc65..3e99f1c 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,250 @@
-# momoapi-java
-MTN MoMo API Client for Java
+# MTN MoMo API Java Client
+
+**🛑 This repository is no longer actively maintained.**
+
+As of July 14, 2025, this project is no longer under active development. This means:
+* No new features will be added.
+* Bugs will not be fixed.
+* Pull requests will not be reviewed or merged.
+* Issues will not be addressed.
+
+We appreciate your interest and contributions.
+**Thank you.**
+
+
+
+Power your apps with our MTN MoMo API
+
+
+
+
+[](https://travis-ci.com/sparkplug/momoapi-java)
+[](https://coveralls.io/github/sparkplug/momoapi-java?branch=master)
+[](https://spectrum.chat/momo-api-developers/)
+
+## Requirements
+
+Java 1.8 or later.
+
+## Installation
+
+### Maven users
+
+Add this dependency to your project's POM:
+
+```xml
+
+ ug.sparkpl
+ mtnmomo-java
+ 1.2.0
+
+```
+
+### Gradle users
+
+Add this dependency to your project's build file:
+
+```groovy
+compile "ug.sparkpl:mtnmomo-java:1.2.0"
+```
+
+# Sandbox Environment
+
+## Creating a sandbox environment API user
+
+Next, we need to get the `User ID` and `User Secret` and to do this we shall need to use the Primary Key for the Product to which we are subscribed, as well as specify a host. The library ships with a commandline application that helps to create sandbox credentials. It assumes you have created an account on `https://momodeveloper.mtn.com` and have your `Ocp-Apim-Subscription-Key`.
+
+```bash
+## within the project, on the command line. In this example, our domain is akabbo.ug
+$ ./gradlew provisionUser --args='-Ocp-Apim-Subscription-Key --providerCallBackHost akabbo.ug'
+```
+
+The `providerCallBackHost` is your callback host and `Ocp-Apim-Subscription-Key` is your API key for the specific product to which you are subscribed. The `API Key` is unique to the product and you will need an `API Key` for each product you use. You should get a response similar to the following:
+
+```bash
+ {'apiKey': 'b0431db58a9b41faa8f5860230xxxxxx', 'UserId': '053c6dea-dd68-xxxx-xxxx-c830dac9f401'}
+```
+
+These are the credentials we shall use for the sandbox environment. In production, these credentials are provided for you on the MTN OVA management dashboard after KYC requirements are met.
+
+
+## Configuration
+
+Before we can fully utilize the library, we need to specify global configurations. The global configuration using the requestOpts builder. By default, these are picked from environment variables,
+but can be overidden using the RequestOpts builder
+
+* `BASE_URL`: An optional base url to the MTN Momo API. By default the staging base url will be used
+* `ENVIRONMENT`: Optional enviroment, either "sandbox" or "production". Default is 'sandbox'
+* `CURRENCY`: currency by default its EUR
+* `CALLBACK_HOST`: The domain where you webhooks urls are hosted. This is mandatory.
+* `COLLECTION_PRIMARY_KEY`: The collections API primary key,
+* `COLLECTION_USER_ID`: The collection User Id
+* `COLLECTION_API_SECRET`: The Collection API secret
+* `REMITTANCE_USER_ID`: The Remittance User ID
+* `REMITTANCE_API_SECRET`: The Remittance API Secret
+* `REMITTANCE_PRIMARY_KEY`: The Remittance Subscription Key
+* `DISBURSEMENT_USER_ID`: The Disbursement User ID
+* `DISBURSEMENT_API_SECRET`: The Disbursement API Secret
+* `DISBURSEMENT_PRIMARY_KEY`: The Disbursement Primary Key
+
+Once you have specified the global variables, you can now provide the product-specific variables. Each MoMo API product requires its own authentication details i.e its own `Subscription Key`, `User ID` and `User Secret`, also sometimes refered to as the `API Secret`. As such, we have to configure subscription keys for each product you will be using.
+
+You will only need to configure the variables for the product(s) you will be using.
+
+### Per-request Configuration
+
+``` java
+
+ RequestOptions opts = RequestOptions.builder()
+ .setCollectionApiSecret("MY_SECRET_API_KEY")
+ .setCollectionPrimaryKey("MY_SECRET_SUBSCRIPTION_KEY")
+ .setCollectionUserId("MYSECRET_USER_ID")
+ .setBaseUrl("NEW_BASE_URL") // Override the default base url
+ .setCurrency("UGX") // Override default currency
+ .setTargetEnvironment("env") // Override default target environment
+ build();
+
+```
+
+
+## Collections
+
+The collections client can be created with the following paramaters. Note that the `COLLECTION_USER_ID` and `COLLECTION_API_SECRET` for production are provided on the MTN OVA dashboard.
+
+* `COLLECTION_PRIMARY_KEY`: Primary Key for the `Collection` product on the developer portal.
+* `COLLECTION_USER_ID`: For sandbox, use the one generated with the `mtnmomo` command.
+* `COLLECTION_API_SECRET`: For sandbox, use the one generated with the `mtnmomo` command.
+
+
+MomoCollectionsExample.java
+
+```java
+import java.util.HashMap;
+import java.util.Map;
+
+import ug.sparkpl.momoapi.network.RequestOptions;
+import ug.sparkpl.momoapi.network.collections.CollectionsClient;
+
+
+public class MomoCollectionsExample {
+
+ public static void main(String[] args) {
+
+ // Make a request to pay call
+ RequestOptions opts = RequestOptions.builder()
+ .setCollectionApiSecret("MY_SECRET_API_KEY")
+ .setCollectionPrimaryKey("MY_SECRET_SUBSCRIPTION_KEY")
+ .setCollectionUserId("MYSECRET_USER_ID").build();
+
+ HashMap collMap = new HashMap();
+ collMap.put("amount", "100");
+ collMap.put("mobile", "1234");
+ collMap.put("externalId", "ext123");
+ collMap.put("payeeNote", "testNote");
+ collMap.put("payerMessage", "testMessage");
+
+ CollectionsClient client = new CollectionsClient(opts);
+
+ try {
+ String transactionRef = client.requestToPay(collMap);
+ System.out.println(transactionRef);
+ } catch (MomoApiException e) {
+ e.printStackTrace();
+ }
+ }
+}
+```
+
+### Methods
+
+1. `requestToPay`: This operation is used to request a payment from a consumer (Payer). The payer will be asked to authorize the payment. The transaction is executed once the payer has authorized the payment. The transaction will be in status PENDING until it is authorized or declined by the payer or it is timed out by the system. Status of the transaction can be validated by using `getTransactionStatus`.
+
+2. `getTransaction`: Retrieve transaction information using the `transactionId` returned by `requestToPay`. You can invoke it at intervals until the transaction fails or succeeds. If the transaction has failed, it will throw an appropriate error.
+
+3. `getBalance`: Get the balance of the account.
+
+4. `isPayerActive`: check if an account holder is registered and active in the system.
+
+
+## Disbursement
+
+The Disbursements client can be created with the following paramaters. Note that the `DISBURSEMENT_USER_ID` and `DISBURSEMENT_API_SECRET` for production are provided on the MTN OVA dashboard;
+
+* `DISBURSEMENT_PRIMARY_KEY`: Primary Key for the `Disbursement` product on the developer portal.
+* `DISBURSEMENT_USER_ID`: For sandbox, use the one generated with the `mtnmomo` command.
+* `DISBURSEMENT_API_SECRET`: For sandbox, use the one generated with the `mtnmomo` command.
+
+Making a disbursements request
+
+MomoDisbursementsExample.java
+
+```java
+import java.util.HashMap;
+import java.util.Map;
+
+import ug.sparkpl.momoapi.network.RequestOptions;
+import ug.sparkpl.momoapi.network.disbursements.DisbursementsClient;
+
+
+public class MomoDisbursementsExample {
+
+ public static void main(String[] args) {
+
+ // Make a request to pay call
+ RequestOptions opts = RequestOptions.builder()
+ .setDisbursementApiSecret("MY_SECRET_API_KEY")
+ .setDisbursementPrimaryKey("MY_SECRET_SUBSCRIPTION_KEY")
+ .setDisbursementUserId("MYSECRET_USER_ID").build();
+
+
+ HashMap collMap = new HashMap();
+ collMap.put("amount", "100");
+ collMap.put("mobile", "1234");
+ collMap.put("externalId", "ext123");
+ collMap.put("payeeNote", "testNote");
+ collMap.put("payerMessage", "testMessage");
+
+ DisbursementsClient client = new DisbursementsClient(opts);
+
+ try {
+ String transactionRef = client.transfer(collMap);
+ System.out.println(transactionRef);
+ } catch (MomoApiException e) {
+ e.printStackTrace();
+ }
+ }
+}
+```
+
+### Methods
+
+1. `transfer`: Used to transfer an amount from the owner’s account to a payee account. Status of the transaction can be validated by using the `getTransactionStatus` method.
+
+2. `getTransaction`: Retrieve transaction information using the `transactionId` returned by `transfer`. You can invoke it at intervals until the transaction fails or succeeds.
+
+2. `getBalance`: Get your account balance.
+
+3. `isPayerActive`: This method is used to check if an account holder is registered and active in the system.
+
+
+
+## Development
+
+You must have Gradle installed. To run the tests:
+
+```bash
+ ./gradlew test
+```
+
+The library uses [Project Lombok][lombok]. While it is not a requirement, you might want to install a [plugin][lombok-plugins] for your favorite IDE to facilitate development.
+
+[lombok]: https://projectlombok.org
+[lombok-plugins]: https://projectlombok.org/setup/overview
+
+# Thank you.
diff --git a/build.gradle b/build.gradle
index 6d647ec..af7256d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -40,6 +40,9 @@ repositories {
apply plugin: 'io.codearte.nexus-staging'
+apply plugin: 'maven-publish'
+apply plugin: 'signing'
+
sourceCompatibility = 1.8
targetCompatibility = 1.8
@@ -76,6 +79,10 @@ dependencies {
compile group: 'com.google.code.gson', name: 'gson', version: '2.3.1'
compile group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.0'
+ compile group: 'commons-cli', name: 'commons-cli', version: '1.4'
+
+ compile group: 'org.gradle', name: 'api', version: '1.0'
+
// This dependency is used internally, and not exposed to consumers on their own compile classpath.
implementation 'com.google.guava:guava:26.0-jre'
@@ -92,6 +99,7 @@ dependencies {
testImplementation 'com.squareup.okhttp3:mockwebserver:3.12.1'
testCompile("org.apache.jclouds:jclouds-core:2.0.2:tests")
testCompile("org.apache.jclouds.driver:jclouds-slf4j:2.0.2")
+ testCompile('org.testng:testng:6.11')
testCompile('org.assertj:assertj-core:3.8.0')
compile "org.apache.jclouds:jclouds-core:2.0.2"
}
@@ -139,7 +147,9 @@ javadoc {
}
-apply from: 'deploy.gradle'
+if (project.hasProperty("signing.keyId")) {
+ apply from: 'deploy.gradle'
+}
test {
useJUnitPlatform()
@@ -149,7 +159,8 @@ test {
}
}
-task testRun(type: JavaExec) {
+task provisionUser(type: JavaExec) {
+ standardInput = System.in
classpath sourceSets.main.runtimeClasspath
main = "ug.sparkpl.momoapi.MomoApi"
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
index 9c69b6f..22e1957 100644
--- a/config/checkstyle/checkstyle.xml
+++ b/config/checkstyle/checkstyle.xml
@@ -124,11 +124,7 @@
-
-
-
-
+
-
-
-
-
-
-
-
-
-
+
- uploadArchives {
- repositories {
- mavenDeployer {
- beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
-
- pom.groupId = GROUP
- pom.artifactId = POM_ARTIFACT_ID
- pom.version = VERSION_NAME
+ signing {
+ sign configurations.archives
+ }
- repository(url: getReleaseRepositoryUrl()) {
- authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
- }
- snapshotRepository(url: getSnapshotRepositoryUrl()) {
- authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
+publishing {
+ publications {
+ mavenJava(MavenPublication) {
+ customizePom(pom)
+ groupId 'ug.sparkpl'
+ artifactId 'mtnmomo-java'
+ version '1.0.0'
+
+ from components.java
+
+ // create the sign pom artifact
+ pom.withXml {
+ def pomFile = file("${project.buildDir}/generated-pom.xml")
+ writeTo(pomFile)
+ def pomAscFile = signing.sign(pomFile).signatureFiles[0]
+ artifact(pomAscFile) {
+ classifier = null
+ extension = 'pom.asc'
}
+ }
- pom.project {
- name POM_NAME
- description POM_DESCRIPTION
- url POM_URL
- packaging POM_PACKAGING
-
- scm {
- url POM_SCM_URL
- connection POM_SCM_CONNECTION
- developerConnection POM_SCM_DEV_CONNECTION
- }
-
- licenses {
- license {
- name POM_LICENCE_NAME
- url POM_LICENCE_URL
- distribution POM_LICENCE_DIST
- }
- }
-
- developers {
- developer {
- id POM_DEVELOPER_ID
- name POM_DEVELOPER_NAME
- email POM_DEVELOPER_EMAIL
- }
- }
+ artifact(sourceJar) {
+ classifier = 'sources'
+ }
+ artifact(javadocJar) {
+ classifier = 'javadoc'
+ }
- organization {
- name POM_DEVELOPER_NAME
- url POM_ORGANIZATION_URL
+ // create the signed artifacts
+ project.tasks.signArchives.signatureFiles.each {
+ artifact(it) {
+ def matcher = it.file =~ /-(sources|javadoc)\.jar\.asc$/
+ if (matcher.find()) {
+ classifier = matcher.group(1)
+ } else {
+ classifier = null
}
+ extension = 'jar.asc'
}
}
}
}
-
- signing {
- required { isReleaseBuild() &&
- (gradle.taskGraph.hasTask("uploadArchives") || gradle.taskGraph.hasTask("publish"))}
- useGpgCmd()
- sign configurations.archives
+ repositories {
+ maven {
+ url "https://oss.sonatype.org/service/local/staging/deploy/maven2"
+ credentials {
+ username hasProperty('sonatypeUsername') ? sonatypeUsername : System.getenv('sonatypeUsername')
+ password hasProperty('sonatypePassword') ? sonatypePassword : System.getenv('sonatypePassword')
+ }
+ }
}
+}
- tasks.withType(Sign) {
- onlyIf { isReleaseBuild() && project.hasProperty('signing.gnupg.keyName') }
- }
+def customizePom(pom) {
+ pom.withXml {
+ def root = asNode()
- task makeJavadocs(type: Javadoc, dependsOn: delombok) {
- source = delombok.outputDir
- classpath = configurations.compile + configurations.annotationProcessor
- failOnError = true
- }
+ // eliminate test-scoped dependencies (no need in maven central POMs)
+ root.dependencies.removeAll { dep ->
+ dep.scope == "test"
+ }
- task makeJavadocsJar(type: Jar, dependsOn: makeJavadocs) {
- classifier = 'javadoc'
- from makeJavadocs.destinationDir
- }
+ // add all items necessary for maven central publication
+ root.children().last() + {
+ resolveStrategy = Closure.DELEGATE_FIRST
- task sourcesJar(type: Jar, dependsOn: delombok) {
- classifier = 'sources'
- from delombok.outputDir
+ description 'MTN MOMO Java Bindings'
+ name 'https://momodeveloper.mtn.com/ Java'
+ url 'https://github.com/sparkplug/momoapi-java'
+ organization {
+ name 'ug.sparkpl'
+ url 'https://sparkpl.ug'
+ }
+ issueManagement {
+ system 'GitHub'
+ url 'https://github.com/sparkplug/momoapi-java/issues'
+ }
+ licenses {
+ license {
+ name 'The MIT License'
+ url 'https://raw.githubusercontent.com/sparkplug/momoapi-java/master/LICENSE'
+ distribution 'repo'
+ }
+ }
+ scm {
+ url 'https://github.com/sparkplug/momoapi-java'
+ connection 'scm:git@github.com/sparkplug/momoapi-java.git'
+ developerConnection 'scm:git:ssh://git@github.com:sparkplug/momoapi-java.git'
+ }
+ developers {
+ developer {
+ name 'Sparkplug'
+ }
+ }
+ }
}
+}
- artifacts {
- archives jar
- archives sourcesJar
- archives makeJavadocsJar
+model {
+ tasks.generatePomFileForMavenJavaPublication {
+ destination = file("$buildDir/generated-pom.xml")
+ }
+ tasks.publishMavenJavaPublicationToMavenLocal {
+ dependsOn project.tasks.signArchives
+ }
+ tasks.publishMavenJavaPublicationToMavenRepository {
+ dependsOn project.tasks.signArchives
}
}
\ No newline at end of file
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..0f8d593
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/lombok.config b/lombok.config
index cac7bd5..27a6257 100644
--- a/lombok.config
+++ b/lombok.config
@@ -1 +1,2 @@
-lombok.addGeneratedAnnotation = false
\ No newline at end of file
+lombok.getter.noIsPrefix = true
+lombok.addLombokGeneratedAnnotation = true
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index 3a2e3a9..895474f 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -7,4 +7,4 @@
* in the user guide at https://docs.gradle.org/5.1/userguide/multi_project_builds.html
*/
-rootProject.name = 'momoapi-java'
+rootProject.name = 'mtnmomo-java'
diff --git a/src/main/java/ug/sparkpl/momoapi/ImproperlyConfiguredException.java b/src/main/java/ug/sparkpl/momoapi/ImproperlyConfiguredException.java
index 90d5805..46ee94d 100644
--- a/src/main/java/ug/sparkpl/momoapi/ImproperlyConfiguredException.java
+++ b/src/main/java/ug/sparkpl/momoapi/ImproperlyConfiguredException.java
@@ -1,10 +1,15 @@
package ug.sparkpl.momoapi;
-public class ImproperlyConfiguredException extends Exception {
+public class ImproperlyConfiguredException extends Exception {
+ /**
+ * ImproperlyConfiguredException.
+ *
+ * @param errorMessage String
+ */
+ public ImproperlyConfiguredException(String errorMessage) {
- public ImproperlyConfiguredException(String errorMessage) {
- super(errorMessage);
- }
+ super(errorMessage);
+ }
}
diff --git a/src/main/java/ug/sparkpl/momoapi/MomoApi.java b/src/main/java/ug/sparkpl/momoapi/MomoApi.java
index 26646ae..9e3ebec 100644
--- a/src/main/java/ug/sparkpl/momoapi/MomoApi.java
+++ b/src/main/java/ug/sparkpl/momoapi/MomoApi.java
@@ -1,42 +1,54 @@
package ug.sparkpl.momoapi;
-
-import ug.sparkpl.momoapi.models.Balance;
-import ug.sparkpl.momoapi.network.RequestOptions;
-import ug.sparkpl.momoapi.network.disbursements.DisbursementsClient;
-import ug.sparkpl.momoapi.network.remittances.RemittancesClient;
-
import java.io.IOException;
+import java.util.HashMap;
-public class MomoApi {
-
- MomoApi() {
+import ug.sparkpl.momoapi.network.MomoApiException;
+import ug.sparkpl.momoapi.network.RequestOptions;
+import ug.sparkpl.momoapi.network.collections.CollectionsClient;
- }
+import org.apache.commons.cli.ParseException;
- public static void main(String[] args) {
- RequestOptions opts = RequestOptions.builder().build();
- DisbursementsClient client = new DisbursementsClient(opts);
+public class MomoApi {
- RemittancesClient rclient = new RemittancesClient(opts);
+ MomoApi() {
- try {
- Balance bl = rclient.getBalance();
- System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&");
+ }
- System.out.println(bl.getBalance());
+ /**
+ * Provision Sandbox Account.
+ *
+ * @param args providerCallBackHost and primaryKey(Ocp-Apim-Subscription-Key)
+ * @throws ParseException when args are missing
+ * @throws IOException when network error occurs
+ */
+ public static void main(String[] args) throws ParseException, IOException {
- } catch (IOException e) {
- System.out.println(e.toString());
+ // Make a request to pay call
+ RequestOptions opts = RequestOptions.builder()
+ .build();
- }
+ HashMap collMap = new HashMap();
+ collMap.put("amount", "100");
+ collMap.put("mobile", "0782123456");
+ collMap.put("externalId", "ext123");
+ collMap.put("payeeNote", "testNote");
+ collMap.put("payerMessage", "testMessage");
+ CollectionsClient client = new CollectionsClient(opts);
+ try {
+ String transactionRef = client.requestToPay(collMap);
+ System.out.println(transactionRef);
+ } catch (MomoApiException e) {
+ e.printStackTrace();
}
+ }
+
}
diff --git a/src/main/java/ug/sparkpl/momoapi/Utils/DateTimeTypeConverter.java b/src/main/java/ug/sparkpl/momoapi/Utils/DateTimeTypeConverter.java
deleted file mode 100644
index 9852c3e..0000000
--- a/src/main/java/ug/sparkpl/momoapi/Utils/DateTimeTypeConverter.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package ug.sparkpl.momoapi.Utils;
-
-
-import com.google.gson.*;
-import lombok.NonNull;
-import org.joda.time.DateTime;
-
-import java.lang.reflect.Type;
-
-public class DateTimeTypeConverter implements JsonSerializer, JsonDeserializer {
- @Override
- public JsonElement serialize(final @NonNull DateTime src, final @NonNull Type srcType,
- final @NonNull JsonSerializationContext context) {
- return new JsonPrimitive(src.getMillis() / 1000);
- }
-
- @Override
- public DateTime deserialize(final @NonNull JsonElement json, final @NonNull Type type,
- final @NonNull JsonDeserializationContext context) {
- return new DateTime(json.getAsInt() * 1000L);
- }
-}
diff --git a/src/main/java/ug/sparkpl/momoapi/Utils/Utils.java b/src/main/java/ug/sparkpl/momoapi/Utils/Utils.java
deleted file mode 100644
index bf99ffa..0000000
--- a/src/main/java/ug/sparkpl/momoapi/Utils/Utils.java
+++ /dev/null
@@ -1,167 +0,0 @@
-package ug.sparkpl.momoapi.Utils;
-
-
-import com.google.gson.Gson;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonSyntaxException;
-import lombok.NonNull;
-import retrofit2.HttpException;
-import retrofit2.Response;
-import ug.sparkpl.momoapi.models.MomoApiError;
-
-import javax.annotation.Nullable;
-
-
-public class Utils {
-
- private Utils() {
- }
-
- public static boolean isNull(final @Nullable Object object) {
- return object == null;
- }
-
- public static boolean isNotNull(final @Nullable Object object) {
- return object != null;
- }
-
- /**
- * Returns the first non-`null` value of its arguments.
- */
- @NonNull
- public static T coalesce(final @Nullable T value, final @NonNull T theDefault) {
- if (value != null) {
- return value;
- }
- return theDefault;
- }
-
- /**
- * Converts a {@link String} to a {@link Boolean}, or null if the boolean cannot be parsed.
- */
- public static @Nullable
- Boolean toBoolean(final @Nullable String s) {
- if (s != null) {
- return Boolean.parseBoolean(s);
- }
-
- return null;
- }
-
- /**
- * Converts a {@link String} to an {@link Integer}, or null if the integer cannot be parsed.
- */
- public static @Nullable
- Integer toInteger(final @Nullable String s) {
- if (s != null) {
- try {
- return Integer.parseInt(s);
- } catch (final @NonNull NumberFormatException e) {
- return null;
- }
- }
-
- return null;
- }
-
- /**
- * Converts an {@link Integer} to a {@link String}, can be null if the integer is also null.
- */
- public static @Nullable
- String toString(final @Nullable Integer n) {
- if (n != null) {
- return Integer.toString(n);
- }
-
- return null;
- }
-
- /**
- * Converts a {@link Long} to a {@link String}, can be null if the long is also null.
- */
- public static @Nullable
- String toString(final @Nullable Long n) {
- if (n != null) {
- return Long.toString(n);
- }
-
- return null;
- }
-
- /**
- * Converts a {@link Float} to a {@link String}, can be null if the float is also null.
- */
- public static @Nullable
- String toString(final @Nullable Float n) {
- if (n != null) {
- return Float.toString(n);
- }
-
- return null;
- }
-
- /**
- * Converts a {@link Double} to a {@link String}, can be null if the double is also null.
- */
- public static @Nullable
- String toString(final @Nullable Double n) {
- if (n != null) {
- return Double.toString(n);
- }
-
- return null;
- }
-
- /**
- * Cast a `null`able value into a non-`null` value, and throw a `NullPointerException` if the value is `null`.
- */
- public static @NonNull
- T requireNonNull(final @Nullable T value) throws NullPointerException {
- return requireNonNull(value, "Value should not be null.");
- }
-
- /**
- * Cast a `null`able value into a non-`null` value, and throw a `NullPointerException` if the value is `null`. Provide
- * a message for a better description of why you require this value to be non-`null`.
- */
- public static @NonNull
- T requireNonNull(final @Nullable T value, final @NonNull Class klass) throws NullPointerException {
- return requireNonNull(value, klass.toString() + " required to be non-null.");
- }
-
- /**
- * Cast a `null`able value into a non-`null` value, and throw a `NullPointerException` if the value is `null`. Provide
- * a message for a better description of why you require this value to be non-`null`.
- */
- public static @NonNull
- T requireNonNull(final @Nullable T value, final @NonNull String message) throws NullPointerException {
- if (value == null) {
- throw new NullPointerException(message);
- }
- return value;
- }
-
- /**
- * Returns true if the Throwable is an instance of RetrofitError with an
- * http status code equals to the given one.
- */
- public static boolean isHttpStatusCode(Throwable throwable, int statusCode) {
- return throwable instanceof HttpException
- && ((HttpException) throwable).code() == statusCode;
- }
-
- public MomoApiError parseError(Response response) {
- Gson gson = new Gson();
-
- MomoApiError error;
-
- try {
- error = gson.fromJson(response.body(), MomoApiError.class);
- } catch (JsonSyntaxException e) {
- return new MomoApiError();
- }
-
- return error;
- }
-}
-
diff --git a/src/main/java/ug/sparkpl/momoapi/models/AccessToken.java b/src/main/java/ug/sparkpl/momoapi/models/AccessToken.java
index a070c10..2d8487d 100644
--- a/src/main/java/ug/sparkpl/momoapi/models/AccessToken.java
+++ b/src/main/java/ug/sparkpl/momoapi/models/AccessToken.java
@@ -1,17 +1,36 @@
package ug.sparkpl.momoapi.models;
+import com.google.gson.annotations.SerializedName;
+
public class AccessToken {
- private String access_token;
- private String token_type;
- private Integer expires_in;
- public AccessToken(String access_token, String token_type, Integer expires_in) {
- this.access_token = access_token;
- this.token_type = token_type;
- this.expires_in = expires_in;
- }
+ @SerializedName("access_token")
+ private String accessToken;
+ @SerializedName("token_type")
+ private String tokenType;
+ @SerializedName("expiresIn")
+ private Integer expires_in;
+
+
+ /**
+ * AccessToken.
+ *
+ * @param accessToken String
+ * @param tokenType String
+ * @param expiresIn String
+ */
+ public AccessToken(String accessToken, String tokenType, Integer expiresIn) {
+ this.accessToken = accessToken;
+ this.tokenType = tokenType;
+ this.expires_in = expiresIn;
+ }
- public String getToken() {
- return this.access_token;
- }
+ /**
+ * Get Access Token.
+ *
+ * @return access Token
+ */
+ public String getToken() {
+ return this.accessToken;
+ }
}
diff --git a/src/main/java/ug/sparkpl/momoapi/models/Account.java b/src/main/java/ug/sparkpl/momoapi/models/Account.java
index 37eaa46..5b4cdce 100644
--- a/src/main/java/ug/sparkpl/momoapi/models/Account.java
+++ b/src/main/java/ug/sparkpl/momoapi/models/Account.java
@@ -3,12 +3,18 @@
import com.google.gson.annotations.SerializedName;
public class Account {
- @SerializedName("availableBalance")
- private String availableBalance;
- private String currency;
+ @SerializedName("availableBalance")
+ private String availableBalance;
+ private String currency;
- Account(String availableBalance, String currency) {
- this.currency = currency;
- this.availableBalance = availableBalance;
- }
+ /**
+ * Account.
+ *
+ * @param availableBalance String
+ * @param currency String
+ */
+ Account(String availableBalance, String currency) {
+ this.currency = currency;
+ this.availableBalance = availableBalance;
+ }
}
diff --git a/src/main/java/ug/sparkpl/momoapi/models/Balance.java b/src/main/java/ug/sparkpl/momoapi/models/Balance.java
index 1534429..0e0ecd2 100644
--- a/src/main/java/ug/sparkpl/momoapi/models/Balance.java
+++ b/src/main/java/ug/sparkpl/momoapi/models/Balance.java
@@ -3,20 +3,32 @@
import com.google.gson.annotations.SerializedName;
public class Balance {
- String description;
+ String description;
- @SerializedName("availableBalance")
- String availableBalance;
+ @SerializedName("availableBalance")
+ String availableBalance;
- String currency;
+ String currency;
- public Balance(String description, String availableBalance, String currency) {
- this.description = description;
- this.currency = currency;
- this.availableBalance = availableBalance;
- }
+ /**
+ * The available balance of the account.
+ *
+ * @param description String
+ * @param availableBalance String The available balance of the account
+ * @param currency String ISO4217 Currency
+ */
+ public Balance(String description, String availableBalance, String currency) {
+ this.description = description;
+ this.currency = currency;
+ this.availableBalance = availableBalance;
+ }
- public String getBalance() {
- return this.availableBalance;
- }
+ /**
+ * Get Available Balance.
+ *
+ * @return String available Balances
+ */
+ public String getBalance() {
+ return this.availableBalance;
+ }
}
diff --git a/src/main/java/ug/sparkpl/momoapi/models/CurrentUserType.java b/src/main/java/ug/sparkpl/momoapi/models/CurrentUserType.java
deleted file mode 100644
index f929414..0000000
--- a/src/main/java/ug/sparkpl/momoapi/models/CurrentUserType.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package ug.sparkpl.momoapi.models;
-
-import lombok.NonNull;
-import rx.Observable;
-import ug.sparkpl.momoapi.Utils.Utils;
-
-import javax.annotation.Nullable;
-
-/**
- * Created by mossplix on 4/27/17.
- */
-
-
-public abstract class CurrentUserType {
-
- /**
- * Call when a user has logged in. The implementation of `CurrentUserType` is responsible
- * for persisting the user and access token.
- */
- public abstract void login(final @NonNull User newUser, final @NonNull String accessToken);
-
- public abstract void login(User user);
-
- /**
- * Call when a user should be logged out.
- */
- public abstract void logout();
-
- /**
- * Get the logged in user's access token.
- */
- public abstract @Nullable
- String getAccessToken();
-
- /**
- * Updates the persisted current user with a fresh, new user.
- */
- public abstract void refresh(final @NonNull User freshUser);
-
- /**
- * Returns an observable representing the current user. It emits immediately
- * with the current user, and then again each time the user is updated.
- */
- public abstract @NonNull
- Observable observable();
-
- /**
- * Returns the most recently emitted user from the user observable.
- *
- * @deprecated Prefer {@link #observable()}
- */
- @Deprecated
- public abstract @Nullable
- User getUser();
-
- /**
- * Returns a boolean that determines if there is a currently logged in user or not.
- *
- * @deprecated Prefer {@link #observable()}
- */
- @Deprecated
- public boolean exists() {
- return getUser() != null;
- }
-
- /**
- * Emits a boolean that determines if the user is logged in or not. The returned
- * observable will emit immediately with the logged in state, and then again
- * each time the current user is updated.
- */
- public @NonNull
- Observable isLoggedIn() {
- return observable().map(Utils::isNotNull);
- }
-
- /**
- * Emits only values of a logged in user. The returned observable may never emit.
- */
- public @NonNull
- Observable loggedInUser() {
- return observable().filter(Utils::isNotNull);
- }
-
- /**
- * Emits only values of a logged out user. The returned observable may never emit.
- */
- public @NonNull
- Observable loggedOutUser() {
- return observable().filter(Utils::isNull);
- }
-}
diff --git a/src/main/java/ug/sparkpl/momoapi/models/LoginBody.java b/src/main/java/ug/sparkpl/momoapi/models/LoginBody.java
index 597a1e9..451747a 100644
--- a/src/main/java/ug/sparkpl/momoapi/models/LoginBody.java
+++ b/src/main/java/ug/sparkpl/momoapi/models/LoginBody.java
@@ -1,11 +1,21 @@
package ug.sparkpl.momoapi.models;
+import com.google.gson.annotations.SerializedName;
+
public class LoginBody {
- private String user_id;
- private String api_key;
+ @SerializedName("user_id")
+ private String userId;
+ @SerializedName("api_key")
+ private String apiKey;
- public LoginBody(String user_id, String api_key) {
- this.user_id = user_id;
- this.api_key = api_key;
- }
+ /**
+ * LoginBody.
+ *
+ * @param userId String
+ * @param apiKey String
+ */
+ public LoginBody(String userId, String apiKey) {
+ this.userId = userId;
+ this.apiKey = apiKey;
+ }
}
\ No newline at end of file
diff --git a/src/main/java/ug/sparkpl/momoapi/models/MomoApiError.java b/src/main/java/ug/sparkpl/momoapi/models/MomoApiError.java
index 824c2bd..cb68d1f 100644
--- a/src/main/java/ug/sparkpl/momoapi/models/MomoApiError.java
+++ b/src/main/java/ug/sparkpl/momoapi/models/MomoApiError.java
@@ -3,18 +3,26 @@
public class MomoApiError {
- private int code;
- private String message;
+ private int code;
+ private String message;
- public MomoApiError() {
- }
- public int status() {
- return code;
- }
+ /**
+ * Get Http Status Code.
+ *
+ * @return Http status Code
+ */
+ public int status() {
+ return code;
+ }
- public String message() {
- return message;
- }
+ /**
+ * Get error Message.
+ *
+ * @return String
+ */
+ public String message() {
+ return message;
+ }
}
diff --git a/src/main/java/ug/sparkpl/momoapi/models/NewUser.java b/src/main/java/ug/sparkpl/momoapi/models/NewUser.java
new file mode 100644
index 0000000..c1a6f24
--- /dev/null
+++ b/src/main/java/ug/sparkpl/momoapi/models/NewUser.java
@@ -0,0 +1,17 @@
+package ug.sparkpl.momoapi.models;
+
+import com.google.gson.annotations.SerializedName;
+
+public class NewUser {
+ @SerializedName("providerCallbackHost")
+ private String providerCallbackHost;
+
+ /**
+ * NewUser.
+ *
+ * @param providerCallbackHost String
+ */
+ public NewUser(String providerCallbackHost) {
+ this.providerCallbackHost = providerCallbackHost;
+ }
+}
diff --git a/src/main/java/ug/sparkpl/momoapi/models/Payer.java b/src/main/java/ug/sparkpl/momoapi/models/Payer.java
index 1b63293..bef8e35 100644
--- a/src/main/java/ug/sparkpl/momoapi/models/Payer.java
+++ b/src/main/java/ug/sparkpl/momoapi/models/Payer.java
@@ -3,13 +3,22 @@
import com.google.gson.annotations.SerializedName;
public class Payer {
- @SerializedName("partyIdType")
- private String partyIdType;
- @SerializedName("partyId")
- private String partyId;
+ @SerializedName("partyIdType")
+ private String partyIdType;
+ @SerializedName("partyId")
+ private String partyId;
- public Payer(String partyId, String partyIdType) {
- this.partyId = partyId;
- this.partyIdType = partyIdType;
- }
+ /**
+ * Payer
+ * MSISDN - Mobile Number validated according to ITU-T E.164. Validated with IsMSISDN
+ * EMAIL - Validated to be a valid e-mail format. Validated with IsEmail
+ * PARTY_CODE - UUID of the party. Validated with IsUuid.
+ *
+ * @param partyId String enum[MSISDN, EMAIL, PARTY_CODE]
+ * @param partyIdType String
+ */
+ public Payer(String partyId, String partyIdType) {
+ this.partyId = partyId;
+ this.partyIdType = partyIdType;
+ }
}
diff --git a/src/main/java/ug/sparkpl/momoapi/models/RequestToPay.java b/src/main/java/ug/sparkpl/momoapi/models/RequestToPay.java
index 3be3d2b..ebd9027 100644
--- a/src/main/java/ug/sparkpl/momoapi/models/RequestToPay.java
+++ b/src/main/java/ug/sparkpl/momoapi/models/RequestToPay.java
@@ -4,32 +4,48 @@
public class RequestToPay {
- @SerializedName("payer")
- private Payer payer;
- @SerializedName("payeeNote")
- private String payeeNote;
- @SerializedName("payerMessage")
- private String payerMessage;
- @SerializedName("externalId")
- private String externalId;
- private String currency;
- private String amount;
-
- public RequestToPay(String mobile,
- String amount,
- String external_id,
- String payee_note,
- String payer_message,
- String currency) {
- this.payer = new Payer(mobile, "MSISDN");
- this.amount = amount;
- this.externalId = external_id;
- this.payerMessage = payer_message;
- this.payeeNote = payee_note;
- this.currency = currency;
-
-
- }
+ @SerializedName("payer")
+ private Payer payer;
+ @SerializedName("payeeNote")
+ private String payeeNote;
+ @SerializedName("payerMessage")
+ private String payerMessage;
+ @SerializedName("externalId")
+ private String externalId;
+ private String currency;
+ private String amount;
+
+
+ /**
+ * Request To Pay.
+ *
+ * @param mobile String
+ * @param amount Amount that will be debited from the payer account.
+ * @param externalId External id is used as a reference to the transaction.
+ * External id is used for reconciliation.
+ * The external id will be included in transaction history report.
+ * External id is not required to be unique.
+ * @param payeeNote Message that will be written in the payee transaction
+ * history note field.
+ * @param payerMessage Message that will be written in the payer transaction
+ * history message field.
+ * @param currency ISO4217 Currency
+ */
+ public RequestToPay(String mobile,
+ String amount,
+ String externalId,
+ String payeeNote,
+ String payerMessage,
+ String currency) {
+ this.payer = new Payer(mobile, "MSISDN");
+ this.amount = amount;
+ this.externalId = externalId;
+ this.payerMessage = payerMessage;
+ this.payeeNote = payeeNote;
+ this.currency = currency;
+
+
+ }
}
diff --git a/src/main/java/ug/sparkpl/momoapi/models/Transaction.java b/src/main/java/ug/sparkpl/momoapi/models/Transaction.java
index 02fc234..939d39e 100644
--- a/src/main/java/ug/sparkpl/momoapi/models/Transaction.java
+++ b/src/main/java/ug/sparkpl/momoapi/models/Transaction.java
@@ -1,47 +1,79 @@
package ug.sparkpl.momoapi.models;
+import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
public class Transaction {
- private float amount;
- private String currency;
- @SerializedName("financialTransactionId")
- private String financialTransactionId;
- @SerializedName("externalId")
- private String externalId;
- private Payer payer;
- private String status;
- private Reason reason;
+ private float amount;
+ private String currency;
+ @SerializedName("financialTransactionId")
+ private String financialTransactionId;
+ @SerializedName("externalId")
+ private String externalId;
+ private Payer payer;
+ private String status;
+ private Reason reason;
- public String getStatus() {
- return this.status;
- }
+ /**
+ * Get Transaction Status.
+ *
+ * @return String
+ */
+ public String getStatus() {
+ return this.status;
+ }
- public float getAmount() {
- return this.amount;
- }
+ /**
+ * Get Transaction amount.
+ *
+ * @return String amount
+ */
+ public float getAmount() {
+ return this.amount;
+ }
- public String getCurrency() {
- return this.currency;
- }
+ /**
+ * Get transaction currency.
+ *
+ * @return String currency
+ */
+ public String getCurrency() {
+ return this.currency;
+ }
- public String getFinancialTransactionId() {
- return this.financialTransactionId;
- }
+ /**
+ * Get Transaction Id.
+ *
+ * @return String transaction id
+ */
+ public String getFinancialTransactionId() {
+ return this.financialTransactionId;
+ }
- public String getExternalId() {
- return this.externalId;
- }
+ /**
+ * Get External Ref.
+ *
+ * @return String
+ */
- class Reason {
+ public String getExternalId() {
+ return this.externalId;
+ }
- private String code;
- private String message;
+ @Override
+ public String toString() {
+ Gson gson = new Gson();
+ return gson.toJson(this);
+ }
- }
+ class Reason {
+ private String code;
+ private String message;
+
+ }
}
diff --git a/src/main/java/ug/sparkpl/momoapi/models/Transfer.java b/src/main/java/ug/sparkpl/momoapi/models/Transfer.java
index 56c9231..9cc5ee2 100644
--- a/src/main/java/ug/sparkpl/momoapi/models/Transfer.java
+++ b/src/main/java/ug/sparkpl/momoapi/models/Transfer.java
@@ -3,31 +3,47 @@
import com.google.gson.annotations.SerializedName;
public class Transfer {
- @SerializedName("payee")
- private Payer payee;
- @SerializedName("payeeNote")
- private String payeeNote;
- @SerializedName("payerMessage")
- private String payerMessage;
- @SerializedName("externalId")
- private String externalId;
- private String currency;
- private String amount;
+ @SerializedName("payee")
+ private Payer payee;
+ @SerializedName("payeeNote")
+ private String payeeNote;
+ @SerializedName("payerMessage")
+ private String payerMessage;
+ @SerializedName("externalId")
+ private String externalId;
+ private String currency;
+ private String amount;
- public Transfer(String mobile,
- String amount,
- String external_id,
- String payee_note,
- String payer_message,
- String currency) {
- this.payee = new Payer(mobile, "MSISDN");
- this.amount = amount;
- this.externalId = external_id;
- this.payerMessage = payer_message;
- this.payeeNote = payee_note;
- this.currency = currency;
+ /**
+ * Transfer operation is used to transfer an
+ * amount from the owner’s account to a payee account.
+ *
+ * @param mobile String Mobile number to transfer to
+ * @param amount Amount that will be debited from the payer account.
+ * @param externalId External id is used as a reference to the transaction.
+ * External id is used for reconciliation. The external id
+ * will be included in transaction history report.
+ * External id is not required to be unique.
+ * @param payeeNote Message that will be written in the payee
+ * transaction history note field.
+ * @param payerMessage Message that will be written in the payer
+ * transaction history message field.
+ * @param currency ISO4217 Currency
+ */
+ public Transfer(String mobile,
+ String amount,
+ String externalId,
+ String payeeNote,
+ String payerMessage,
+ String currency) {
+ this.payee = new Payer(mobile, "MSISDN");
+ this.amount = amount;
+ this.externalId = externalId;
+ this.payerMessage = payerMessage;
+ this.payeeNote = payeeNote;
+ this.currency = currency;
- }
+ }
}
diff --git a/src/main/java/ug/sparkpl/momoapi/models/User.java b/src/main/java/ug/sparkpl/momoapi/models/User.java
index 8d89837..c62b1f7 100644
--- a/src/main/java/ug/sparkpl/momoapi/models/User.java
+++ b/src/main/java/ug/sparkpl/momoapi/models/User.java
@@ -1,7 +1,21 @@
package ug.sparkpl.momoapi.models;
+import com.google.gson.annotations.SerializedName;
+
public class User {
-private static AccessToken collectionsToken;
-private static AccessToken disbursementsToken;
+ private static AccessToken collectionsToken;
+ private static AccessToken disbursementsToken;
+
+ @SerializedName("apiKey")
+ private String apiKey;
+
+ /**
+ * Get API Key.
+ *
+ * @return String
+ */
+ public String getApiKey() {
+ return this.apiKey;
+ }
}
diff --git a/src/main/java/ug/sparkpl/momoapi/network/ApiException.java b/src/main/java/ug/sparkpl/momoapi/network/ApiException.java
deleted file mode 100644
index f6a2407..0000000
--- a/src/main/java/ug/sparkpl/momoapi/network/ApiException.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package ug.sparkpl.momoapi.network;
-
-/**
- * An exception class for the response.
- */
-public final class ApiException extends RuntimeException {
-
-
- public ApiException(String response) {
- super(response);
-
- }
-}
diff --git a/src/main/java/ug/sparkpl/momoapi/network/BaseClient.java b/src/main/java/ug/sparkpl/momoapi/network/BaseClient.java
index c69f2de..8c3d501 100644
--- a/src/main/java/ug/sparkpl/momoapi/network/BaseClient.java
+++ b/src/main/java/ug/sparkpl/momoapi/network/BaseClient.java
@@ -1,69 +1,90 @@
package ug.sparkpl.momoapi.network;
+import ug.sparkpl.momoapi.network.collections.CollectionsApiService;
+import ug.sparkpl.momoapi.utils.DateTimeTypeConverter;
+
+import org.joda.time.DateTime;
+
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
+
import lombok.NonNull;
-import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
-import org.joda.time.DateTime;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
-import rx.Scheduler;
-import rx.schedulers.Schedulers;
-import ug.sparkpl.momoapi.Utils.DateTimeTypeConverter;
-import ug.sparkpl.momoapi.network.collections.CollectionsApiService;
-
-
-class BaseClient {
-
- BaseClient() {
-
- }
-
-
- Scheduler getScheduler() {
- return Schedulers.computation();
- }
-
-
- Gson getGson() {
- return new GsonBuilder()
- .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
- .registerTypeAdapter(DateTime.class, new DateTimeTypeConverter())
- .create();
- }
-
-
- Retrofit createRetrofit(final @NonNull HttpUrl apiEndpoint, final @NonNull Gson gson, final @NonNull OkHttpClient okHttpClient) {
- return new Retrofit.Builder()
- .client(okHttpClient)
- .baseUrl(apiEndpoint)
- .addConverterFactory(GsonConverterFactory.create(gson))
- .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
- .build();
- }
-
-
- HttpLoggingInterceptor getHttpLoggingInterceptor() {
- final HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
- interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
- return interceptor;
- }
-
-
- CollectionsApiService provideCollectionsApiService(final @NonNull Retrofit apiRetrofit) {
- return apiRetrofit.create(CollectionsApiService.class);
- }
- Retrofit getApiRetrofit(final @NonNull HttpUrl apiEndpoint,
- final @NonNull Gson gson,
- final @NonNull OkHttpClient okHttpClient) {
- return createRetrofit(apiEndpoint, gson, okHttpClient);
- }
+public class BaseClient {
+
+
+ /**
+ * getGson.
+ *
+ * @return Gson
+ */
+ public Gson getGson() {
+ return new GsonBuilder()
+ .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
+ .registerTypeAdapter(DateTime.class, new DateTimeTypeConverter())
+ .create();
+ }
+
+
+ /**
+ * create Retrofit.
+ *
+ * @param apiEndpoint String
+ * @param okHttpClient OkHttpClient
+ * @return Retrofit
+ */
+ Retrofit createRetrofit(final String apiEndpoint,
+ final @NonNull OkHttpClient okHttpClient) {
+ return new Retrofit.Builder()
+ .client(okHttpClient)
+ .baseUrl(apiEndpoint)
+ .addConverterFactory(GsonConverterFactory.create(getGson()))
+ .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
+ .build();
+ }
+
+
+ /**
+ * get Http Logging Interceptor.
+ *
+ * @return HttpLoggingInterceptor
+ */
+ HttpLoggingInterceptor getHttpLoggingInterceptor() {
+ final HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
+ interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
+ return interceptor;
+ }
+
+
+ /**
+ * get collections Api Service.
+ *
+ * @param apiRetrofit Retrofit.
+ * @return CollectionsApiService
+ */
+ CollectionsApiService provideCollectionsApiService(final @NonNull Retrofit apiRetrofit) {
+ return apiRetrofit.create(CollectionsApiService.class);
+ }
+
+
+ /**
+ * Get Api Retrofit.
+ *
+ * @param apiEndpoint String
+ * @param okHttpClient OkHttpClient
+ * @return Retrofit
+ */
+ Retrofit getApiRetrofit(final @NonNull String apiEndpoint,
+ final @NonNull OkHttpClient okHttpClient) {
+ return createRetrofit(apiEndpoint, okHttpClient);
+ }
}
\ No newline at end of file
diff --git a/src/main/java/ug/sparkpl/momoapi/network/BaseResponse.java b/src/main/java/ug/sparkpl/momoapi/network/BaseResponse.java
index 069f92f..55ddd29 100644
--- a/src/main/java/ug/sparkpl/momoapi/network/BaseResponse.java
+++ b/src/main/java/ug/sparkpl/momoapi/network/BaseResponse.java
@@ -1,9 +1,14 @@
-
package ug.sparkpl.momoapi.network;
-public class BaseResponse {
- private String error = null;
- public String getError() {
- return error;
- }
+public class BaseResponse {
+ private String error = null;
+
+ /**
+ * get Error.
+ *
+ * @return String
+ */
+ public String getError() {
+ return error;
+ }
}
\ No newline at end of file
diff --git a/src/main/java/ug/sparkpl/momoapi/network/MomoApiException.java b/src/main/java/ug/sparkpl/momoapi/network/MomoApiException.java
new file mode 100644
index 0000000..1c88a26
--- /dev/null
+++ b/src/main/java/ug/sparkpl/momoapi/network/MomoApiException.java
@@ -0,0 +1,20 @@
+package ug.sparkpl.momoapi.network;
+
+import java.io.IOException;
+
+/**
+ * An exception class for the response.
+ */
+public final class MomoApiException extends IOException {
+
+
+ /**
+ * MomoApiException.
+ *
+ * @param response String
+ */
+ public MomoApiException(String response) {
+ super(response);
+
+ }
+}
diff --git a/src/main/java/ug/sparkpl/momoapi/network/RequestOptions.java b/src/main/java/ug/sparkpl/momoapi/network/RequestOptions.java
index 89776dd..992e462 100644
--- a/src/main/java/ug/sparkpl/momoapi/network/RequestOptions.java
+++ b/src/main/java/ug/sparkpl/momoapi/network/RequestOptions.java
@@ -7,209 +7,549 @@
public class RequestOptions {
- private String COLLECTION_USER_ID;
- private String COLLECTION_API_SECRET;
- private String COLLECTION_PRIMARY_KEY;
+ private final String collectionUserId;
+ private final String collectionApiSecret;
+ private final String collectionPrimaryKey;
+
+ private final String remittancePrimaryKey;
+ private final String remittanceUserId;
+ private final String remittanceApiSecret;
+
+
+ private final String disbursementPrimaryKey;
+ private final String disbursementUserId;
+ private final String disbursementApiSecret;
+
+ private final String baseUrl;
+ private final String targetEnvironment;
+ private final String currency;
+
+ /**
+ * Build options.
+ *
+ * @param collectionApiSecret String
+ * @param collectionPrimaryKey String
+ * @param collectionUserId String
+ * @param remittanceUserId String
+ * @param remittancePrimaryKey String
+ * @param remittanceApiSecret String
+ * @param disbursementApiSecret String
+ * @param disbursementPrimaryKey String
+ * @param disbursementUserId String
+ * @param baseUrl String
+ * @param targetEnvironment String
+ * @param currency String
+ */
+ public RequestOptions(String collectionApiSecret,
+ String collectionPrimaryKey,
+ String collectionUserId,
+ String remittanceUserId,
+ String remittancePrimaryKey,
+ String remittanceApiSecret,
+ String disbursementApiSecret,
+ String disbursementPrimaryKey,
+ String disbursementUserId,
+ String baseUrl,
+ String targetEnvironment,
+ String currency) {
+
+ this.collectionApiSecret = collectionApiSecret;
+ this.collectionPrimaryKey = collectionPrimaryKey;
+ this.collectionUserId = collectionUserId;
+
+ this.remittanceUserId = remittanceUserId;
+ this.remittancePrimaryKey = remittancePrimaryKey;
+ this.remittanceApiSecret = remittanceApiSecret;
+
+ this.disbursementApiSecret = disbursementApiSecret;
+ this.disbursementPrimaryKey = disbursementPrimaryKey;
+ this.disbursementUserId = disbursementUserId;
+ this.baseUrl = baseUrl;
+ this.targetEnvironment = targetEnvironment;
+ this.currency = currency;
+
+
+ }
+
+ /**
+ * Builder.
+ *
+ * @return Builder
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * for playing nice with unittests.
+ *
+ * @return Builder
+ */
+ public Builder toBuilder() {
+ return new Builder()
+ .setCollectionPrimaryKey(this.collectionPrimaryKey)
+ .setCollectionApiSecret(this.collectionApiSecret)
+ .setCollectionUserId(this.collectionUserId)
+ .setCurrency(this.currency)
+ .setBaseUrl(this.baseUrl)
+ .setTargetEnvironment(this.targetEnvironment)
+ .setDisbursementApiSecret(this.disbursementApiSecret)
+ .setDisbursementPrimaryKey(this.disbursementPrimaryKey)
+ .setDisbursementUserId(this.disbursementUserId)
+ .setRemittanceApiSecret(this.remittanceApiSecret)
+ .setRemittancePrimaryKey(this.remittancePrimaryKey)
+ .setRemittanceUserId(this.remittanceUserId);
+
+ }
+
+ /**
+ * get Collection Id.
+ *
+ * @return String
+ */
+ public String getCollectionUserId() {
+ return this.collectionUserId;
+ }
+
+ /**
+ * get collection API secret.
+ *
+ * @return String
+ */
+ public String getCollectionApiSecret() {
+ return this.collectionApiSecret;
+ }
+
+ /**
+ * Get collection Primary Key.
+ *
+ * @return String
+ */
+ public String getCollectionPrimaryKey() {
+ return this.collectionPrimaryKey;
+ }
+
+ /**
+ * Get Remittance Primary Key.
+ *
+ * @return String
+ */
+
+ public String getRemittancePrimaryKey() {
+ return this.remittancePrimaryKey;
+ }
+
+
+ /**
+ * get Remittance user Id.
+ *
+ * @return String
+ */
+ public String getRemittanceUserId() {
+ return remittanceUserId;
+ }
+
+ /**
+ * Get Remittance Api Secret.
+ *
+ * @return String
+ */
+ public String getRemittanceApiSecret() {
+ return this.remittanceApiSecret;
+ }
+
+
+ /**
+ * Get Disbursement Primnary Key.
+ *
+ * @return String
+ */
+ public String getDisbursementPrimaryKey() {
+ return this.disbursementPrimaryKey;
+ }
+
+
+ /**
+ * Get Disbursement User Id.
+ *
+ * @return String
+ */
+ public String getDisbursementUserId() {
+ return this.disbursementUserId;
+ }
+
+ /**
+ * Get Disbursement Api Secret.
+ *
+ * @return String
+ */
+ public String getDisbursementApiSecret() {
+ return this.disbursementApiSecret;
+ }
+
+ /**
+ * Get Base Url.
+ *
+ * @return String
+ */
+ public String getBaseUrl() {
+ return this.baseUrl;
+ }
+
+ /**
+ * Get Target Environment.
+ *
+ * @return String
+ */
+ public String getTargetEnvironment() {
+ return this.targetEnvironment;
+ }
+
+ /**
+ * get Currency.
+ *
+ * @return String
+ */
+ public String getCurrency() {
+ return this.currency;
+ }
+
+
+ public static class Builder {
+
+ private String collectionUserId;
+ private String collectionApiSecret;
+ private String collectionPrimaryKey;
+ private String remittancePrimaryKey;
+ private String remittanceUserId;
+ private String remittanceApiSecret;
+ private String disbursementPrimaryKey;
+ private String disbursementUserId;
+ private String disbursementApiSecret;
+
+ private String baseUrl = "https://ericssonbasicapi2.azure-api.net";
+
+ private String currency = "EUR";
+
+ private String targetEnvironment = "sandbox";
+
+
+ /**
+ * Constructs a request options builder with the global parameters (API key, client ID and
+ * API version) as default values.
+ */
+ public Builder() {
+ this.collectionUserId = System.getenv("COLLECTION_USER_ID");
+ this.collectionApiSecret = System.getenv("COLLECTION_API_SECRET");
+ this.collectionPrimaryKey = System.getenv("COLLECTION_PRIMARY_KEY");
+
+ this.remittancePrimaryKey = System.getenv("REMITTANCE_PRIMARY_KEY");
+ this.remittanceUserId = System.getenv("REMITTANCE_USER_ID");
+ this.remittanceApiSecret = System.getenv("REMITTANCE_API_SECRET");
+
+ this.disbursementPrimaryKey = System.getenv("DISBURSEMENT_PRIMARY_KEY");
+ this.disbursementUserId = System.getenv("DISBURSEMENT_USER_ID");
+ this.disbursementApiSecret = System.getenv("DISBURSEMENT_API_SECRET");
- private String REMITTANCE_PRIMARY_KEY;
- private String REMITTANCE_USER_ID;
- private String REMITTANCE_API_SECRET;
-
-
- private String DISBURSEMENT_PRIMARY_KEY;
- private String DISBURSEMENT_USER_ID;
- private String DISBURSEMENT_API_SECRET;
-
- private String BASE_URL = "https://ericssonbasicapi2.azure-api.net";
- private String TARGET_ENVIRONMENT = "sandbox";
+ }
- private RequestOptions() {
+ /**
+ * Normalize Keys.
+ *
+ * @param key String
+ * @return String
+ */
+ private static String normalizeKey(String key) {
+ String normalized = key.trim();
+ if (normalized.isEmpty()) {
+ throw new InvalidRequestOptionsException("Empty key specified!");
+ }
+ return normalized;
}
- public static Builder builder() {
- return new Builder();
+ /**
+ * Get Collection primary key.
+ *
+ * @return String
+ */
+ public String getCollectionPrimaryKey() {
+ return this.collectionPrimaryKey;
}
+ /**
+ * Set Collection Primary Key.
+ *
+ * @param collectionPrimaryKey String
+ * @return String
+ */
+ public Builder setCollectionPrimaryKey(String collectionPrimaryKey) {
+ this.collectionPrimaryKey = collectionPrimaryKey;
+ return this;
+ }
+ /**
+ * get Collection User Id.
+ *
+ * @return String
+ */
public String getCollectionUserId() {
- return this.COLLECTION_USER_ID;
+ return this.collectionUserId;
}
+ /**
+ * Set Collection User Id.
+ *
+ * @param collectionUserId String
+ * @return Builder
+ */
+ public Builder setCollectionUserId(String collectionUserId) {
+ this.collectionUserId = collectionUserId;
+ return this;
+ }
+
+ /**
+ * get Collection Api Secret.
+ *
+ * @return String
+ */
public String getCollectionApiSecret() {
- return this.COLLECTION_API_SECRET;
+ return this.collectionApiSecret;
}
- public String getCollectionPrimaryKey() {
- return this.COLLECTION_PRIMARY_KEY;
+ /**
+ * Set Collection Api Secret.
+ *
+ * @param collectionApiSecret String
+ * @return String
+ */
+ public Builder setCollectionApiSecret(String collectionApiSecret) {
+ this.collectionApiSecret = collectionApiSecret;
+ return this;
}
+ /**
+ * Get Remittance Primary Key.
+ *
+ * @return String
+ */
public String getRemittancePrimaryKey() {
- return this.REMITTANCE_PRIMARY_KEY;
+ return this.remittancePrimaryKey;
}
+ /**
+ * Set Remittance Primary Key.
+ *
+ * @param remittancePrimaryKey String
+ * @return Builder
+ */
+ public Builder setRemittancePrimaryKey(String remittancePrimaryKey) {
+ this.remittancePrimaryKey = remittancePrimaryKey;
+ return this;
+ }
+ /**
+ * Get Remittance User Id.
+ *
+ * @return String
+ */
public String getRemittanceUserId() {
- return this.REMITTANCE_USER_ID;
+ return remittanceUserId;
+ }
+
+ /**
+ * Set Remittance User Id.
+ *
+ * @param remittanceUserId String
+ * @return Builder
+ */
+
+ public Builder setRemittanceUserId(String remittanceUserId) {
+ this.remittanceUserId = remittanceUserId;
+ return this;
}
+ /**
+ * Set Remittance Api Secret.
+ *
+ * @return String
+ */
public String getRemittanceApiSecret() {
- return this.REMITTANCE_API_SECRET;
+ return this.remittanceApiSecret;
}
+ /**
+ * Set Remittance Api Secret.
+ *
+ * @param remittanceApiSecret String
+ * @return Builder
+ */
+ public Builder setRemittanceApiSecret(String remittanceApiSecret) {
+ this.remittanceApiSecret = remittanceApiSecret;
+ return this;
+ }
+ /**
+ * Get Disbursements Primary Key.
+ *
+ * @return String
+ */
public String getDisbursementPrimaryKey() {
- return this.DISBURSEMENT_PRIMARY_KEY;
+ return this.disbursementPrimaryKey;
}
+ /**
+ * Set Disbursements Primary Key.
+ *
+ * @param disbursementPrimaryKey String
+ * @return Builder
+ */
+ public Builder setDisbursementPrimaryKey(String disbursementPrimaryKey) {
+ this.disbursementPrimaryKey = disbursementPrimaryKey;
+ return this;
+ }
+ /**
+ * Get Disbursements User Id.
+ *
+ * @return String
+ */
public String getDisbursementUserId() {
- return this.DISBURSEMENT_USER_ID;
+ return this.disbursementUserId;
}
- public String getDisbursementApiSecret() {
- return this.DISBURSEMENT_API_SECRET;
+ /**
+ * Set Disbursements User Id.
+ *
+ * @param disbursementUserId String
+ * @return Builder
+ */
+ public Builder setDisbursementUserId(String disbursementUserId) {
+ this.disbursementUserId = disbursementUserId;
+ return this;
}
- public String getBaseUrl() {
- return this.BASE_URL;
+ /**
+ * Get Disbursements Api Secret.
+ *
+ * @return String
+ */
+ public String getDisbursementApiSecret() {
+ return this.disbursementApiSecret;
}
- public String getTargetEnvironment() {
- return this.TARGET_ENVIRONMENT;
+ /**
+ * Set Disbursement Api Secret.
+ *
+ * @param disbursementApiSecret String
+ * @return Builder
+ */
+ public Builder setDisbursementApiSecret(String disbursementApiSecret) {
+ this.disbursementApiSecret = disbursementApiSecret;
+ return this;
}
+ /**
+ * Get Base Url.
+ *
+ * @return String
+ */
+ public String getBaseUrl() {
+ return this.baseUrl;
+ }
- public static final class Builder {
-
- private String COLLECTION_USER_ID;
- private String COLLECTION_API_SECRET;
- private String COLLECTION_PRIMARY_KEY;
- private String REMITTANCE_PRIMARY_KEY;
- private String REMITTANCE_USER_ID;
- private String REMITTANCE_API_SECRET;
- private String DISBURSEMENT_PRIMARY_KEY;
- private String DISBURSEMENT_USER_ID;
- private String DISBURSEMENT_API_SECRET;
-
- private String BASE_URL = "https://ericssonbasicapi2.azure-api.net";
-
- private String CURRENCY = "EUR";
-
- private String TARGET_ENVIRONMENT = "sandbox";
-
-
- /**
- * Constructs a request options builder with the global parameters (API key, client ID and
- * API version) as default values.
- */
- public Builder() {
- this.COLLECTION_USER_ID = System.getenv("COLLECTION_USER_ID");
- this.COLLECTION_API_SECRET = System.getenv("COLLECTION_API_SECRET");
- this.COLLECTION_PRIMARY_KEY = System.getenv("COLLECTION_PRIMARY_KEY");
-
- this.REMITTANCE_PRIMARY_KEY = System.getenv("REMITTANCE_PRIMARY_KEY");
- this.REMITTANCE_USER_ID = System.getenv("REMITTANCE_USER_ID");
- this.REMITTANCE_API_SECRET = System.getenv("REMITTANCE_API_SECRET");
-
- this.DISBURSEMENT_PRIMARY_KEY = System.getenv("DISBURSEMENT_PRIMARY_KEY");
- this.DISBURSEMENT_USER_ID = System.getenv("DISBURSEMENT_USER_ID");
- this.DISBURSEMENT_API_SECRET = System.getenv("DISBURSEMENT_API_SECRET");
- }
-
- private static String normalizeKey(String key) {
-
- String normalized = key.trim();
- if (normalized.isEmpty()) {
- throw new InvalidRequestOptionsException("Empty key specified!");
- }
- return normalized;
- }
-
-
- public Builder setCollectionUserId(String collectionUserId) {
- this.COLLECTION_USER_ID = collectionUserId;
- return this;
- }
-
- public Builder setCollectionApiSecret(String collectionApiSecret) {
- this.COLLECTION_API_SECRET = collectionApiSecret;
- return this;
- }
-
- public Builder setCollectionPrimaryKey(String collectionPrimaryKey) {
- this.COLLECTION_PRIMARY_KEY = collectionPrimaryKey;
- return this;
- }
-
- public Builder setRemittanceUserId(String remittanceUserId) {
- this.REMITTANCE_USER_ID = remittanceUserId;
- return this;
- }
-
- public Builder setRemittanceApiSecret(String remittanceApiSecret) {
- this.REMITTANCE_API_SECRET = remittanceApiSecret;
- return this;
- }
-
- public Builder setRemittancePrimaryKey(String remittancePrimaryKey) {
- this.REMITTANCE_PRIMARY_KEY = remittancePrimaryKey;
- return this;
- }
-
- public Builder setDisbursementUserId(String disbursementUserId) {
- this.DISBURSEMENT_USER_ID = disbursementUserId;
- return this;
- }
-
- public Builder setDisbursementApiSecret(String disbursementApiSecret) {
- this.DISBURSEMENT_API_SECRET = disbursementApiSecret;
- return this;
- }
-
- public Builder setDisbursementPrimaryKey(String disbursementPrimaryKey) {
- this.DISBURSEMENT_PRIMARY_KEY = disbursementPrimaryKey;
- return this;
- }
-
- public Builder setBaseUrl(String url) {
- this.BASE_URL = url;
- return this;
- }
-
-
- public RequestOptions build() {
- RequestOptions opts = new RequestOptions();
- opts.COLLECTION_API_SECRET = this.COLLECTION_API_SECRET;
- opts.COLLECTION_PRIMARY_KEY = this.COLLECTION_PRIMARY_KEY;
- opts.COLLECTION_USER_ID = this.COLLECTION_USER_ID;
+ /**
+ * Set Base Url.
+ *
+ * @param url String
+ * @return Builder
+ */
+ public Builder setBaseUrl(String url) {
+ this.baseUrl = url;
+ return this;
+ }
- opts.REMITTANCE_USER_ID = this.REMITTANCE_USER_ID;
- opts.REMITTANCE_PRIMARY_KEY = this.REMITTANCE_PRIMARY_KEY;
- opts.REMITTANCE_API_SECRET = this.REMITTANCE_API_SECRET;
+ /**
+ * Get Target Environment.
+ *
+ * @return String
+ */
+ public String getTargetEnvironment() {
+ return this.targetEnvironment;
+ }
- opts.DISBURSEMENT_API_SECRET = this.DISBURSEMENT_API_SECRET;
- opts.DISBURSEMENT_PRIMARY_KEY = this.DISBURSEMENT_PRIMARY_KEY;
- opts.DISBURSEMENT_USER_ID = this.DISBURSEMENT_USER_ID;
- opts.BASE_URL = this.BASE_URL;
- opts.TARGET_ENVIRONMENT = this.TARGET_ENVIRONMENT;
+ /**
+ * Set Target Environment.
+ *
+ * @param environment String
+ * @return Builder
+ */
+ public Builder setTargetEnvironment(String environment) {
+ this.targetEnvironment = environment;
+ return this;
+ }
- return opts;
+ /**
+ * Get Currency.
+ *
+ * @return String
+ */
+ public String getCurrency() {
+ return this.currency;
+ }
- }
+ /**
+ * Set Currency.
+ *
+ * @param currency String
+ * @return Builder
+ */
+ public Builder setCurrency(String currency) {
+ this.currency = currency;
+ return this;
+ }
+ /**
+ * RequestOptions.
+ *
+ * @return RequestOptions
+ */
+ public RequestOptions build() {
+ return new RequestOptions(
+ this.collectionApiSecret,
+ this.collectionPrimaryKey,
+ this.collectionUserId,
+
+ this.remittanceUserId,
+ this.remittancePrimaryKey,
+ this.remittanceApiSecret,
+
+ this.disbursementApiSecret,
+ this.disbursementPrimaryKey,
+ this.disbursementUserId,
+ this.baseUrl,
+ this.targetEnvironment,
+ this.currency
+ );
}
- public static class InvalidRequestOptionsException extends RuntimeException {
- private static final long serialVersionUID = 1L;
+ }
+
+ public static class InvalidRequestOptionsException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
- public InvalidRequestOptionsException(String message) {
- super(message);
- }
+ /**
+ * Ovveride.
+ *
+ * @param message String
+ */
+ public InvalidRequestOptionsException(String message) {
+ super(message);
}
+ }
}
diff --git a/src/main/java/ug/sparkpl/momoapi/network/ResponseException.java b/src/main/java/ug/sparkpl/momoapi/network/ResponseException.java
index 977e07b..19b0d0b 100644
--- a/src/main/java/ug/sparkpl/momoapi/network/ResponseException.java
+++ b/src/main/java/ug/sparkpl/momoapi/network/ResponseException.java
@@ -1,16 +1,25 @@
package ug.sparkpl.momoapi.network;
-import lombok.NonNull;
+import okhttp3.Response;
public class ResponseException extends RuntimeException {
- private final okhttp3.Response response;
+ private final Response response;
- public ResponseException(final @NonNull okhttp3.Response response) {
- this.response = response;
- }
+ /**
+ * ResponseException.
+ *
+ * @param response Response
+ */
+ public ResponseException(final Response response) {
+ this.response = response;
+ }
- public @NonNull
- okhttp3.Response response() {
- return response;
- }
+ /**
+ * response.
+ *
+ * @return Response
+ */
+ public Response response() {
+ return response;
+ }
}
diff --git a/src/main/java/ug/sparkpl/momoapi/network/collections/CollectionSession.java b/src/main/java/ug/sparkpl/momoapi/network/collections/CollectionSession.java
index 0a99ef7..a9291c0 100644
--- a/src/main/java/ug/sparkpl/momoapi/network/collections/CollectionSession.java
+++ b/src/main/java/ug/sparkpl/momoapi/network/collections/CollectionSession.java
@@ -3,29 +3,29 @@
import java.util.prefs.Preferences;
public class CollectionSession {
- String TOKEN_NAME = "TOKEN";
- private String token;
- private Preferences prefs;
+ String TOKEN_NAME = "TOKEN";
+ private String token;
+ private Preferences prefs;
- public CollectionSession() {
- this.prefs = Preferences.userRoot().node(this.getClass().getName());
- }
+ public CollectionSession() {
+ this.prefs = Preferences.userRoot().node(this.getClass().getName());
+ }
- public void saveToken(String token) {
- prefs.put(TOKEN_NAME, token);
- }
+ public void saveToken(String token) {
+ prefs.put(TOKEN_NAME, token);
+ }
- public String getToken() {
- // return the token that was saved earlier
- return prefs.get(TOKEN_NAME, "ddd");
- }
+ public String getToken() {
+ // return the token that was saved earlier
+ return prefs.get(TOKEN_NAME, "dummy");
+ }
- public void invalidate() {
+ public void invalidate() {
- }
+ }
}
diff --git a/src/main/java/ug/sparkpl/momoapi/network/collections/CollectionsApiService.java b/src/main/java/ug/sparkpl/momoapi/network/collections/CollectionsApiService.java
index 2260405..bdaa78c 100644
--- a/src/main/java/ug/sparkpl/momoapi/network/collections/CollectionsApiService.java
+++ b/src/main/java/ug/sparkpl/momoapi/network/collections/CollectionsApiService.java
@@ -1,33 +1,107 @@
package ug.sparkpl.momoapi.network.collections;
+import ug.sparkpl.momoapi.models.AccessToken;
+import ug.sparkpl.momoapi.models.Account;
+import ug.sparkpl.momoapi.models.Balance;
+import ug.sparkpl.momoapi.models.NewUser;
+import ug.sparkpl.momoapi.models.RequestToPay;
+import ug.sparkpl.momoapi.models.Transaction;
+import ug.sparkpl.momoapi.models.User;
+
import retrofit2.Call;
-import retrofit2.http.*;
-import ug.sparkpl.momoapi.models.*;
+import retrofit2.http.Body;
+import retrofit2.http.GET;
+import retrofit2.http.Header;
+import retrofit2.http.Headers;
+import retrofit2.http.POST;
+import retrofit2.http.Path;
+
public interface CollectionsApiService {
- @GET("/v1_0/accountholder/{accountHolderIdType}/{accountHolderId}/active")
- @Headers("Content-Type: application/json")
- Call isActive(@Path("accountHolderIdType") String accountHolderIdType, @Path("accountHolderId") String accountHolderId);
+ /**
+ * Is Active.
+ *
+ * @param accountHolderIdType String
+ * @param accountHolderId String
+ * @return Account
+ */
+ @GET("/v1_0/accountholder/{accountHolderIdType}/{accountHolderId}/active")
+ @Headers("Content-Type: application/json")
+ Call isActive(@Path("accountHolderIdType") String accountHolderIdType,
+ @Path("accountHolderId") String accountHolderId);
+
+ /**
+ * requestToPay.
+ *
+ * @param body RequestBody
+ * @param ref String
+ * @return Void
+ */
+ @POST("/collection/v1_0/requesttopay")
+ @Headers("Content-Type: application/json")
+ Call requestToPay(@Body RequestToPay body,
+ @Header("X-Reference-Id") String ref);
+
+ /**
+ * getToken.
+ *
+ * @param credentials String
+ * @param subscriptionKey String
+ * @return AccessToken
+ */
+ @POST("/collection/token/")
+ @Headers("Content-Type: application/json")
+ Call getToken(@Header("Authorization") String credentials,
+ @Header("Ocp-Apim-Subscription-Key") String subscriptionKey);
+
+ /**
+ * Get Account Balance.
+ *
+ * @return Balance Object
+ */
+ @Headers("Content-Type: application/json")
+ @GET("/collection/v1_0/account/balance")
+ Call getBalance();
+
+
+ /**
+ * Get Transaction Status.
+ *
+ * @param transactionId String
+ * @return Transaction object
+ */
+ @GET("/collection/v1_0/requesttopay/{transactionId}")
+ @Headers("Content-Type: application/json")
+ Call getTransactionStatus(@Path("transactionId") String transactionId);
- @POST("/collection/v1_0/requesttopay")
- @Headers("Content-Type: application/json")
- Call requestToPay(@Body RequestToPay body, @Header("X-Reference-Id") String ref);
- @POST("/collection/token/")
- @Headers("Content-Type: application/json")
- Call getToken(@Header("Authorization") String credentials, @Header("Ocp-Apim-Subscription-Key") String subscriptionKey);
+ /**
+ * provision User Account.
+ *
+ * @param key String
+ * @param token String
+ * @param body NewUser
+ * @return Void
+ */
+ @POST("https://ericssonbasicapi2.azure-api.net/v1_0/apiuser")
+ @Headers("Content-Type: application/json")
+ Call provisonUser(@Header("Ocp-Apim-Subscription-Key") String key,
+ @Header("X-Reference-Id") String token,
+ @Body NewUser body);
- /**
- * Get Account Balance
- */
- @Headers("Content-Type: application/json")
- @GET("/collection/v1_0/account/balance")
- Call getBalance();
- @GET("/collection/v1_0/requesttopay/{transaction_id}")
- @Headers("Content-Type: application/json")
- Call getTransactionStatus(@Path("transaction_id") String transaction_id);
+ /**
+ * getUser.
+ *
+ * @param token String
+ * @param key String
+ * @return User
+ */
+ @POST("https://ericssonbasicapi2.azure-api.net/v1_0/apiuser/{token}/apikey")
+ @Headers("Content-Type: application/json")
+ Call getUser(@Path("token") String token,
+ @Header("Ocp-Apim-Subscription-Key") String key);
}
diff --git a/src/main/java/ug/sparkpl/momoapi/network/collections/CollectionsAuthorizationInterceptor.java b/src/main/java/ug/sparkpl/momoapi/network/collections/CollectionsAuthorizationInterceptor.java
index a1c6244..78d7969 100644
--- a/src/main/java/ug/sparkpl/momoapi/network/collections/CollectionsAuthorizationInterceptor.java
+++ b/src/main/java/ug/sparkpl/momoapi/network/collections/CollectionsAuthorizationInterceptor.java
@@ -1,135 +1,189 @@
package ug.sparkpl.momoapi.network.collections;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import ug.sparkpl.momoapi.models.AccessToken;
+import ug.sparkpl.momoapi.network.MomoApiException;
+import ug.sparkpl.momoapi.network.RequestOptions;
+import ug.sparkpl.momoapi.utils.DateTimeTypeConverter;
+
+import org.joda.time.DateTime;
+
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
+
import okhttp3.Credentials;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.logging.HttpLoggingInterceptor;
-import org.joda.time.DateTime;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
-import ug.sparkpl.momoapi.Utils.DateTimeTypeConverter;
-import ug.sparkpl.momoapi.models.AccessToken;
-import ug.sparkpl.momoapi.network.ApiException;
-import ug.sparkpl.momoapi.network.RequestOptions;
-
-import java.io.IOException;
-import java.util.concurrent.TimeUnit;
-import java.util.logging.Level;
-import java.util.logging.Logger;
public class CollectionsAuthorizationInterceptor implements Interceptor {
- Logger logger;
- private CollectionsApiService apiService;
- private CollectionSession session;
- private RequestOptions opts;
+ Logger logger;
+ private CollectionsApiService apiService;
+ private CollectionSession session;
+ private RequestOptions opts;
- public CollectionsAuthorizationInterceptor(CollectionSession session, RequestOptions opts) {
+ /**
+ * CollectionsAuthorizationInterceptor.
+ *
+ * @param session CollectionSession
+ * @param opts RequestOptions
+ */
+ public CollectionsAuthorizationInterceptor(CollectionSession session, RequestOptions opts) {
- this.session = session;
- this.opts = opts;
- this.logger = Logger.getLogger(CollectionsAuthorizationInterceptor.class.getName());
+ this.session = session;
+ this.opts = opts;
+ this.logger = Logger.getLogger(CollectionsAuthorizationInterceptor.class.getName());
- Gson gson = new GsonBuilder()
- .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
- .registerTypeAdapter(DateTime.class, new DateTimeTypeConverter())
- .create();
+ final Gson gson = new GsonBuilder()
+ .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
+ .registerTypeAdapter(DateTime.class, new DateTimeTypeConverter())
+ .create();
- final OkHttpClient.Builder okhttpbuilder = new OkHttpClient.Builder();
+ final OkHttpClient.Builder okhttpbuilder = new OkHttpClient.Builder();
- // Only log in debug mode to avoid leaking sensitive information.
- final HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
- httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
- httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
- okhttpbuilder.addInterceptor(httpLoggingInterceptor);
+ // Only log in debug mode to avoid leaking sensitive information.
+ final HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
+ httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
+ httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
+ okhttpbuilder.addInterceptor(httpLoggingInterceptor);
- okhttpbuilder.connectTimeout(30, TimeUnit.SECONDS);
- okhttpbuilder.readTimeout(30, TimeUnit.SECONDS);
- okhttpbuilder.writeTimeout(30, TimeUnit.SECONDS);
+ okhttpbuilder.connectTimeout(60, TimeUnit.SECONDS);
+ okhttpbuilder.readTimeout(60, TimeUnit.SECONDS);
+ okhttpbuilder.writeTimeout(60, TimeUnit.SECONDS);
- OkHttpClient httpClient = okhttpbuilder
- .build();
+ OkHttpClient httpClient = okhttpbuilder
+ .build();
- Retrofit retrofitClient = new Retrofit.Builder()
- .client(httpClient)
- .baseUrl(this.opts.getBaseUrl())
- .addConverterFactory(GsonConverterFactory.create(gson))
- .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
- .build();
+ Retrofit retrofitClient = new Retrofit.Builder()
+ .client(httpClient)
+ .baseUrl(this.opts.getBaseUrl())
+ .addConverterFactory(GsonConverterFactory.create(gson))
+ .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
+ .build();
- this.apiService = retrofitClient.create(CollectionsApiService.class);
+ this.apiService = retrofitClient.create(CollectionsApiService.class);
- }
+ }
- private Request request(final Request initialRequest) {
+ /**
+ * request wrapper.
+ *
+ * @param initialRequest Request
+ * @return Request
+ */
+ private Request request(final Request initialRequest) {
- this.logger.log(Level.INFO, "Using token >>>>>>>>>>>>>>>>> " + this.session.getToken());
+ this.logger.log(Level.INFO, "Using token >>>>>>>>>>>>>>>>> " + this.session.getToken());
- return initialRequest.newBuilder()
- //.header("Accept", "application/json")
- .addHeader("Authorization", "Bearer " + this.session.getToken())
- .addHeader("Ocp-Apim-Subscription-Key", this.opts.getCollectionPrimaryKey())
- .addHeader("X-Target-Environment", this.opts.getTargetEnvironment())
+ return initialRequest.newBuilder()
+ //.header("Accept", "application/json")
+ .addHeader("Authorization", "Bearer " + this.session.getToken())
+ .addHeader("Ocp-Apim-Subscription-Key", this.opts.getCollectionPrimaryKey())
+ .addHeader("X-Target-Environment", this.opts.getTargetEnvironment())
- .method(initialRequest.method(), initialRequest.body())
- .build();
- }
+ .method(initialRequest.method(), initialRequest.body())
+ .build();
+ }
+
+
+ /**
+ * Intercept.
+ *
+ * @param chain Chain
+ * @return Response
+ * @throws IOException when there is a network error
+ */
+ @Override
+ public okhttp3.Response intercept(Chain chain) throws IOException {
+
+
+ okhttp3.Response mainResponse = chain.proceed(request(chain.request()));
+
+
+ Request mainRequest = chain.request();
- @Override
- public okhttp3.Response intercept(Chain chain) throws IOException {
- okhttp3.Response mainResponse = chain.proceed(request(chain.request()));
- Request mainRequest = chain.request();
+ // if response code is 401 or 403, 'mainRequest' has encountered authentication error
+ if (mainResponse.code() == 401 || mainResponse.code() == 403) {
- // if response code is 401 or 403, 'mainRequest' has encountered authentication error
- if (mainResponse.code() == 401 || mainResponse.code() == 403) {
+ this.logger.log(Level.INFO, "<<<<<<<<<<<<<< loginResponse = this.apiService
+ .getToken(credentials, this.opts.getCollectionPrimaryKey()).execute();
+ if (loginResponse.isSuccessful()) {
+ // login request succeed, new token generated
+ AccessToken token = loginResponse.body();
+ // save the new token
+ this.session.saveToken(token.getToken());
+ // retry the 'mainRequest' which encountered an authentication error
+ // add new token into 'mainRequest' header and request again
+ Request.Builder builder = mainRequest.newBuilder().addHeader("Authorization",
+ "Bearer " + this.session.getToken())
+ .addHeader("Ocp-Apim-Subscription-Key", this.opts.getCollectionPrimaryKey())
+ .addHeader("X-Target-Environment", this.opts.getTargetEnvironment())
+ .method(mainRequest.method(), mainRequest.body());
+ mainResponse = chain.proceed(builder.build());
+ }
+ } else if (mainResponse.code() == 400 || mainResponse.code() == 500
+ || mainResponse.code() == 404) {
+ String error = "";
- String credentials = Credentials.basic(this.opts.getCollectionUserId(), this.opts.getCollectionApiSecret());
- Response loginResponse = this.apiService
- .getToken(credentials, this.opts.getCollectionPrimaryKey()).execute();
+ try {
+ error = mainResponse.body().string();
+ } catch (IllegalStateException e) {
+ this.logger.log(Level.SEVERE, e.toString());
- if (loginResponse.isSuccessful()) {
- // login request succeed, new token generated
- AccessToken token = loginResponse.body();
- // save the new token
- this.session.saveToken(token.getToken());
- // retry the 'mainRequest' which encountered an authentication error
- // add new token into 'mainRequest' header and request again
- Request.Builder builder = mainRequest.newBuilder().addHeader("Authorization", "Bearer " + this.session.getToken())
- .addHeader("Ocp-Apim-Subscription-Key", this.opts.getCollectionPrimaryKey())
- .addHeader("X-Target-Environment", this.opts.getTargetEnvironment()).
- method(mainRequest.method(), mainRequest.body());
- mainResponse = chain.proceed(builder.build());
- }
- } else if (!mainResponse.isSuccessful()) {
+ }
- this.logger.log(Level.INFO, "<<<<<<<<<<<<<<< ETETETET " + mainResponse.code() + " .." + mainResponse.body().string());
+ throw new MomoApiException(error);
- throw new ApiException(mainResponse.body().string());
+
+ } else {
+
+ Integer numRequests = 0;
+
+ while (numRequests < 3) {
+
+ okhttp3.Response r = chain.proceed(chain.request());
+ if (r.isSuccessful()) {
+ return r;
}
+ numRequests++;
+ }
- return mainResponse;
}
+
+
+ return mainResponse;
+
+
+ }
+
}
diff --git a/src/main/java/ug/sparkpl/momoapi/network/collections/CollectionsClient.java b/src/main/java/ug/sparkpl/momoapi/network/collections/CollectionsClient.java
index e800283..4826489 100644
--- a/src/main/java/ug/sparkpl/momoapi/network/collections/CollectionsClient.java
+++ b/src/main/java/ug/sparkpl/momoapi/network/collections/CollectionsClient.java
@@ -1,115 +1,168 @@
package ug.sparkpl.momoapi.network.collections;
-import com.google.gson.FieldNamingPolicy;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+import ug.sparkpl.momoapi.models.AccessToken;
+import ug.sparkpl.momoapi.models.Balance;
+import ug.sparkpl.momoapi.models.RequestToPay;
+import ug.sparkpl.momoapi.models.Transaction;
+import ug.sparkpl.momoapi.network.BaseClient;
+import ug.sparkpl.momoapi.network.RequestOptions;
+
import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
+
import okhttp3.Credentials;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
-import org.joda.time.DateTime;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.converter.scalars.ScalarsConverterFactory;
-import ug.sparkpl.momoapi.Utils.DateTimeTypeConverter;
-import ug.sparkpl.momoapi.models.AccessToken;
-import ug.sparkpl.momoapi.models.Balance;
-import ug.sparkpl.momoapi.models.RequestToPay;
-import ug.sparkpl.momoapi.models.Transaction;
-import ug.sparkpl.momoapi.network.RequestOptions;
-
-import java.io.IOException;
-import java.util.UUID;
-import java.util.concurrent.TimeUnit;
-
-public class CollectionsClient {
-
-
- RequestOptions opts;
- Gson gson;
- private CollectionSession session;
- private CollectionsApiService apiService;
- private OkHttpClient httpClient;
- private Retrofit retrofitClient;
- private Retrofit client;
-
-
- public CollectionsClient(RequestOptions opts) {
- this.opts = opts;
- this.gson = new GsonBuilder()
- .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
- .registerTypeAdapter(DateTime.class, new DateTimeTypeConverter())
- .create();
-
- this.session = new CollectionSession();
-
- final HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
- httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
- httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
-
-
- final OkHttpClient.Builder okhttpbuilder = new OkHttpClient.Builder();
-
- // Only log in debug mode to avoid leaking sensitive information.
-
-
- okhttpbuilder.addInterceptor(new CollectionsAuthorizationInterceptor(this.session, this.opts));
- okhttpbuilder.addInterceptor(httpLoggingInterceptor);
-
-
- okhttpbuilder.connectTimeout(30, TimeUnit.SECONDS);
- okhttpbuilder.readTimeout(30, TimeUnit.SECONDS);
- okhttpbuilder.writeTimeout(30, TimeUnit.SECONDS);
-
-
- this.httpClient = okhttpbuilder
- .build();
-
-
- this.retrofitClient = new Retrofit.Builder()
- .client(this.httpClient)
- .baseUrl(opts.getBaseUrl())
- .addConverterFactory(GsonConverterFactory.create(gson))
- .addConverterFactory(ScalarsConverterFactory.create())
- .build();
-
- this.apiService = this.retrofitClient.create(CollectionsApiService.class);
-
- }
+public class CollectionsClient extends BaseClient {
- public AccessToken getToken() throws IOException {
- String credentials = Credentials.basic(this.opts.getCollectionUserId(), this.opts.getCollectionApiSecret());
- Response token = this.apiService
- .getToken(credentials, this.opts.getCollectionPrimaryKey()).execute();
+ RequestOptions opts;
+ Gson gson;
+ private CollectionSession session;
+ private CollectionsApiService apiService;
+ private OkHttpClient httpClient;
+ private Retrofit retrofitClient;
+ private Retrofit client;
- return token.body();
- }
+ /**
+ * CollectionsClient.
+ *
+ * @param opts RequestOptions
+ */
+ public CollectionsClient(RequestOptions opts) {
+ this.opts = opts;
+ this.gson = getGson();
- public Balance getBalance() throws IOException {
- Response balance = this.apiService
- .getBalance().execute();
- return balance.body();
+ this.session = new CollectionSession();
- }
+ final HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
+ httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
+ httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
- public Transaction getTransactionStatus(String ref) throws IOException {
- Response transaction = this.apiService
- .getTransactionStatus(ref).execute();
- return transaction.body();
- }
+ final OkHttpClient.Builder okhttpbuilder = new OkHttpClient.Builder();
+ // Only log in debug mode to avoid leaking sensitive information.
- public String requestToPay(String mobile, String amount, String external_id, String payee_note, String payer_message, String currency) throws IOException {
- RequestToPay rBody = new RequestToPay(mobile, amount, external_id, payee_note, payer_message, currency);
- String ref = UUID.randomUUID().toString();
- this.apiService.requestToPay(rBody, ref).execute();
- return ref;
- }
+ okhttpbuilder.addInterceptor(new CollectionsAuthorizationInterceptor(this.session, this.opts));
+ okhttpbuilder.addInterceptor(httpLoggingInterceptor);
+
+
+ okhttpbuilder.connectTimeout(60, TimeUnit.SECONDS);
+ okhttpbuilder.readTimeout(60, TimeUnit.SECONDS);
+ okhttpbuilder.writeTimeout(60, TimeUnit.SECONDS);
+
+
+ this.httpClient = okhttpbuilder
+ .build();
+
+
+ this.retrofitClient = new Retrofit.Builder()
+ .client(this.httpClient)
+ .baseUrl(opts.getBaseUrl())
+ .addConverterFactory(GsonConverterFactory.create(gson))
+ .addConverterFactory(ScalarsConverterFactory.create())
+ .build();
+
+ this.apiService = this.retrofitClient.create(CollectionsApiService.class);
+
+
+ }
+
+
+ /**
+ * get access Token.
+ *
+ * @return AccessToken
+ * @throws IOException when there is a network error
+ */
+ public AccessToken getToken() throws IOException {
+ String credentials = Credentials.basic(this.opts.getCollectionUserId(),
+ this.opts.getCollectionApiSecret());
+ Response token = this.apiService
+ .getToken(credentials, this.opts.getCollectionPrimaryKey()).execute();
+
+ return token.body();
+ }
+
+
+ /**
+ * get Account Balance.
+ *
+ * @return Balance
+ * @throws IOException when there is a network error
+ */
+ public Balance getBalance() throws IOException {
+ Response balance = this.apiService
+ .getBalance().execute();
+ return balance.body();
+
+ }
+
+ /**
+ * get Transaction.
+ *
+ * @param ref String
+ * @return Transaction
+ * @throws IOException when there is a network error
+ */
+ public Transaction getTransaction(String ref) throws IOException {
+ Response transaction = this.apiService
+ .getTransactionStatus(ref).execute();
+ return transaction.body();
+
+ }
+
+
+ /**
+ * Request To Pay.
+ *
+ * @param mobile String
+ * @param amount String
+ * @param externalId String
+ * @param payeeNote String
+ * @param payerMessage String
+ * @param currency String
+ * @return String
+ * @throws IOException when there is a network error
+ */
+ public String requestToPay(String mobile, String amount, String externalId, String payeeNote,
+ String payerMessage, String currency) throws IOException {
+ RequestToPay rbody = new RequestToPay(mobile, amount, externalId,
+ payeeNote, payerMessage, currency);
+ String ref = UUID.randomUUID().toString();
+ this.apiService.requestToPay(rbody, ref).execute();
+ return ref;
+
+ }
+
+ /**
+ * Request To Pay.
+ *
+ * @param opts HashMap
+ * @return String
+ * @throws IOException when there is a network error
+ */
+ public String requestToPay(HashMap opts) throws IOException {
+ RequestToPay rbody = new RequestToPay(opts.get("mobile"), opts.get("amount"),
+ opts.get("externalId"), opts.get("payeeNote"), opts.get("payerMessage"),
+ opts.getOrDefault("currency", this.opts.getCurrency()));
+ String ref = UUID.randomUUID().toString();
+ this.apiService.requestToPay(rbody, ref).execute();
+ return ref;
+
+ }
}
diff --git a/src/main/java/ug/sparkpl/momoapi/network/disbursements/DisbursementsApiService.java b/src/main/java/ug/sparkpl/momoapi/network/disbursements/DisbursementsApiService.java
index b54cd30..cffbc7d 100644
--- a/src/main/java/ug/sparkpl/momoapi/network/disbursements/DisbursementsApiService.java
+++ b/src/main/java/ug/sparkpl/momoapi/network/disbursements/DisbursementsApiService.java
@@ -1,35 +1,76 @@
package ug.sparkpl.momoapi.network.disbursements;
+import ug.sparkpl.momoapi.models.AccessToken;
+import ug.sparkpl.momoapi.models.Account;
+import ug.sparkpl.momoapi.models.Balance;
+import ug.sparkpl.momoapi.models.Transaction;
+import ug.sparkpl.momoapi.models.Transfer;
+
import retrofit2.Call;
-import retrofit2.http.*;
-import ug.sparkpl.momoapi.models.*;
+import retrofit2.http.Body;
+import retrofit2.http.GET;
+import retrofit2.http.Header;
+import retrofit2.http.Headers;
+import retrofit2.http.POST;
+import retrofit2.http.Path;
public interface DisbursementsApiService {
- @POST("/disbursement/v1_0/transfer")
- @Headers("Content-Type: application/json")
- Call transfer(@Body Transfer body, @Header("X-Reference-Id") String ref);
+ /**
+ * transfer request.
+ *
+ * @param body Transfer
+ * @param ref String
+ * @return Void
+ */
+ @POST("/disbursement/v1_0/transfer")
+ @Headers("Content-Type: application/json")
+ Call transfer(@Body Transfer body, @Header("X-Reference-Id") String ref);
- @POST("/disbursement/token/")
- @Headers("Content-Type: application/json")
- Call getToken(@Header("Authorization") String credentials, @Header("Ocp-Apim-Subscription-Key") String subscriptionKey);
+ /**
+ * getToken.
+ *
+ * @param credentials String
+ * @param subscriptionKey String
+ * @return AccessToken
+ */
+ @POST("/disbursement/token/")
+ @Headers("Content-Type: application/json")
+ Call getToken(@Header("Authorization") String credentials,
+ @Header("Ocp-Apim-Subscription-Key") String subscriptionKey);
- /**
- * Get Account Balance
- */
- @Headers("Content-Type: application/json")
- @GET("/disbursement/v1_0/account/balance")
- Call getBalance();
+ /**
+ * Get Account Balance.
+ *
+ * @return Balance
+ */
+ @Headers("Content-Type: application/json")
+ @GET("/disbursement/v1_0/account/balance")
+ Call getBalance();
- @GET("/disbursement/v1_0/transfer/{transaction_id}")
- @Headers("Content-Type: application/json")
- Call getTransactionStatus(@Path("transaction_id") String transaction_id);
+ /**
+ * getTransactionStatus.
+ *
+ * @param transactionId String
+ * @return Transaction
+ */
+ @GET("/disbursement/v1_0/transfer/{transactionId}")
+ @Headers("Content-Type: application/json")
+ Call getTransactionStatus(@Path("transactionId") String transactionId);
- @GET("/v1_0/accountholder/{accountHolderIdType}/{accountHolderId}/active")
- @Headers("Content-Type: application/json")
- Call isActive(@Path("accountHolderIdType") String accountHolderIdType, @Path("accountHolderId") String accountHolderId);
+ /**
+ * isActive.
+ *
+ * @param accountHolderIdType String
+ * @param accountHolderId String
+ * @return Account
+ */
+ @GET("/v1_0/accountholder/{accountHolderIdType}/{accountHolderId}/active")
+ @Headers("Content-Type: application/json")
+ Call isActive(@Path("accountHolderIdType") String accountHolderIdType,
+ @Path("accountHolderId") String accountHolderId);
}
diff --git a/src/main/java/ug/sparkpl/momoapi/network/disbursements/DisbursementsAuthorizationInterceptor.java b/src/main/java/ug/sparkpl/momoapi/network/disbursements/DisbursementsAuthorizationInterceptor.java
index dc5dfdf..e4812f2 100644
--- a/src/main/java/ug/sparkpl/momoapi/network/disbursements/DisbursementsAuthorizationInterceptor.java
+++ b/src/main/java/ug/sparkpl/momoapi/network/disbursements/DisbursementsAuthorizationInterceptor.java
@@ -1,135 +1,184 @@
package ug.sparkpl.momoapi.network.disbursements;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import ug.sparkpl.momoapi.models.AccessToken;
+import ug.sparkpl.momoapi.network.MomoApiException;
+import ug.sparkpl.momoapi.network.RequestOptions;
+import ug.sparkpl.momoapi.utils.DateTimeTypeConverter;
+
+import org.joda.time.DateTime;
+
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
+
import okhttp3.Credentials;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.logging.HttpLoggingInterceptor;
-import org.joda.time.DateTime;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
-import ug.sparkpl.momoapi.Utils.DateTimeTypeConverter;
-import ug.sparkpl.momoapi.models.AccessToken;
-import ug.sparkpl.momoapi.network.ApiException;
-import ug.sparkpl.momoapi.network.RequestOptions;
-
-import java.io.IOException;
-import java.util.concurrent.TimeUnit;
-import java.util.logging.Level;
-import java.util.logging.Logger;
public class DisbursementsAuthorizationInterceptor implements Interceptor {
- Logger logger;
- private DisbursementsApiService apiService;
- private DisbursementsSession session;
- private RequestOptions opts;
+ Logger logger;
+ private DisbursementsApiService apiService;
+ private DisbursementsSession session;
+ private RequestOptions opts;
- public DisbursementsAuthorizationInterceptor(DisbursementsSession session, RequestOptions opts) {
+ /**
+ * DisbursementsAuthorizationInterceptor.
+ *
+ * @param session DisbursementsSession
+ * @param opts RequestOptions
+ */
+ public DisbursementsAuthorizationInterceptor(DisbursementsSession session, RequestOptions opts) {
- this.session = session;
- this.opts = opts;
- this.logger = Logger.getLogger(DisbursementsAuthorizationInterceptor.class.getName());
+ this.session = session;
+ this.opts = opts;
+ this.logger = Logger.getLogger(DisbursementsAuthorizationInterceptor.class.getName());
- Gson gson = new GsonBuilder()
- .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
- .registerTypeAdapter(DateTime.class, new DateTimeTypeConverter())
- .create();
+ final Gson gson = new GsonBuilder()
+ .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
+ .registerTypeAdapter(DateTime.class, new DateTimeTypeConverter())
+ .create();
- final OkHttpClient.Builder okhttpbuilder = new OkHttpClient.Builder();
+ final OkHttpClient.Builder okhttpbuilder = new OkHttpClient.Builder();
- // Only log in debug mode to avoid leaking sensitive information.
- final HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
- httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
- httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
- okhttpbuilder.addInterceptor(httpLoggingInterceptor);
+ // Only log in debug mode to avoid leaking sensitive information.
+ final HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
+ httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
+ httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
+ okhttpbuilder.addInterceptor(httpLoggingInterceptor);
- okhttpbuilder.connectTimeout(30, TimeUnit.SECONDS);
- okhttpbuilder.readTimeout(30, TimeUnit.SECONDS);
- okhttpbuilder.writeTimeout(30, TimeUnit.SECONDS);
+ okhttpbuilder.connectTimeout(60, TimeUnit.SECONDS);
+ okhttpbuilder.readTimeout(60, TimeUnit.SECONDS);
+ okhttpbuilder.writeTimeout(60, TimeUnit.SECONDS);
- OkHttpClient httpClient = okhttpbuilder
- .build();
+ OkHttpClient httpClient = okhttpbuilder
+ .build();
- Retrofit retrofitClient = new Retrofit.Builder()
- .client(httpClient)
- .baseUrl(this.opts.getBaseUrl())
- .addConverterFactory(GsonConverterFactory.create(gson))
- .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
- .build();
+ Retrofit retrofitClient = new Retrofit.Builder()
+ .client(httpClient)
+ .baseUrl(this.opts.getBaseUrl())
+ .addConverterFactory(GsonConverterFactory.create(gson))
+ .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
+ .build();
- this.apiService = retrofitClient.create(DisbursementsApiService.class);
+ this.apiService = retrofitClient.create(DisbursementsApiService.class);
- }
+ }
- private Request request(final Request initialRequest) {
+ /**
+ * request wrapper.
+ *
+ * @param initialRequest Request
+ * @return Request
+ */
+ private Request request(final Request initialRequest) {
- this.logger.log(Level.INFO, "Using token >>>>>>>>>>>>>>>>> " + this.session.getToken());
+ this.logger.log(Level.INFO, "Using token >>>>>>>>>>>>>>>>> " + this.session.getToken());
- return initialRequest.newBuilder()
- //.header("Accept", "application/json")
- .addHeader("Authorization", "Bearer " + this.session.getToken())
- .addHeader("Ocp-Apim-Subscription-Key", this.opts.getDisbursementPrimaryKey())
- .addHeader("X-Target-Environment", this.opts.getTargetEnvironment())
+ return initialRequest.newBuilder()
+ //.header("Accept", "application/json")
+ .addHeader("Authorization", "Bearer " + this.session.getToken())
+ .addHeader("Ocp-Apim-Subscription-Key", this.opts.getDisbursementPrimaryKey())
+ .addHeader("X-Target-Environment", this.opts.getTargetEnvironment())
- .method(initialRequest.method(), initialRequest.body())
- .build();
- }
+ .method(initialRequest.method(), initialRequest.body())
+ .build();
+ }
- @Override
- public okhttp3.Response intercept(Chain chain) throws IOException {
- okhttp3.Response mainResponse = chain.proceed(request(chain.request()));
- Request mainRequest = chain.request();
+ /**
+ * Intercept.
+ *
+ * @param chain Chain
+ * @return Response
+ * @throws IOException when there is a network error
+ */
+ @Override
+ public okhttp3.Response intercept(Chain chain) throws IOException {
+ okhttp3.Response mainResponse = chain.proceed(request(chain.request()));
+ Request mainRequest = chain.request();
- // if response code is 401 or 403, 'mainRequest' has encountered authentication error
- if (mainResponse.code() == 401 || mainResponse.code() == 403) {
+ // if response code is 401 or 403, 'mainRequest' has encountered authentication error
+ if (mainResponse.code() == 401 || mainResponse.code() == 403) {
- this.logger.log(Level.INFO, "<<<<<<<<<<<<<< loginResponse = this.apiService
- .getToken(credentials, this.opts.getDisbursementPrimaryKey()).execute();
+ String credentials = Credentials.basic(this.opts.getDisbursementUserId(),
+ this.opts.getDisbursementApiSecret());
+ Response loginResponse = this.apiService
+ .getToken(credentials, this.opts.getDisbursementPrimaryKey()).execute();
- if (loginResponse.isSuccessful()) {
- // login request succeed, new token generated
- AccessToken token = loginResponse.body();
- // save the new token
- this.session.saveToken(token.getToken());
- // retry the 'mainRequest' which encountered an authentication error
- // add new token into 'mainRequest' header and request again
- Request.Builder builder = mainRequest.newBuilder().addHeader("Authorization", "Bearer " + this.session.getToken())
- .addHeader("Ocp-Apim-Subscription-Key", this.opts.getDisbursementPrimaryKey())
- .addHeader("X-Target-Environment", this.opts.getTargetEnvironment()).
- method(mainRequest.method(), mainRequest.body());
- mainResponse = chain.proceed(builder.build());
- }
- } else if (!mainResponse.isSuccessful()) {
+ if (loginResponse.isSuccessful()) {
+ // login request succeed, new token generated
+ AccessToken token = loginResponse.body();
+ // save the new token
+ this.session.saveToken(token.getToken());
+ // retry the 'mainRequest' which encountered an authentication error
+ // add new token into 'mainRequest' header and request again
+ Request.Builder builder = mainRequest.newBuilder().addHeader("Authorization",
+ "Bearer " + this.session.getToken())
+ .addHeader("Ocp-Apim-Subscription-Key", this.opts.getDisbursementPrimaryKey())
+ .addHeader("X-Target-Environment", this.opts.getTargetEnvironment())
+ .method(mainRequest.method(), mainRequest.body());
+ mainResponse = chain.proceed(builder.build());
- this.logger.log(Level.INFO, "<<<<<<<<<<<<<<< ETETETET " + mainResponse.code() + " .." + mainResponse.body().string());
+ }
+ } else if (mainResponse.code() == 400 || mainResponse.code() == 500
+ || mainResponse.code() == 404) {
+ String error = "";
- throw new ApiException(mainResponse.body().string());
+ try {
+ error = mainResponse.body().string();
+ } catch (IllegalStateException e) {
+ this.logger.log(Level.SEVERE, e.toString());
+
+ }
+
+
+ throw new MomoApiException(error);
- }
+ } else {
- return mainResponse;
+ Integer numRequests = 0;
+
+ while (numRequests < 3) {
+
+ okhttp3.Response r = chain.proceed(chain.request());
+ if (r.isSuccessful()) {
+ return r;
+
+
+ }
+
+ numRequests++;
+ }
}
+
+
+ return mainResponse;
+ }
}
diff --git a/src/main/java/ug/sparkpl/momoapi/network/disbursements/DisbursementsClient.java b/src/main/java/ug/sparkpl/momoapi/network/disbursements/DisbursementsClient.java
index 6c0399e..d97d055 100644
--- a/src/main/java/ug/sparkpl/momoapi/network/disbursements/DisbursementsClient.java
+++ b/src/main/java/ug/sparkpl/momoapi/network/disbursements/DisbursementsClient.java
@@ -1,118 +1,169 @@
package ug.sparkpl.momoapi.network.disbursements;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+import ug.sparkpl.momoapi.models.AccessToken;
+import ug.sparkpl.momoapi.models.Balance;
+import ug.sparkpl.momoapi.models.Transaction;
+import ug.sparkpl.momoapi.models.Transfer;
+import ug.sparkpl.momoapi.network.RequestOptions;
+import ug.sparkpl.momoapi.utils.DateTimeTypeConverter;
+
+import org.joda.time.DateTime;
+
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
+
import okhttp3.Credentials;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
-import org.joda.time.DateTime;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.converter.scalars.ScalarsConverterFactory;
-import ug.sparkpl.momoapi.Utils.DateTimeTypeConverter;
-import ug.sparkpl.momoapi.models.AccessToken;
-import ug.sparkpl.momoapi.models.Balance;
-import ug.sparkpl.momoapi.models.Transaction;
-import ug.sparkpl.momoapi.models.Transfer;
-import ug.sparkpl.momoapi.network.RequestOptions;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.UUID;
-import java.util.concurrent.TimeUnit;
public class DisbursementsClient {
- RequestOptions opts;
- Gson gson;
- private DisbursementsSession session;
- private DisbursementsApiService apiService;
- private OkHttpClient httpClient;
- private Retrofit retrofitClient;
-
- public DisbursementsClient(RequestOptions opts) {
- this.opts = opts;
- this.gson = new GsonBuilder()
- .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
- .registerTypeAdapter(DateTime.class, new DateTimeTypeConverter())
- .create();
-
- this.session = new DisbursementsSession();
-
- final HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
- httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
- httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
-
-
- final OkHttpClient.Builder okhttpbuilder = new OkHttpClient.Builder();
-
- // Only log in debug mode to avoid leaking sensitive information.
-
-
- okhttpbuilder.addInterceptor(new DisbursementsAuthorizationInterceptor(this.session, this.opts));
- okhttpbuilder.addInterceptor(httpLoggingInterceptor);
-
-
- okhttpbuilder.connectTimeout(30, TimeUnit.SECONDS);
- okhttpbuilder.readTimeout(30, TimeUnit.SECONDS);
- okhttpbuilder.writeTimeout(30, TimeUnit.SECONDS);
-
-
- this.httpClient = okhttpbuilder
- .build();
-
-
- this.retrofitClient = new Retrofit.Builder()
- .client(this.httpClient)
- .baseUrl(opts.getBaseUrl())
- .addConverterFactory(GsonConverterFactory.create(gson))
- .addConverterFactory(ScalarsConverterFactory.create())
- .build();
-
- this.apiService = this.retrofitClient.create(DisbursementsApiService.class);
-
-
- }
-
-
- public AccessToken getToken() throws IOException {
- String credentials = Credentials.basic(this.opts.getDisbursementUserId(), this.opts.getDisbursementApiSecret());
- Response token = this.apiService
- .getToken(credentials, this.opts.getDisbursementPrimaryKey()).execute();
- return token.body();
- }
-
- public Balance getBalance() throws IOException {
- Response balance = this.apiService
- .getBalance().execute();
- return balance.body();
-
- }
-
- public Transaction getTransactionStatus(String ref) throws IOException {
- Response transaction = this.apiService
- .getTransactionStatus(ref).execute();
- return transaction.body();
-
- }
-
-
- public String transfer(String mobile, String amount, String external_id, String payee_note, String payer_message, String currency) throws IOException {
- Transfer rBody = new Transfer(mobile, amount, external_id, payee_note, payer_message, currency);
- String ref = UUID.randomUUID().toString();
- this.apiService.transfer(rBody, ref).execute();
- return ref;
-
- }
-
-
- public String transfer(HashMap opts) throws IOException {
- Transfer rBody = new Transfer(opts.get("mobile"), opts.get("amount"), opts.get("externalId"), opts.get("payeeNote"), opts.get("payerMessage"), opts.get("currency"));
- String ref = UUID.randomUUID().toString();
- this.apiService.transfer(rBody, ref).execute();
- return ref;
-
- }
+ RequestOptions opts;
+ Gson gson;
+ private DisbursementsSession session;
+ private DisbursementsApiService apiService;
+ private OkHttpClient httpClient;
+ private Retrofit retrofitClient;
+
+ /**
+ * DisbursementsClient.
+ *
+ * @param opts RequestOptions
+ */
+ public DisbursementsClient(RequestOptions opts) {
+ this.opts = opts;
+ this.gson = new GsonBuilder()
+ .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
+ .registerTypeAdapter(DateTime.class, new DateTimeTypeConverter())
+ .create();
+
+ this.session = new DisbursementsSession();
+
+ final HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
+ httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
+ httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
+
+
+ final OkHttpClient.Builder okhttpbuilder = new OkHttpClient.Builder();
+
+ // Only log in debug mode to avoid leaking sensitive information.
+
+
+ okhttpbuilder.addInterceptor(
+ new DisbursementsAuthorizationInterceptor(this.session, this.opts));
+ okhttpbuilder.addInterceptor(httpLoggingInterceptor);
+
+
+ okhttpbuilder.connectTimeout(30, TimeUnit.SECONDS);
+ okhttpbuilder.readTimeout(30, TimeUnit.SECONDS);
+ okhttpbuilder.writeTimeout(30, TimeUnit.SECONDS);
+
+
+ this.httpClient = okhttpbuilder
+ .build();
+
+
+ this.retrofitClient = new Retrofit.Builder()
+ .client(this.httpClient)
+ .baseUrl(opts.getBaseUrl())
+ .addConverterFactory(GsonConverterFactory.create(gson))
+ .addConverterFactory(ScalarsConverterFactory.create())
+ .build();
+
+ this.apiService = this.retrofitClient.create(DisbursementsApiService.class);
+
+
+ }
+
+
+ /**
+ * getToken.
+ *
+ * @return AccessToken
+ * @throws IOException when network error occurs
+ */
+ public AccessToken getToken() throws IOException {
+ String credentials = Credentials.basic(this.opts.getDisbursementUserId(),
+ this.opts.getDisbursementApiSecret());
+ Response token = this.apiService
+ .getToken(credentials, this.opts.getDisbursementPrimaryKey()).execute();
+ return token.body();
+ }
+
+ /**
+ * getBalance.
+ *
+ * @return Balance
+ * @throws IOException when network error occurs
+ */
+ public Balance getBalance() throws IOException {
+ Response balance = this.apiService
+ .getBalance().execute();
+ return balance.body();
+
+ }
+
+ /**
+ * get Transaction.
+ *
+ * @param ref String
+ * @return Transaction
+ * @throws IOException when there is a network error
+ */
+
+ public Transaction getTransaction(String ref) throws IOException {
+ Response transaction = this.apiService
+ .getTransactionStatus(ref).execute();
+ return transaction.body();
+
+ }
+
+ /**
+ * transfer money.
+ *
+ * @param mobile String
+ * @param amount String
+ * @param externalId String
+ * @param payeeNote String
+ * @param payerMessage String
+ * @param currency String
+ * @return String
+ * @throws IOException when there is a network error
+ */
+ public String transfer(String mobile, String amount,
+ String externalId, String payeeNote,
+ String payerMessage, String currency) throws IOException {
+ Transfer rbody = new Transfer(mobile, amount, externalId, payeeNote, payerMessage, currency);
+ String ref = UUID.randomUUID().toString();
+ this.apiService.transfer(rbody, ref).execute();
+ return ref;
+
+ }
+
+ /**
+ * transfer money.
+ *
+ * @param opts HashMap
+ * @return String
+ * @throws IOException when there is a network error
+ */
+ public String transfer(HashMap opts) throws IOException {
+ Transfer rbody = new Transfer(opts.get("mobile"), opts.get("amount"),
+ opts.get("externalId"), opts.get("payeeNote"),
+ opts.get("payerMessage"), opts.getOrDefault("currency", this.opts.getCurrency()));
+ String ref = UUID.randomUUID().toString();
+ this.apiService.transfer(rbody, ref).execute();
+ return ref;
+
+ }
}
diff --git a/src/main/java/ug/sparkpl/momoapi/network/disbursements/DisbursementsSession.java b/src/main/java/ug/sparkpl/momoapi/network/disbursements/DisbursementsSession.java
index acea8e4..b63f1a1 100644
--- a/src/main/java/ug/sparkpl/momoapi/network/disbursements/DisbursementsSession.java
+++ b/src/main/java/ug/sparkpl/momoapi/network/disbursements/DisbursementsSession.java
@@ -3,27 +3,27 @@
import java.util.prefs.Preferences;
public class DisbursementsSession {
- String TOKEN_NAME = "DISBURSEMENT_TOKEN";
- private String token;
- private Preferences prefs;
+ String TOKEN_NAME = "DISBURSEMENT_TOKEN";
+ private String token;
+ private Preferences prefs;
- public DisbursementsSession() {
- this.prefs = Preferences.userRoot().node(this.getClass().getName());
- }
+ public DisbursementsSession() {
+ this.prefs = Preferences.userRoot().node(this.getClass().getName());
+ }
- public void saveToken(String token) {
- prefs.put(TOKEN_NAME, token);
- }
+ public void saveToken(String token) {
+ prefs.put(TOKEN_NAME, token);
+ }
- public String getToken() {
- // return the token that was saved earlier
- return prefs.get(TOKEN_NAME, "rando");
- }
+ public String getToken() {
+ // return the token that was saved earlier
+ return prefs.get(TOKEN_NAME, "dummy");
+ }
- public void invalidate() {
+ public void invalidate() {
- }
+ }
}
diff --git a/src/main/java/ug/sparkpl/momoapi/network/remittances/RemittancesApiService.java b/src/main/java/ug/sparkpl/momoapi/network/remittances/RemittancesApiService.java
index c1ed656..220a4c6 100644
--- a/src/main/java/ug/sparkpl/momoapi/network/remittances/RemittancesApiService.java
+++ b/src/main/java/ug/sparkpl/momoapi/network/remittances/RemittancesApiService.java
@@ -1,33 +1,60 @@
package ug.sparkpl.momoapi.network.remittances;
-import retrofit2.Call;
-import retrofit2.http.*;
import ug.sparkpl.momoapi.models.AccessToken;
import ug.sparkpl.momoapi.models.Balance;
import ug.sparkpl.momoapi.models.Transaction;
import ug.sparkpl.momoapi.models.Transfer;
-public interface RemittancesApiService {
-
- @POST("/remittance/v1_0/transfer/")
- @Headers("Content-Type: application/json")
- Call transfer(@Body Transfer body, @Header("X-Reference-Id") String ref);
-
-
- @POST("/remittance/token/")
- @Headers("Content-Type: application/json")
- Call getToken(@Header("Authorization") String credentials, @Header("Ocp-Apim-Subscription-Key") String subscriptionKey);
-
- /**
- * Get Account Balance
- */
- @Headers("Content-Type: application/json")
- @GET("/remittance/v1_0/account/balance")
- Call getBalance();
+import retrofit2.Call;
+import retrofit2.http.Body;
+import retrofit2.http.GET;
+import retrofit2.http.Header;
+import retrofit2.http.Headers;
+import retrofit2.http.POST;
+import retrofit2.http.Path;
+public interface RemittancesApiService {
- @GET("/remittance/v1_0/transfer/{transaction_id}")
- @Headers("Content-Type: application/json")
- Call getTransactionStatus(@Path("transaction_id") String transaction_id);
+ /**
+ * transfer money.
+ *
+ * @param body Transfer
+ * @param ref String
+ * @return Void
+ */
+ @POST("/remittance/v1_0/transfer/")
+ @Headers("Content-Type: application/json")
+ Call transfer(@Body Transfer body, @Header("X-Reference-Id") String ref);
+
+ /**
+ * get Token.
+ *
+ * @param credentials String
+ * @param subscriptionKey String
+ * @return AccessToken
+ */
+ @POST("/remittance/token/")
+ @Headers("Content-Type: application/json")
+ Call getToken(@Header("Authorization") String credentials,
+ @Header("Ocp-Apim-Subscription-Key") String subscriptionKey);
+
+ /**
+ * Get Account Balance.
+ *
+ * @return Balance
+ */
+ @Headers("Content-Type: application/json")
+ @GET("/remittance/v1_0/account/balance")
+ Call getBalance();
+
+ /**
+ * GetTransaction Status.
+ *
+ * @param transactionId String
+ * @return Transaction
+ */
+ @GET("/remittance/v1_0/transfer/{transactionId}")
+ @Headers("Content-Type: application/json")
+ Call getTransactionStatus(@Path("transaction_id") String transactionId);
}
diff --git a/src/main/java/ug/sparkpl/momoapi/network/remittances/RemittancesAuthorizationInterceptor.java b/src/main/java/ug/sparkpl/momoapi/network/remittances/RemittancesAuthorizationInterceptor.java
index 5e92a3c..f9f01a6 100644
--- a/src/main/java/ug/sparkpl/momoapi/network/remittances/RemittancesAuthorizationInterceptor.java
+++ b/src/main/java/ug/sparkpl/momoapi/network/remittances/RemittancesAuthorizationInterceptor.java
@@ -1,133 +1,177 @@
package ug.sparkpl.momoapi.network.remittances;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import ug.sparkpl.momoapi.models.AccessToken;
+import ug.sparkpl.momoapi.network.MomoApiException;
+import ug.sparkpl.momoapi.network.RequestOptions;
+import ug.sparkpl.momoapi.utils.DateTimeTypeConverter;
+
+import org.joda.time.DateTime;
+
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
+
import okhttp3.Credentials;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.logging.HttpLoggingInterceptor;
-import org.joda.time.DateTime;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
-import ug.sparkpl.momoapi.Utils.DateTimeTypeConverter;
-import ug.sparkpl.momoapi.models.AccessToken;
-import ug.sparkpl.momoapi.network.ApiException;
-import ug.sparkpl.momoapi.network.RequestOptions;
-
-import java.io.IOException;
-import java.util.concurrent.TimeUnit;
-import java.util.logging.Level;
-import java.util.logging.Logger;
public class RemittancesAuthorizationInterceptor implements Interceptor {
- Logger logger;
- private RemittancesApiService apiService;
- private RemittancesSession session;
- private RequestOptions opts;
+ Logger logger;
+ private RemittancesApiService apiService;
+ private RemittancesSession session;
+ private RequestOptions opts;
- public RemittancesAuthorizationInterceptor(RemittancesSession session, RequestOptions opts) {
+ /**
+ * RemittancesAuthorizationInterceptor.
+ *
+ * @param session RemittancesSession
+ * @param opts RequestOptions
+ */
+ public RemittancesAuthorizationInterceptor(RemittancesSession session, RequestOptions opts) {
- this.session = session;
- this.opts = opts;
- this.logger = Logger.getLogger(RemittancesAuthorizationInterceptor.class.getName());
+ this.session = session;
+ this.opts = opts;
+ this.logger = Logger.getLogger(RemittancesAuthorizationInterceptor.class.getName());
- Gson gson = new GsonBuilder()
- .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
- .registerTypeAdapter(DateTime.class, new DateTimeTypeConverter())
- .create();
+ final Gson gson = new GsonBuilder()
+ .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
+ .registerTypeAdapter(DateTime.class, new DateTimeTypeConverter())
+ .create();
- final OkHttpClient.Builder okhttpbuilder = new OkHttpClient.Builder();
+ final OkHttpClient.Builder okhttpbuilder = new OkHttpClient.Builder();
- // Only log in debug mode to avoid leaking sensitive information.
- final HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
- httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
- httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
- okhttpbuilder.addInterceptor(httpLoggingInterceptor);
+ // Only log in debug mode to avoid leaking sensitive information.
+ final HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
+ httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
+ httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
+ okhttpbuilder.addInterceptor(httpLoggingInterceptor);
- okhttpbuilder.connectTimeout(30, TimeUnit.SECONDS);
- okhttpbuilder.readTimeout(30, TimeUnit.SECONDS);
- okhttpbuilder.writeTimeout(30, TimeUnit.SECONDS);
+ okhttpbuilder.connectTimeout(30, TimeUnit.SECONDS);
+ okhttpbuilder.readTimeout(30, TimeUnit.SECONDS);
+ okhttpbuilder.writeTimeout(30, TimeUnit.SECONDS);
- OkHttpClient httpClient = okhttpbuilder
- .build();
+ OkHttpClient httpClient = okhttpbuilder
+ .build();
- Retrofit retrofitClient = new Retrofit.Builder()
- .client(httpClient)
- .baseUrl(this.opts.getBaseUrl())
- .addConverterFactory(GsonConverterFactory.create(gson))
- .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
- .build();
+ Retrofit retrofitClient = new Retrofit.Builder()
+ .client(httpClient)
+ .baseUrl(this.opts.getBaseUrl())
+ .addConverterFactory(GsonConverterFactory.create(gson))
+ .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
+ .build();
- this.apiService = retrofitClient.create(RemittancesApiService.class);
+ this.apiService = retrofitClient.create(RemittancesApiService.class);
- }
+ }
- private Request request(final Request initialRequest) {
+ /**
+ * method wrapper to add auth headers.
+ *
+ * @param initialRequest Request
+ * @return
+ */
+ private Request request(final Request initialRequest) {
- this.logger.log(Level.INFO, "Using token >>>>>>>>>>>>>>>>> " + this.session.getToken());
+ this.logger.log(Level.INFO, "Using token >>>>>>>>>>>>>>>>> " + this.session.getToken());
- return initialRequest.newBuilder()
- //.header("Accept", "application/json")
- .addHeader("Authorization", "Bearer " + this.session.getToken())
- .addHeader("Ocp-Apim-Subscription-Key", this.opts.getRemittancePrimaryKey())
- .addHeader("X-Target-Environment", this.opts.getTargetEnvironment())
+ return initialRequest.newBuilder()
+ //.header("Accept", "application/json")
+ .addHeader("Authorization", "Bearer " + this.session.getToken())
+ .addHeader("Ocp-Apim-Subscription-Key", this.opts.getRemittancePrimaryKey())
+ .addHeader("X-Target-Environment", this.opts.getTargetEnvironment())
- .method(initialRequest.method(), initialRequest.body())
- .build();
- }
+ .method(initialRequest.method(), initialRequest.body())
+ .build();
+ }
- @Override
- public okhttp3.Response intercept(Chain chain) throws IOException {
- okhttp3.Response mainResponse = chain.proceed(request(chain.request()));
- Request mainRequest = chain.request();
+ /**
+ * intercept http request.
+ *
+ * @param chain Chain
+ * @return Response
+ * @throws IOException when network error
+ */
+ @Override
+ public okhttp3.Response intercept(Chain chain) throws IOException {
+ okhttp3.Response mainResponse = chain.proceed(request(chain.request()));
+ Request mainRequest = chain.request();
- // if response code is 401 or 403, 'mainRequest' has encountered authentication error
- if (mainResponse.code() == 401 || mainResponse.code() == 403) {
+ // if response code is 401 or 403, 'mainRequest' has encountered authentication error
+ if (mainResponse.code() == 401 || mainResponse.code() == 403) {
- this.logger.log(Level.INFO, "<<<<<<<<<<<<<< loginResponse = this.apiService
- .getToken(credentials, this.opts.getRemittancePrimaryKey()).execute();
+ String credentials = Credentials.basic(this.opts.getRemittanceUserId(),
+ this.opts.getRemittanceApiSecret());
+ Response loginResponse = this.apiService
+ .getToken(credentials, this.opts.getRemittancePrimaryKey()).execute();
- if (loginResponse.isSuccessful()) {
- // login request succeed, new token generated
- AccessToken token = loginResponse.body();
- // save the new token
- this.session.saveToken(token.getToken());
- // retry the 'mainRequest' which encountered an authentication error
- // add new token into 'mainRequest' header and request again
- Request.Builder builder = mainRequest.newBuilder().addHeader("Authorization", "Bearer " + this.session.getToken())
- .addHeader("Ocp-Apim-Subscription-Key", this.opts.getRemittancePrimaryKey())
- .addHeader("X-Target-Environment", this.opts.getTargetEnvironment()).
- method(mainRequest.method(), mainRequest.body());
- mainResponse = chain.proceed(builder.build());
- }
- } else if (!mainResponse.isSuccessful()) {
+ if (loginResponse.isSuccessful()) {
+ // login request succeed, new token generated
+ AccessToken token = loginResponse.body();
+ // save the new token
+ this.session.saveToken(token.getToken());
+ // retry the 'mainRequest' which encountered an authentication error
+ // add new token into 'mainRequest' header and request again
+ Request.Builder builder = mainRequest.newBuilder().addHeader("Authorization",
+ "Bearer " + this.session.getToken())
+ .addHeader("Ocp-Apim-Subscription-Key", this.opts.getRemittancePrimaryKey())
+ .addHeader("X-Target-Environment", this.opts.getTargetEnvironment())
+ .method(mainRequest.method(), mainRequest.body());
+ mainResponse = chain.proceed(builder.build());
+ }
+ } else if (mainResponse.code() == 400 || mainResponse.code() == 500
+ || mainResponse.code() == 404) {
+ String error = "";
- this.logger.log(Level.INFO, "<<<<<<<<<<<<<<< ETETETET " + mainResponse.code() + " .." + mainResponse.body().string());
+ try {
+ error = mainResponse.body().string();
+ } catch (IllegalStateException e) {
+ this.logger.log(Level.SEVERE, e.toString());
+ }
- throw new ApiException(mainResponse.body().string());
+ throw new MomoApiException(error);
- }
+
+ } else {
+ Integer numRequests = 0;
+
+ while (numRequests < 3) {
+
+ okhttp3.Response r = chain.proceed(chain.request());
+ if (r.isSuccessful()) {
+ return r;
- return mainResponse;
+ }
+
+ numRequests++;
+ }
}
+
+ return mainResponse;
+ }
}
diff --git a/src/main/java/ug/sparkpl/momoapi/network/remittances/RemittancesClient.java b/src/main/java/ug/sparkpl/momoapi/network/remittances/RemittancesClient.java
index 68b817a..10676cb 100644
--- a/src/main/java/ug/sparkpl/momoapi/network/remittances/RemittancesClient.java
+++ b/src/main/java/ug/sparkpl/momoapi/network/remittances/RemittancesClient.java
@@ -1,110 +1,174 @@
package ug.sparkpl.momoapi.network.remittances;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+import ug.sparkpl.momoapi.models.AccessToken;
+import ug.sparkpl.momoapi.models.Balance;
+import ug.sparkpl.momoapi.models.Transaction;
+import ug.sparkpl.momoapi.models.Transfer;
+import ug.sparkpl.momoapi.network.RequestOptions;
+import ug.sparkpl.momoapi.utils.DateTimeTypeConverter;
+
+import org.joda.time.DateTime;
+
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
+
import okhttp3.Credentials;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
-import org.joda.time.DateTime;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.converter.scalars.ScalarsConverterFactory;
-import ug.sparkpl.momoapi.Utils.DateTimeTypeConverter;
-import ug.sparkpl.momoapi.models.AccessToken;
-import ug.sparkpl.momoapi.models.Balance;
-import ug.sparkpl.momoapi.models.Transaction;
-import ug.sparkpl.momoapi.models.Transfer;
-import ug.sparkpl.momoapi.network.RequestOptions;
-
-import java.io.IOException;
-import java.util.UUID;
-import java.util.concurrent.TimeUnit;
public class RemittancesClient {
- RequestOptions opts;
- Gson gson;
- private RemittancesSession session;
- private RemittancesApiService apiService;
- private OkHttpClient httpClient;
- private Retrofit retrofitClient;
-
-
- public RemittancesClient(RequestOptions opts) {
- this.opts = opts;
- this.gson = new GsonBuilder()
- .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
- .registerTypeAdapter(DateTime.class, new DateTimeTypeConverter())
- .create();
-
- this.session = new RemittancesSession();
-
- final HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
- httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
- httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
-
-
- final OkHttpClient.Builder okhttpbuilder = new OkHttpClient.Builder();
-
- // Only log in debug mode to avoid leaking sensitive information.
-
-
- okhttpbuilder.addInterceptor(new RemittancesAuthorizationInterceptor(this.session, this.opts));
- okhttpbuilder.addInterceptor(httpLoggingInterceptor);
-
-
- okhttpbuilder.connectTimeout(30, TimeUnit.SECONDS);
- okhttpbuilder.readTimeout(30, TimeUnit.SECONDS);
- okhttpbuilder.writeTimeout(30, TimeUnit.SECONDS);
-
-
- this.httpClient = okhttpbuilder
- .build();
-
-
- this.retrofitClient = new Retrofit.Builder()
- .client(this.httpClient)
- .baseUrl(opts.getBaseUrl())
- .addConverterFactory(GsonConverterFactory.create(gson))
- .addConverterFactory(ScalarsConverterFactory.create())
- .build();
-
- this.apiService = this.retrofitClient.create(RemittancesApiService.class);
-
-
- }
-
-
- public AccessToken getToken() throws IOException {
- String credentials = Credentials.basic(this.opts.getRemittanceUserId(), this.opts.getRemittanceApiSecret());
- Response token = this.apiService
- .getToken(credentials, this.opts.getRemittancePrimaryKey()).execute();
- return token.body();
- }
-
-
- public Balance getBalance() throws IOException {
- Response balance = this.apiService
- .getBalance().execute();
- return balance.body();
-
- }
-
- public Transaction getTransactionStatus(String ref) throws IOException {
- Response transaction = this.apiService
- .getTransactionStatus(ref).execute();
- return transaction.body();
-
- }
-
+ RequestOptions opts;
+ Gson gson;
+ private RemittancesSession session;
+ private RemittancesApiService apiService;
+ private OkHttpClient httpClient;
+ private Retrofit retrofitClient;
- public String transfer(String mobile, String amount, String external_id, String payee_note, String payer_message, String currency) throws IOException {
- Transfer rBody = new Transfer(mobile, amount, external_id, payee_note, payer_message, currency);
- String ref = UUID.randomUUID().toString();
- this.apiService.transfer(rBody, ref).execute();
- return ref;
- }
+ /**
+ * RemittancesClient.
+ *
+ * @param opts RequestOptions
+ */
+ public RemittancesClient(RequestOptions opts) {
+ this.opts = opts;
+ this.gson = new GsonBuilder()
+ .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
+ .registerTypeAdapter(DateTime.class, new DateTimeTypeConverter())
+ .create();
+
+ this.session = new RemittancesSession();
+
+ final HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
+ httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
+ httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
+
+
+ final OkHttpClient.Builder okhttpbuilder = new OkHttpClient.Builder();
+
+ // Only log in debug mode to avoid leaking sensitive information.
+
+
+ okhttpbuilder.addInterceptor(new RemittancesAuthorizationInterceptor(this.session, this.opts));
+ okhttpbuilder.addInterceptor(httpLoggingInterceptor);
+
+
+ okhttpbuilder.connectTimeout(30, TimeUnit.SECONDS);
+ okhttpbuilder.readTimeout(30, TimeUnit.SECONDS);
+ okhttpbuilder.writeTimeout(30, TimeUnit.SECONDS);
+
+
+ this.httpClient = okhttpbuilder
+ .build();
+
+
+ this.retrofitClient = new Retrofit.Builder()
+ .client(this.httpClient)
+ .baseUrl(opts.getBaseUrl())
+ .addConverterFactory(GsonConverterFactory.create(gson))
+ .addConverterFactory(ScalarsConverterFactory.create())
+ .build();
+
+ this.apiService = this.retrofitClient.create(RemittancesApiService.class);
+
+
+ }
+
+
+ /**
+ * Get access Token.
+ *
+ * @return AccessToken
+ * @throws IOException when network error
+ */
+ public AccessToken getToken() throws IOException {
+ String credentials = Credentials.basic(this.opts.getRemittanceUserId(),
+ this.opts.getRemittanceApiSecret());
+ Response token = this.apiService
+ .getToken(credentials, this.opts.getRemittancePrimaryKey()).execute();
+ return token.body();
+ }
+
+
+ /**
+ * Get account balance.
+ *
+ * @return Balance
+ * @throws IOException when network error
+ */
+ public Balance getBalance() throws IOException {
+ Response balance = this.apiService
+ .getBalance().execute();
+ return balance.body();
+
+ }
+
+ /**
+ * Get transaction.
+ *
+ * @param ref String
+ * @return Transaction
+ * @throws IOException when network error
+ */
+ public Transaction getTransaction(String ref) throws IOException {
+ Response transaction = this.apiService
+ .getTransactionStatus(ref).execute();
+ return transaction.body();
+
+ }
+
+
+ /**
+ * Transfer money.
+ *
+ * @param mobile String
+ * @param amount String
+ * @param externalId String
+ * @param payeeNote String
+ * @param payerMessage String
+ * @param currency String
+ * @return String
+ * @throws IOException when network error
+ */
+ public String transfer(String mobile, String amount,
+ String externalId,
+ String payeeNote,
+ String payerMessage,
+ String currency) throws IOException {
+ Transfer rbody = new Transfer(mobile, amount, externalId,
+ payeeNote, payerMessage, currency);
+ String ref = UUID.randomUUID().toString();
+ this.apiService.transfer(rbody, ref).execute();
+ return ref;
+
+ }
+
+ /**
+ * transfer.
+ *
+ * @param opts String
+ * @return String
+ * @throws IOException when there is a network error
+ */
+ public String transfer(HashMap opts) throws IOException {
+ Transfer rbody = new Transfer(opts.get("mobile"),
+ opts.get("amount"), opts.get("externalId"),
+ opts.get("payeeNote"), opts.get("payerMessage"),
+ opts.getOrDefault("currency", this.opts.getCurrency()));
+ String ref = UUID.randomUUID().toString();
+ this.apiService.transfer(rbody, ref).execute();
+ return ref;
+
+ }
}
diff --git a/src/main/java/ug/sparkpl/momoapi/network/remittances/RemittancesSession.java b/src/main/java/ug/sparkpl/momoapi/network/remittances/RemittancesSession.java
index d51eaef..9f7b978 100644
--- a/src/main/java/ug/sparkpl/momoapi/network/remittances/RemittancesSession.java
+++ b/src/main/java/ug/sparkpl/momoapi/network/remittances/RemittancesSession.java
@@ -3,27 +3,37 @@
import java.util.prefs.Preferences;
public class RemittancesSession {
- String TOKEN_NAME = "REMITTANCE_TOKEN";
- private String token;
- private Preferences prefs;
+ String TOKEN_NAME = "REMITTANCE_TOKEN";
+ private String token;
+ private Preferences prefs;
+
+ /**
+ * RemittancesSession.
+ */
+ public RemittancesSession() {
+ this.prefs = Preferences.userRoot().node(this.getClass().getName());
+ }
+
+
+ /**
+ * Save token.
+ *
+ * @param token String
+ */
+ public void saveToken(String token) {
+ prefs.put(TOKEN_NAME, token);
+ }
+
+
+ /**
+ * get Token.
+ *
+ * @return String
+ */
+ public String getToken() {
+ // return the token that was saved earlier
+ return prefs.get(TOKEN_NAME, "dummy");
+ }
- public RemittancesSession() {
- this.prefs = Preferences.userRoot().node(this.getClass().getName());
- }
-
- public void saveToken(String token) {
- prefs.put(TOKEN_NAME, token);
- }
-
-
- public String getToken() {
- // return the token that was saved earlier
- return prefs.get(TOKEN_NAME, "");
- }
-
-
- public void invalidate() {
-
- }
}
diff --git a/src/main/java/ug/sparkpl/momoapi/utils/DateTimeTypeConverter.java b/src/main/java/ug/sparkpl/momoapi/utils/DateTimeTypeConverter.java
new file mode 100644
index 0000000..fbe1dbf
--- /dev/null
+++ b/src/main/java/ug/sparkpl/momoapi/utils/DateTimeTypeConverter.java
@@ -0,0 +1,29 @@
+package ug.sparkpl.momoapi.utils;
+
+
+import java.lang.reflect.Type;
+
+import org.joda.time.DateTime;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonPrimitive;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+
+import lombok.NonNull;
+
+public class DateTimeTypeConverter implements JsonSerializer, JsonDeserializer {
+ @Override
+ public JsonElement serialize(final @NonNull DateTime src, final @NonNull Type srcType,
+ final @NonNull JsonSerializationContext context) {
+ return new JsonPrimitive(src.getMillis() / 1000);
+ }
+
+ @Override
+ public DateTime deserialize(final @NonNull JsonElement json, final @NonNull Type type,
+ final @NonNull JsonDeserializationContext context) {
+ return new DateTime(json.getAsInt() * 1000L);
+ }
+}
diff --git a/src/test/java/ug/sparkpl/network/BaseTest.java b/src/test/java/ug/sparkpl/network/BaseTest.java
index 0e5e7c4..3ef2d0d 100644
--- a/src/test/java/ug/sparkpl/network/BaseTest.java
+++ b/src/test/java/ug/sparkpl/network/BaseTest.java
@@ -1,41 +1,94 @@
package ug.sparkpl.network;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+import ug.sparkpl.momoapi.utils.DateTimeTypeConverter;
+
+import org.joda.time.DateTime;
+
import com.google.common.base.Charsets;
import com.google.common.base.Throwables;
-import okhttp3.mockwebserver.MockWebServer;
+import com.google.gson.FieldNamingPolicy;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
-import java.io.IOException;
+import okhttp3.OkHttpClient;
+import okhttp3.mockwebserver.MockWebServer;
+import retrofit2.Retrofit;
+import retrofit2.converter.gson.GsonConverterFactory;
+import retrofit2.converter.scalars.ScalarsConverterFactory;
import static org.jclouds.util.Strings2.toStringAndClose;
public class BaseTest {
- public MockWebServer server;
-
- /**
- * Create a MockWebServer.
- *
- * @return instance of MockWebServer
- * @throws IOException if unable to start/play server
- */
- public static MockWebServer mockWebServer() throws IOException {
- final MockWebServer server = new MockWebServer();
- server.start();
- return server;
- }
+ public MockWebServer server;
+
+ /**
+ * Create a MockWebServer.
+ *
+ * @return instance of MockWebServer
+ * @throws IOException if unable to start/play server
+ */
+ public static MockWebServer mockWebServer() throws IOException {
+ final MockWebServer server = new MockWebServer();
+ server.start();
+ return server;
+ }
- /**
- * Get the String representation of some resource to be used as payload.
- *
- * @param resource String representation of a given resource
- * @return payload in String form
- */
- public String payloadFromResource(final String resource) {
- try {
- return new String(toStringAndClose(getClass().getResourceAsStream(resource)).getBytes(Charsets.UTF_8));
- } catch (IOException e) {
- throw Throwables.propagate(e);
- }
+ /**
+ * Get the String representation of some resource to be used as payload.
+ *
+ * @param resource String representation of a given resource
+ * @return payload in String form
+ */
+ public String payloadFromResource(final String resource) {
+ try {
+ return new String(toStringAndClose(getClass().getResourceAsStream(resource))
+ .getBytes(Charsets.UTF_8));
+ } catch (IOException e) {
+ throw Throwables.propagate(e);
}
+ }
+
+
+ /**
+ * Get gson.
+ *
+ * @return Gson
+ */
+ public Gson getGson() {
+ return new GsonBuilder()
+ .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
+ .registerTypeAdapter(DateTime.class, new DateTimeTypeConverter())
+ .create();
+ }
+
+ /**
+ * Get retrofit token.
+ *
+ * @param url String
+ * @return Retrofit
+ */
+ public Retrofit getRetrofit(String url) {
+ final OkHttpClient.Builder okhttpbuilder = new OkHttpClient.Builder();
+
+
+ okhttpbuilder.connectTimeout(30, TimeUnit.SECONDS);
+ okhttpbuilder.readTimeout(30, TimeUnit.SECONDS);
+ okhttpbuilder.writeTimeout(30, TimeUnit.SECONDS);
+
+ OkHttpClient httpClient = okhttpbuilder
+ .build();
+
+
+ return new Retrofit.Builder()
+ .client(httpClient)
+ .baseUrl(url)
+ .addConverterFactory(GsonConverterFactory.create(getGson()))
+ .addConverterFactory(ScalarsConverterFactory.create())
+ .build();
+ }
}
diff --git a/src/test/java/ug/sparkpl/network/RequestOptionsTest.java b/src/test/java/ug/sparkpl/network/RequestOptionsTest.java
index 4574e48..040f8d8 100644
--- a/src/test/java/ug/sparkpl/network/RequestOptionsTest.java
+++ b/src/test/java/ug/sparkpl/network/RequestOptionsTest.java
@@ -1,25 +1,48 @@
package ug.sparkpl.network;
-import org.junit.jupiter.api.Test;
import ug.sparkpl.momoapi.network.RequestOptions;
+import org.junit.jupiter.api.Test;
+
import static org.junit.jupiter.api.Assertions.assertEquals;
public class RequestOptionsTest {
- @Test
- public void testPersistentValuesInToBuilder() {
- RequestOptions opts = RequestOptions.builder()
- .setCollectionApiSecret("sec")
- .setCollectionPrimaryKey("123")
- .setCollectionUserId("1234").build();
+ @Test
+ public void testPersistentValuesInToBuilder() {
+ RequestOptions.Builder opts = RequestOptions.builder()
+ .setCollectionApiSecret("sec")
+ .setCollectionPrimaryKey("123")
+ .setCollectionUserId("1234")
+ .setCurrency("UGX")
+ .setTargetEnvironment("test")
+ .setBaseUrl("new_base")
+ .setRemittanceUserId("remituid")
+ .setRemittancePrimaryKey("remKey")
+ .setRemittanceApiSecret("remSecret")
+ .setDisbursementUserId("duid")
+ .setDisbursementApiSecret("dSecret")
+ .setDisbursementPrimaryKey("dKey")
+ .build().toBuilder();
+
+
+ // assuming these are stable across a given stripe integration
+
+ assertEquals("123", opts.getCollectionPrimaryKey());
+ assertEquals("sec", opts.getCollectionApiSecret());
+ assertEquals("1234", opts.getCollectionUserId());
+ assertEquals("UGX", opts.getCurrency());
+ assertEquals("test", opts.getTargetEnvironment());
+ assertEquals("UGX", opts.getCurrency());
+ assertEquals("new_base", opts.getBaseUrl());
+ assertEquals("remituid", opts.getRemittanceUserId());
+ assertEquals("remKey", opts.getRemittancePrimaryKey());
+ assertEquals("remSecret", opts.getRemittanceApiSecret());
+ assertEquals("dKey", opts.getDisbursementPrimaryKey());
+ assertEquals("dSecret", opts.getDisbursementApiSecret());
+ assertEquals("duid", opts.getDisbursementUserId());
- // only api keys and account should persist
- // assuming these are stable across a given stripe integration
- assertEquals("sec", opts.getCollectionApiSecret());
- assertEquals("123", opts.getCollectionPrimaryKey());
- assertEquals("1234", opts.getRemittanceUserId());
- }
+ }
}
diff --git a/src/test/java/ug/sparkpl/network/collections/CollectionsClientTest.java b/src/test/java/ug/sparkpl/network/collections/CollectionsClientTest.java
deleted file mode 100644
index 19a80cc..0000000
--- a/src/test/java/ug/sparkpl/network/collections/CollectionsClientTest.java
+++ /dev/null
@@ -1,227 +0,0 @@
-package ug.sparkpl.network.collections;
-
-import okhttp3.mockwebserver.MockWebServer;
-
-public class CollectionsClientTest {
-
-
- public void testGetListUserByGroup() throws Exception {
- final MockWebServer server = new MockWebServer();
-
- /* server.enqueue(new MockResponse()
- .setBody(payloadFromResource("/admin-list-user-by-group.json"))
- .setResponseCode(200));
- try (final BitbucketApi baseApi = api(server.getUrl("/"))) {
-
- final UserPage up = baseApi.adminApi().listUsersByGroup(localContext, null, 0, 2);
- assertThat(up).isNotNull();
- assertThat(up.errors()).isEmpty();
- assertThat(up.size() == 2).isTrue();
- assertThat(up.values().get(0).slug().equals("bob123")).isTrue();
-
- final Map queryParams = ImmutableMap.of("context", localContext, limitKeyword, 2, startKeyword, 0);
- assertSent(server, getMethod, restApiPath + BitbucketApiMetadata.API_VERSION
- + "/admin/groups/more-members", queryParams);
- } finally {
- server.shutdown();
- }
-
-
-
-
-
-
- RequestOptions opts = RequestOptions.builder().build();
- CollectionsClient client = new CollectionsClient(opts);
-
-
- try {
-
- System.out.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
- String ref = client.requestToPay("256794631873", "456", "234", "dd", "rty", "EUR");
-
-
- System.out.println(ref + ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
- System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
-
- Transaction tr = client.getTransactionStatus(ref);
-
-
- System.out.println(tr.getStatus());
-
- Balance bl = client.getBalance();
-
- System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&");
-
- System.out.println(bl.getBalance());
-
-
- } catch (IOException e) {
- System.out.println(e.toString());
-
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- */
- }
-
-
-
-
- /*
-
-
- public void testGetListUserByGroupOnError() throws Exception {
- final MockWebServer server = mockWebServer();
-
- server.enqueue(new MockResponse()
- .setBody(payloadFromResource("/admin-list-user-by-group-error.json"))
- .setResponseCode(401));
- try (final BitbucketApi baseApi = api(server.getUrl("/"))) {
-
- final UserPage up = baseApi.adminApi().listUsersByGroup(localContext, null, 0, 2);
- assertThat(up).isNotNull();
- assertThat(up.errors()).isNotEmpty();
-
- final Map queryParams = ImmutableMap.of("context", localContext, limitKeyword, 2, startKeyword, 0);
- assertSent(server, getMethod, restApiPath + BitbucketApiMetadata.API_VERSION
- + "/admin/groups/more-members", queryParams);
- } finally {
- server.shutdown();
- }
- }
-
-
- public void testAddBuildStatus() throws Exception {
- final MockWebServer server = mockWebServer();
-
- server.enqueue(new MockResponse().setBody(payloadFromResource("/build-status-post.json")).setResponseCode(204));
- try (final BitbucketApi baseApi = api(server.getUrl("/"))) {
-
- final CreateBuildStatus cbs = CreateBuildStatus.create(CreateBuildStatus.STATE.SUCCESSFUL,
- "REPO-MASTER",
- "REPO-MASTER-42",
- "https://bamboo.example.com/browse/REPO-MASTER-42",
- "Changes by John Doe");
- final RequestStatus success = baseApi.buildStatusApi().add(commitHash, cbs);
- assertThat(success).isNotNull();
- assertThat(success.value()).isTrue();
- assertThat(success.errors()).isEmpty();
-
- assertSent(server, "POST", restBuildStatusPath + BitbucketApiMetadata.API_VERSION
- + commitPath);
- } finally {
- server.shutdown();
- }
- }
-
-
- public void testGetCommit() throws Exception {
- final MockWebServer server = mockWebServer();
-
- server.enqueue(new MockResponse().setBody(payloadFromResource("/commit.json")).setResponseCode(200));
- try (final BitbucketApi baseApi = api(server.getUrl("/"))) {
-
- final Commit commit = baseApi.commitsApi().get(projectKey, repoKey, commitHash, null);
- assertThat(commit).isNotNull();
- assertThat(commit.errors().isEmpty()).isTrue();
- assertThat(commit.id().equalsIgnoreCase(commitHash)).isTrue();
-
- assertSent(server, getMethod, restBasePath + BitbucketApiMetadata.API_VERSION
- + "/projects/" + projectKey + "/repos/" + repoKey + "/commits/" + commitHash);
- } finally {
- server.shutdown();
- }
- }
-
-
- public void testCreateProject() throws Exception {
- final MockWebServer server = mockWebServer();
-
- server.enqueue(new MockResponse()
- .setBody(payloadFromResource("/project.json"))
- .setResponseCode(201));
- try (final BitbucketApi baseApi = api(server.getUrl("/"))) {
-
- final String projectKey = "HELLO";
- final CreateProject createProject = CreateProject.create(projectKey, null, null, null);
- final Project project = baseApi.projectApi().create(createProject);
-
- assertThat(project).isNotNull();
- assertThat(project.errors()).isEmpty();
- assertThat(project.key()).isEqualToIgnoringCase(projectKey);
- assertThat(project.name()).isEqualToIgnoringCase(projectKey);
- assertThat(project.links()).isNotNull();
- assertSent(server, "POST", restBasePath + BitbucketApiMetadata.API_VERSION + localPath);
- } finally {
- server.shutdown();
- }
- }
-
-
- public void testCreateProjectWithIllegalName() throws Exception {
- final MockWebServer server = mockWebServer();
-
- server.enqueue(new MockResponse()
- .setBody(payloadFromResource("/project-create-fail.json"))
- .setResponseCode(400));
- try (final BitbucketApi baseApi = api(server.getUrl("/"))) {
-
- final String projectKey = "9999";
- final CreateProject createProject = CreateProject.create(projectKey, null, null, null);
- final Project project = baseApi.projectApi().create(createProject);
-
- assertThat(project).isNotNull();
- assertThat(project.errors()).isNotEmpty();
- assertSent(server, "POST", restBasePath + BitbucketApiMetadata.API_VERSION + localPath);
- } finally {
- server.shutdown();
- }
- }
-
-
- public void testCreateBranch() throws Exception {
- final MockWebServer server = mockWebServer();
-
- server.enqueue(new MockResponse().setBody(payloadFromResource("/branch.json")).setResponseCode(200));
- try (final BitbucketApi baseApi = api(server.getUrl("/"))) {
-
- final String branchName = "dev-branch";
- final String commitHash = "8d351a10fb428c0c1239530256e21cf24f136e73";
-
- final CreateBranch createBranch = CreateBranch.create(branchName, commitHash, null);
- final Branch branch = baseApi.branchApi().create(projectKey, repoKey, createBranch);
- assertThat(branch).isNotNull();
- assertThat(branch.errors().isEmpty()).isTrue();
- assertThat(branch.id().endsWith(branchName)).isTrue();
- assertThat(commitHash.equalsIgnoreCase(branch.latestChangeset())).isTrue();
- assertSent(server, "POST", localRestPath + BitbucketApiMetadata.API_VERSION
- + localProjectsPath + projectKey + localReposPath + repoKey + localBranchesPath);
- } finally {
- server.shutdown();
- }
- }
-
-
-
- */
-
-
-}
diff --git a/src/test/java/ug/sparkpl/network/collections/LiveCollectionsClientTest.java b/src/test/java/ug/sparkpl/network/collections/LiveCollectionsClientTest.java
new file mode 100644
index 0000000..86fd68d
--- /dev/null
+++ b/src/test/java/ug/sparkpl/network/collections/LiveCollectionsClientTest.java
@@ -0,0 +1,60 @@
+package ug.sparkpl.network.collections;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+import ug.sparkpl.momoapi.models.Balance;
+import ug.sparkpl.momoapi.network.MomoApiException;
+import ug.sparkpl.momoapi.network.RequestOptions;
+import ug.sparkpl.momoapi.network.collections.CollectionsClient;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.Assert.assertNotNull;
+
+public class LiveCollectionsClientTest {
+
+ /**
+ * Test request to pay.
+ *
+ * @throws IOException when network error
+ */
+
+ @Test
+ public void testRequestToPay() throws IOException {
+
+ RequestOptions opts = RequestOptions.builder()
+ .build();
+ assertNotNull(opts.getCollectionPrimaryKey());
+ assertNotNull(opts.getCollectionApiSecret());
+ assertNotNull(opts.getCollectionUserId());
+
+
+ HashMap collMap = new HashMap();
+ collMap.put("amount", "100");
+ collMap.put("mobile", "0782123456");
+ collMap.put("externalId", "ext123");
+ collMap.put("payeeNote", "testNote");
+ collMap.put("payerMessage", "testMessage");
+
+ CollectionsClient client = new CollectionsClient(opts);
+
+ try {
+ String transactionRef = client.requestToPay(collMap);
+ assertNotNull(transactionRef);
+
+ Balance bl = client.getBalance();
+ assertNotNull(bl);
+
+ assertNotNull(bl.getBalance());
+
+
+ } catch (MomoApiException e) {
+ e.printStackTrace();
+ }
+
+
+ }
+
+
+}
diff --git a/src/test/java/ug/sparkpl/network/collections/LiveUserProvisioningTest.java b/src/test/java/ug/sparkpl/network/collections/LiveUserProvisioningTest.java
new file mode 100644
index 0000000..4660dab
--- /dev/null
+++ b/src/test/java/ug/sparkpl/network/collections/LiveUserProvisioningTest.java
@@ -0,0 +1,82 @@
+package ug.sparkpl.network.collections;
+
+import java.io.IOException;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+import ug.sparkpl.momoapi.models.NewUser;
+import ug.sparkpl.momoapi.models.User;
+import ug.sparkpl.momoapi.network.collections.CollectionsApiService;
+import ug.sparkpl.momoapi.utils.DateTimeTypeConverter;
+
+import org.joda.time.DateTime;
+import org.junit.jupiter.api.Test;
+
+import com.google.gson.FieldNamingPolicy;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+import okhttp3.OkHttpClient;
+import retrofit2.Response;
+import retrofit2.Retrofit;
+import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
+import retrofit2.converter.gson.GsonConverterFactory;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public class LiveUserProvisioningTest {
+
+
+ /**
+ * Test user account provisioning.
+ *
+ * @throws IOException when network error.
+ */
+ @Test
+ public void testUserProvisioning() throws IOException {
+
+ String baseUrl = "https://ericssonbasicapi2.azure-api.net";
+ final CollectionsApiService apiService;
+ Gson gson = new GsonBuilder()
+ .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
+ .registerTypeAdapter(DateTime.class, new DateTimeTypeConverter())
+ .create();
+
+
+ final OkHttpClient.Builder okhttpbuilder = new OkHttpClient.Builder();
+
+ okhttpbuilder.connectTimeout(30, TimeUnit.SECONDS);
+ okhttpbuilder.readTimeout(30, TimeUnit.SECONDS);
+ okhttpbuilder.writeTimeout(30, TimeUnit.SECONDS);
+
+
+ OkHttpClient httpClient = okhttpbuilder
+ .build();
+
+
+ Retrofit retrofitClient = new Retrofit.Builder()
+ .client(httpClient)
+ .baseUrl(baseUrl)
+ .addConverterFactory(GsonConverterFactory.create(gson))
+ .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
+ .build();
+
+ apiService = retrofitClient.create(CollectionsApiService.class);
+
+ String token = UUID.randomUUID().toString();
+
+ Response res = apiService
+ .provisonUser(System.getenv("COLLECTION_PRIMARY_KEY"), token,
+ new NewUser("ubuntudata.com"))
+ .execute();
+
+ Response user = apiService.getUser(token,
+ System.getenv("COLLECTION_PRIMARY_KEY")).execute();
+ assertNotNull(user);
+
+
+ assertNotNull(user.body().getApiKey());
+
+
+ }
+}
diff --git a/src/test/java/ug/sparkpl/network/disbursements/LiveDisbursementsClientTest.java b/src/test/java/ug/sparkpl/network/disbursements/LiveDisbursementsClientTest.java
new file mode 100644
index 0000000..9c9c3b0
--- /dev/null
+++ b/src/test/java/ug/sparkpl/network/disbursements/LiveDisbursementsClientTest.java
@@ -0,0 +1,57 @@
+package ug.sparkpl.network.disbursements;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+import ug.sparkpl.momoapi.models.Balance;
+import ug.sparkpl.momoapi.network.MomoApiException;
+import ug.sparkpl.momoapi.network.RequestOptions;
+import ug.sparkpl.momoapi.network.disbursements.DisbursementsClient;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.Assert.assertNotNull;
+
+public class LiveDisbursementsClientTest {
+
+ /**
+ * Test disbursements.
+ *
+ * @throws IOException when netowk error.
+ */
+
+ @Test
+ public void testTransfer() throws IOException {
+
+
+ RequestOptions opts = RequestOptions.builder()
+ .build();
+
+
+ HashMap collMap = new HashMap();
+ collMap.put("amount", "100");
+ collMap.put("mobile", "0782181656");
+ collMap.put("externalId", "ext123");
+ collMap.put("payeeNote", "testNote");
+ collMap.put("payerMessage", "testMessage");
+
+ DisbursementsClient client = new DisbursementsClient(opts);
+
+ try {
+ String transactionRef = client.transfer(collMap);
+ assertNotNull(transactionRef);
+
+ Balance bl = client.getBalance();
+
+ assertNotNull(bl);
+
+ assertNotNull(bl.getBalance());
+
+
+ } catch (MomoApiException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+}
diff --git a/src/test/java/ug/sparkpl/network/disbursements/MockDisbursementsClientTest.java b/src/test/java/ug/sparkpl/network/disbursements/MockDisbursementsClientTest.java
new file mode 100644
index 0000000..396b4d1
--- /dev/null
+++ b/src/test/java/ug/sparkpl/network/disbursements/MockDisbursementsClientTest.java
@@ -0,0 +1,4 @@
+package ug.sparkpl.network.disbursements;
+
+public class MockDisbursementsClientTest {
+}
diff --git a/src/test/java/ug/sparkpl/network/remittance/LiveRemittanceClientTest.java b/src/test/java/ug/sparkpl/network/remittance/LiveRemittanceClientTest.java
new file mode 100644
index 0000000..923cbc8
--- /dev/null
+++ b/src/test/java/ug/sparkpl/network/remittance/LiveRemittanceClientTest.java
@@ -0,0 +1,55 @@
+package ug.sparkpl.network.remittance;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+import ug.sparkpl.momoapi.models.Balance;
+import ug.sparkpl.momoapi.network.MomoApiException;
+import ug.sparkpl.momoapi.network.RequestOptions;
+import ug.sparkpl.momoapi.network.remittances.RemittancesClient;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.Assert.assertNotNull;
+
+public class LiveRemittanceClientTest {
+
+ /**
+ * Test remittance transfer.
+ *
+ * @throws IOException when network error
+ */
+
+ @Test
+ public void testTransfer() throws IOException {
+
+ RequestOptions opts = RequestOptions.builder()
+ .build();
+
+
+ HashMap collMap = new HashMap();
+ collMap.put("amount", "100");
+ collMap.put("mobile", "0782181656");
+ collMap.put("externalId", "ext123");
+ collMap.put("payeeNote", "testNote");
+ collMap.put("payerMessage", "testMessage");
+
+ RemittancesClient client = new RemittancesClient(opts);
+
+ try {
+ String transactionRef = client.transfer(collMap);
+ assertNotNull(transactionRef);
+
+ Balance bl = client.getBalance();
+
+ assertNotNull(bl.getBalance());
+
+
+ } catch (MomoApiException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+}
+
diff --git a/src/test/java/ug/sparkpl/network/remittance/MockRemittanceClientTest.java b/src/test/java/ug/sparkpl/network/remittance/MockRemittanceClientTest.java
new file mode 100644
index 0000000..3016797
--- /dev/null
+++ b/src/test/java/ug/sparkpl/network/remittance/MockRemittanceClientTest.java
@@ -0,0 +1,4 @@
+package ug.sparkpl.network.remittance;
+
+public class MockRemittanceClientTest {
+}