From 6369ed55a6d9485d1d4ece035cf5d304bb5c5732 Mon Sep 17 00:00:00 2001 From: Moses Mugisha Date: Tue, 23 Apr 2019 16:40:44 +0300 Subject: [PATCH 01/29] update to library --- README.md | 103 +++++++- build.gradle | 4 + deploy.gradle | 204 ++++++++------- settings.gradle | 2 +- src/main/java/ug/sparkpl/momoapi/MomoApi.java | 39 +-- .../sparkpl/momoapi/network/ApiException.java | 13 - .../momoapi/network/MomoApiException.java | 15 ++ .../momoapi/network/RequestOptions.java | 81 +++--- .../collections/CollectionSession.java | 2 +- .../CollectionsAuthorizationInterceptor.java | 8 +- .../collections/CollectionsClient.java | 9 + ...DisbursementsAuthorizationInterceptor.java | 4 +- .../disbursements/DisbursementsSession.java | 2 +- .../RemittancesAuthorizationInterceptor.java | 4 +- .../remittances/RemittancesClient.java | 9 + .../remittances/RemittancesSession.java | 2 +- .../sparkpl/network/RequestOptionsTest.java | 1 - .../collections/CollectionsClientTest.java | 241 +++--------------- 18 files changed, 374 insertions(+), 369 deletions(-) delete mode 100644 src/main/java/ug/sparkpl/momoapi/network/ApiException.java create mode 100644 src/main/java/ug/sparkpl/momoapi/network/MomoApiException.java diff --git a/README.md b/README.md index 4edcc65..9cef207 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,101 @@ -# momoapi-java -MTN MoMo API Client for Java +# MomoAPI Java Bindings + +You can sign up for a MOMOAPI account at https://https://momodeveloper.mtn.com + +## Requirements + +Java 1.8 or later. + +## Installation + +### Maven users + +Add this dependency to your project's POM: + +```xml + + ug.sparkpl + mtnmomo-java + 1.0.0 + +``` + +### Gradle users + +Add this dependency to your project's build file: + +```groovy +compile "ug.sparkpl:mtnmomo-java:1.0.0" +``` + + +## Usage + +MomoExample.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 MomoExample { + + public static void main(String[] args) { + 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(); + } + } +} +``` + + +### Per-request Configuration + +By default, you can set + + + +``` java + +``` + + + +## Development + +You must have Gradle installed. To run the tests: + + ./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. + +[connect]: https://stripe.com/connect +[lombok]: https://projectlombok.org +[lombok-plugins]: https://projectlombok.org/setup/overview +[stripe-mock]: https://github.com/stripe/stripe-mock + + \ No newline at end of file diff --git a/build.gradle b/build.gradle index 6d647ec..f06761e 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 @@ -92,6 +95,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" } diff --git a/deploy.gradle b/deploy.gradle index a590698..56fa4ed 100644 --- a/deploy.gradle +++ b/deploy.gradle @@ -1,126 +1,138 @@ -/* - * Based on the example at Chris Banes's repository that allows signing - * without manually creating a maven file. - * - * The original can be found at - * https://raw.github.com/chrisbanes/gradle-mvn-push/master/gradle-mvn-push.gradle - */ - -apply plugin: 'maven' +apply plugin: 'java' +apply plugin: 'maven-publish' apply plugin: 'signing' -apply plugin: 'io.codearte.nexus-staging' -nexusStaging { - packageGroup = GROUP +repositories { + mavenCentral() } -def isReleaseBuild() { - return VERSION_NAME.contains("SNAPSHOT") == false -} -def getReleaseRepositoryUrl() { - return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL - : "https://oss.sonatype.org/service/local/staging/deploy/maven2/" +task sourceJar(type: Jar) { + classifier "sources" + from sourceSets.main.allJava } -def getSnapshotRepositoryUrl() { - return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL - : "https://oss.sonatype.org/content/repositories/snapshots/" +task javadocJar(type: Jar, dependsOn: javadoc) { + classifier "javadoc" + from javadoc.destinationDir } -def getRepositoryUsername() { - return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : "" +artifacts { + archives jar + archives sourceJar + archives javadocJar } -def getRepositoryPassword() { - return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : "" +signing { + sign configurations.archives } -afterEvaluate { project -> - uploadArchives { - repositories { - mavenDeployer { - beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } - - pom.groupId = GROUP - pom.artifactId = POM_ARTIFACT_ID - pom.version = VERSION_NAME - - 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 sonatypeUsername + password 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/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/MomoApi.java b/src/main/java/ug/sparkpl/momoapi/MomoApi.java index 26646ae..92c158c 100644 --- a/src/main/java/ug/sparkpl/momoapi/MomoApi.java +++ b/src/main/java/ug/sparkpl/momoapi/MomoApi.java @@ -1,12 +1,12 @@ package ug.sparkpl.momoapi; -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 ug.sparkpl.momoapi.network.remittances.RemittancesClient; +import ug.sparkpl.momoapi.network.collections.CollectionsClient; import java.io.IOException; +import java.util.HashMap; public class MomoApi { @@ -14,25 +14,30 @@ public class MomoApi { } - public static void main(String[] args) { + public static void main(String[] args) throws IOException { + RequestOptions opts = RequestOptions.builder() + .setCollectionApiSecret("MY_SECRET_API_KEY") + .setCollectionPrimaryKey("MY_SECRET_SUBSCRIPTION_KEY") + .setCollectionUserId("MYSECRET_USER_ID") + .setCurrency("UGX") - RequestOptions opts = RequestOptions.builder().build(); - DisbursementsClient client = new DisbursementsClient(opts); + .build(); - RemittancesClient rclient = new RemittancesClient(opts); + HashMap collMap = new HashMap(); + collMap.put("amount", "100"); + collMap.put("mobile", "1234"); + collMap.put("externalId", "ext123"); + collMap.put("payeeNote", "testNote"); + collMap.put("payerMessage", "testMessage"); - try { - Balance bl = rclient.getBalance(); - - System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&"); - - System.out.println(bl.getBalance()); - - - } catch (IOException e) { - System.out.println(e.toString()); + 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/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/MomoApiException.java b/src/main/java/ug/sparkpl/momoapi/network/MomoApiException.java new file mode 100644 index 0000000..36554bd --- /dev/null +++ b/src/main/java/ug/sparkpl/momoapi/network/MomoApiException.java @@ -0,0 +1,15 @@ +package ug.sparkpl.momoapi.network; + +import java.io.IOException; + +/** + * An exception class for the response. + */ +public final class MomoApiException extends IOException { + + + 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..ef488d0 100644 --- a/src/main/java/ug/sparkpl/momoapi/network/RequestOptions.java +++ b/src/main/java/ug/sparkpl/momoapi/network/RequestOptions.java @@ -7,24 +7,39 @@ public class RequestOptions { - private String COLLECTION_USER_ID; - private String COLLECTION_API_SECRET; - private String COLLECTION_PRIMARY_KEY; + private final String COLLECTION_USER_ID; + private final String COLLECTION_API_SECRET; + private final String COLLECTION_PRIMARY_KEY; - private String REMITTANCE_PRIMARY_KEY; - private String REMITTANCE_USER_ID; - private String REMITTANCE_API_SECRET; + private final String REMITTANCE_PRIMARY_KEY; + private final String REMITTANCE_USER_ID; + private final String REMITTANCE_API_SECRET; - private String DISBURSEMENT_PRIMARY_KEY; - private String DISBURSEMENT_USER_ID; - private String DISBURSEMENT_API_SECRET; + private final String DISBURSEMENT_PRIMARY_KEY; + private final String DISBURSEMENT_USER_ID; + private final String DISBURSEMENT_API_SECRET; - private String BASE_URL = "https://ericssonbasicapi2.azure-api.net"; - private String TARGET_ENVIRONMENT = "sandbox"; + private final String BASE_URL; + private final String TARGET_ENVIRONMENT; - private RequestOptions() { + public RequestOptions(String COLLECTION_API_SECRET, String COLLECTION_PRIMARY_KEY, String COLLECTION_USER_ID, String REMITTANCE_USER_ID, String REMITTANCE_PRIMARY_KEY, String REMITTANCE_API_SECRET, String DISBURSEMENT_API_SECRET, String DISBURSEMENT_PRIMARY_KEY, String DISBURSEMENT_USER_ID, String BASE_URL, String TARGET_ENVIRONMENT) { + + this.COLLECTION_API_SECRET = COLLECTION_API_SECRET; + this.COLLECTION_PRIMARY_KEY = COLLECTION_PRIMARY_KEY; + this.COLLECTION_USER_ID = COLLECTION_USER_ID; + + this.REMITTANCE_USER_ID = REMITTANCE_USER_ID; + this.REMITTANCE_PRIMARY_KEY = REMITTANCE_PRIMARY_KEY; + this.REMITTANCE_API_SECRET = REMITTANCE_API_SECRET; + + this.DISBURSEMENT_API_SECRET = DISBURSEMENT_API_SECRET; + this.DISBURSEMENT_PRIMARY_KEY = DISBURSEMENT_PRIMARY_KEY; + this.DISBURSEMENT_USER_ID = DISBURSEMENT_USER_ID; + this.BASE_URL = BASE_URL; + this.TARGET_ENVIRONMENT = TARGET_ENVIRONMENT; + } @@ -51,7 +66,7 @@ public String getRemittancePrimaryKey() { public String getRemittanceUserId() { - return this.REMITTANCE_USER_ID; + return REMITTANCE_USER_ID; } public String getRemittanceApiSecret() { @@ -81,7 +96,7 @@ public String getTargetEnvironment() { } - public static final class Builder { + public static class Builder { private String COLLECTION_USER_ID; private String COLLECTION_API_SECRET; @@ -116,6 +131,7 @@ public Builder() { 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) { @@ -178,31 +194,34 @@ public Builder setBaseUrl(String url) { return this; } + public Builder setCurrency(String currency) { + this.CURRENCY = CURRENCY; + 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; - - opts.REMITTANCE_USER_ID = this.REMITTANCE_USER_ID; - opts.REMITTANCE_PRIMARY_KEY = this.REMITTANCE_PRIMARY_KEY; - opts.REMITTANCE_API_SECRET = this.REMITTANCE_API_SECRET; - - 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; - return opts; + public RequestOptions build() { + return new RequestOptions( + this.COLLECTION_API_SECRET, + this.COLLECTION_PRIMARY_KEY, + this.COLLECTION_USER_ID, + + this.REMITTANCE_USER_ID, + this.REMITTANCE_PRIMARY_KEY, + this.REMITTANCE_API_SECRET, + + this.DISBURSEMENT_API_SECRET, + this.DISBURSEMENT_PRIMARY_KEY, + this.DISBURSEMENT_USER_ID, + this.BASE_URL, + this.TARGET_ENVIRONMENT + ); } } - public static class InvalidRequestOptionsException extends RuntimeException { private static final long serialVersionUID = 1L; 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..fa7fb9f 100644 --- a/src/main/java/ug/sparkpl/momoapi/network/collections/CollectionSession.java +++ b/src/main/java/ug/sparkpl/momoapi/network/collections/CollectionSession.java @@ -19,7 +19,7 @@ public void saveToken(String token) { public String getToken() { // return the token that was saved earlier - return prefs.get(TOKEN_NAME, "ddd"); + return prefs.get(TOKEN_NAME, "dummy"); } 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..0576f99 100644 --- a/src/main/java/ug/sparkpl/momoapi/network/collections/CollectionsAuthorizationInterceptor.java +++ b/src/main/java/ug/sparkpl/momoapi/network/collections/CollectionsAuthorizationInterceptor.java @@ -16,7 +16,7 @@ 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.MomoApiException; import ug.sparkpl.momoapi.network.RequestOptions; import java.io.IOException; @@ -124,11 +124,15 @@ public okhttp3.Response intercept(Chain chain) throws IOException { this.logger.log(Level.INFO, "<<<<<<<<<<<<<<< ETETETET " + mainResponse.code() + " .." + mainResponse.body().string()); - throw new ApiException(mainResponse.body().string()); + throw new MomoApiException(mainResponse.body().string()); } + if (this.session.getToken() == "dummy") { + throw new MomoApiException(mainResponse.body().string()); + } + 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..c420ce5 100644 --- a/src/main/java/ug/sparkpl/momoapi/network/collections/CollectionsClient.java +++ b/src/main/java/ug/sparkpl/momoapi/network/collections/CollectionsClient.java @@ -19,6 +19,7 @@ import ug.sparkpl.momoapi.network.RequestOptions; import java.io.IOException; +import java.util.HashMap; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -111,5 +112,13 @@ public String requestToPay(String mobile, String amount, String external_id, Str } + public String requestToPay(HashMap opts) throws IOException { + RequestToPay rBody = new RequestToPay(opts.get("mobile"), opts.get("amount"), opts.get("external_id"), opts.get("payee_note"), opts.get("payer_message"), opts.get("currency")); + String ref = UUID.randomUUID().toString(); + this.apiService.requestToPay(rBody, ref).execute(); + return ref; + + } + } 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..a83c7f1 100644 --- a/src/main/java/ug/sparkpl/momoapi/network/disbursements/DisbursementsAuthorizationInterceptor.java +++ b/src/main/java/ug/sparkpl/momoapi/network/disbursements/DisbursementsAuthorizationInterceptor.java @@ -15,7 +15,7 @@ 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.MomoApiException; import ug.sparkpl.momoapi.network.RequestOptions; import java.io.IOException; @@ -124,7 +124,7 @@ public okhttp3.Response intercept(Chain chain) throws IOException { this.logger.log(Level.INFO, "<<<<<<<<<<<<<<< ETETETET " + mainResponse.code() + " .." + mainResponse.body().string()); - throw new ApiException(mainResponse.body().string()); + throw new MomoApiException(mainResponse.body().string()); } 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..296d184 100644 --- a/src/main/java/ug/sparkpl/momoapi/network/disbursements/DisbursementsSession.java +++ b/src/main/java/ug/sparkpl/momoapi/network/disbursements/DisbursementsSession.java @@ -19,7 +19,7 @@ public void saveToken(String token) { public String getToken() { // return the token that was saved earlier - return prefs.get(TOKEN_NAME, "rando"); + return prefs.get(TOKEN_NAME, "dummy"); } 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..019bbd3 100644 --- a/src/main/java/ug/sparkpl/momoapi/network/remittances/RemittancesAuthorizationInterceptor.java +++ b/src/main/java/ug/sparkpl/momoapi/network/remittances/RemittancesAuthorizationInterceptor.java @@ -15,7 +15,7 @@ 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.MomoApiException; import ug.sparkpl.momoapi.network.RequestOptions; import java.io.IOException; @@ -122,7 +122,7 @@ public okhttp3.Response intercept(Chain chain) throws IOException { this.logger.log(Level.INFO, "<<<<<<<<<<<<<<< ETETETET " + mainResponse.code() + " .." + mainResponse.body().string()); - throw new ApiException(mainResponse.body().string()); + throw new MomoApiException(mainResponse.body().string()); } 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..e7527a4 100644 --- a/src/main/java/ug/sparkpl/momoapi/network/remittances/RemittancesClient.java +++ b/src/main/java/ug/sparkpl/momoapi/network/remittances/RemittancesClient.java @@ -19,6 +19,7 @@ import ug.sparkpl.momoapi.network.RequestOptions; import java.io.IOException; +import java.util.HashMap; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -107,4 +108,12 @@ public String transfer(String mobile, String amount, String external_id, String } + 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; + + } + } 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..5491986 100644 --- a/src/main/java/ug/sparkpl/momoapi/network/remittances/RemittancesSession.java +++ b/src/main/java/ug/sparkpl/momoapi/network/remittances/RemittancesSession.java @@ -19,7 +19,7 @@ public void saveToken(String token) { public String getToken() { // return the token that was saved earlier - return prefs.get(TOKEN_NAME, ""); + return prefs.get(TOKEN_NAME, "dummy"); } diff --git a/src/test/java/ug/sparkpl/network/RequestOptionsTest.java b/src/test/java/ug/sparkpl/network/RequestOptionsTest.java index 4574e48..eecff22 100644 --- a/src/test/java/ug/sparkpl/network/RequestOptionsTest.java +++ b/src/test/java/ug/sparkpl/network/RequestOptionsTest.java @@ -15,7 +15,6 @@ public void testPersistentValuesInToBuilder() { .setCollectionUserId("1234").build(); - // only api keys and account should persist // assuming these are stable across a given stripe integration assertEquals("sec", opts.getCollectionApiSecret()); assertEquals("123", opts.getCollectionPrimaryKey()); diff --git a/src/test/java/ug/sparkpl/network/collections/CollectionsClientTest.java b/src/test/java/ug/sparkpl/network/collections/CollectionsClientTest.java index 19a80cc..862fa09 100644 --- a/src/test/java/ug/sparkpl/network/collections/CollectionsClientTest.java +++ b/src/test/java/ug/sparkpl/network/collections/CollectionsClientTest.java @@ -1,227 +1,70 @@ package ug.sparkpl.network.collections; +import com.google.gson.FieldNamingPolicy; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import okhttp3.OkHttpClient; +import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; +import org.joda.time.DateTime; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; +import retrofit2.converter.scalars.ScalarsConverterFactory; +import ug.sparkpl.momoapi.Utils.DateTimeTypeConverter; +import ug.sparkpl.momoapi.network.collections.CollectionsApiService; +import ug.sparkpl.network.BaseTest; -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()); - - } - - - - - - - +import java.util.concurrent.TimeUnit; +import static org.junit.Assert.assertEquals; +public class CollectionsClientTest extends BaseTest { - - - - - - - - - */ - } - - - - - /* - - - public void testGetListUserByGroupOnError() throws Exception { - final MockWebServer server = mockWebServer(); + public void testLogin() throws Exception { + final MockWebServer server = new MockWebServer(); + String path = "/collection/v1_0/requesttopay"; 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(); - } - } + .setBody(payloadFromResource("resources/collections/token.json")) + .setResponseCode(200)); - public void testAddBuildStatus() throws Exception { - final MockWebServer server = mockWebServer(); + Gson gson = new GsonBuilder() + .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) + .registerTypeAdapter(DateTime.class, new DateTimeTypeConverter()) + .create(); - 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(); + final OkHttpClient.Builder okhttpbuilder = new OkHttpClient.Builder(); - assertSent(server, "POST", restBuildStatusPath + BitbucketApiMetadata.API_VERSION - + commitPath); - } finally { - server.shutdown(); - } - } + okhttpbuilder.connectTimeout(30, TimeUnit.SECONDS); + okhttpbuilder.readTimeout(30, TimeUnit.SECONDS); + okhttpbuilder.writeTimeout(30, TimeUnit.SECONDS); - public void testGetCommit() throws Exception { - final MockWebServer server = mockWebServer(); + OkHttpClient httpClient = okhttpbuilder + .build(); - 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(); + Retrofit retrofitClient = new Retrofit.Builder() + .client(httpClient) + .baseUrl("/") + .addConverterFactory(GsonConverterFactory.create(gson)) + .addConverterFactory(ScalarsConverterFactory.create()) + .build(); - assertSent(server, getMethod, restBasePath + BitbucketApiMetadata.API_VERSION - + "/projects/" + projectKey + "/repos/" + repoKey + "/commits/" + commitHash); - } finally { - server.shutdown(); - } - } + CollectionsApiService apiService = retrofitClient.create(CollectionsApiService.class); + apiService.getToken("", "").execute(); - public void testCreateProject() throws Exception { - final MockWebServer server = mockWebServer(); + RecordedRequest request = server.takeRequest(); + // Make sure we made the request to the required path + assertEquals(path, request.getPath()); - 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(); - } - } - - - - */ - - } From d01b60fda2724cbfb803212951cfcb29aa5217d8 Mon Sep 17 00:00:00 2001 From: Moses Mugisha Date: Mon, 29 Apr 2019 17:01:46 +0300 Subject: [PATCH 02/29] add provisioning API --- README.md | 26 +++++- build.gradle | 7 +- src/main/java/ug/sparkpl/momoapi/MomoApi.java | 87 +++++++++++++------ .../ug/sparkpl/momoapi/models/NewUser.java | 12 +++ .../sparkpl/momoapi/models/Transaction.java | 10 ++- .../java/ug/sparkpl/momoapi/models/User.java | 13 ++- .../collections/CollectionsApiService.java | 10 +++ .../collections/CollectionsClient.java | 2 +- 8 files changed, 134 insertions(+), 33 deletions(-) create mode 100644 src/main/java/ug/sparkpl/momoapi/models/NewUser.java diff --git a/README.md b/README.md index 9cef207..ecb99a1 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ You can sign up for a MOMOAPI account at https://https://momodeveloper.mtn.com +[![Build Status](https://travis-ci.com/sparkplug/momoapi-java.svg?branch=master)](https://travis-ci.com/sparkplug/momoapi-java) +[![Coverage Status](https://coveralls.io/repos/github/sparkplug/momoapi-java/badge.svg?branch=master)](https://coveralls.io/github/sparkplug/momoapi-java?branch=master) +[![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/momo-api-developers/) + ## Requirements Java 1.8 or later. @@ -28,6 +32,26 @@ Add this dependency to your project's build file: compile "ug.sparkpl:mtnmomo-java:1.0.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 +Here is your User Id and API secret : {'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. + + ## Usage @@ -91,10 +115,8 @@ You must have Gradle installed. To run the tests: 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. -[connect]: https://stripe.com/connect [lombok]: https://projectlombok.org [lombok-plugins]: https://projectlombok.org/setup/overview -[stripe-mock]: https://github.com/stripe/stripe-mock \ No newline at end of file +# Thank you. \ No newline at end of file From 8130f92ca608843c934989d43b380b0a524f233b Mon Sep 17 00:00:00 2001 From: Ray Besiga Date: Tue, 7 May 2019 13:08:01 +0300 Subject: [PATCH 24/29] Update Readme --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4ccd975..ca4ffdc 100644 --- a/README.md +++ b/README.md @@ -225,8 +225,9 @@ public class MomoDisbursementsExample { 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. From f0a03980f187123a368cbc9a32b3bc1af7c21f78 Mon Sep 17 00:00:00 2001 From: Ray Besiga Date: Tue, 7 May 2019 13:09:11 +0300 Subject: [PATCH 25/29] Add Authors, Changelog, and Contributing Guide --- AUTHORS.md | 7 ++ CHANGELOG.md | 8 +++ CONTRIBUTING.md | 177 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 192 insertions(+) create mode 100644 AUTHORS.md create mode 100644 CHANGELOG.md create mode 100644 CONTRIBUTING.md 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. + From 162ac692df3bd75bf8516ab016cf366013eee9c9 Mon Sep 17 00:00:00 2001 From: Moses Mugisha Date: Wed, 8 May 2019 02:43:17 +0300 Subject: [PATCH 26/29] update readme --- README.md | 4 ++-- .../java/ug/sparkpl/momoapi/network/BaseClient.java | 13 +++++-------- .../network/collections/CollectionsClient.java | 13 +++---------- 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 4b14e3c..1aa04b2 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Add this dependency to your project's POM: ug.sparkpl mtnmomo-java - 1.0.0 + 1.2.0 ``` @@ -179,7 +179,7 @@ import java.util.HashMap; import java.util.Map; import ug.sparkpl.momoapi.network.RequestOptions; -import ug.sparkpl.momoapi.network.collections.CollectionsClient; +import ug.sparkpl.momoapi.network.disbursements.DisbursementsClient; public class MomoDisbursementsExample { diff --git a/src/main/java/ug/sparkpl/momoapi/network/BaseClient.java b/src/main/java/ug/sparkpl/momoapi/network/BaseClient.java index 152cbe5..8c3d501 100644 --- a/src/main/java/ug/sparkpl/momoapi/network/BaseClient.java +++ b/src/main/java/ug/sparkpl/momoapi/network/BaseClient.java @@ -17,7 +17,7 @@ import retrofit2.converter.gson.GsonConverterFactory; -class BaseClient { +public class BaseClient { /** @@ -25,7 +25,7 @@ class BaseClient { * * @return Gson */ - Gson getGson() { + public Gson getGson() { return new GsonBuilder() .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) .registerTypeAdapter(DateTime.class, new DateTimeTypeConverter()) @@ -37,16 +37,15 @@ Gson getGson() { * create Retrofit. * * @param apiEndpoint String - * @param gson Gson * @param okHttpClient OkHttpClient * @return Retrofit */ - Retrofit createRetrofit(final String apiEndpoint, final Gson gson, + Retrofit createRetrofit(final String apiEndpoint, final @NonNull OkHttpClient okHttpClient) { return new Retrofit.Builder() .client(okHttpClient) .baseUrl(apiEndpoint) - .addConverterFactory(GsonConverterFactory.create(gson)) + .addConverterFactory(GsonConverterFactory.create(getGson())) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build(); } @@ -79,14 +78,12 @@ CollectionsApiService provideCollectionsApiService(final @NonNull Retrofit apiRe * Get Api Retrofit. * * @param apiEndpoint String - * @param gson Gson * @param okHttpClient OkHttpClient * @return Retrofit */ Retrofit getApiRetrofit(final @NonNull String apiEndpoint, - final @NonNull Gson gson, final @NonNull OkHttpClient okHttpClient) { - return createRetrofit(apiEndpoint, gson, okHttpClient); + return createRetrofit(apiEndpoint, okHttpClient); } 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 5ad5d47..4826489 100644 --- a/src/main/java/ug/sparkpl/momoapi/network/collections/CollectionsClient.java +++ b/src/main/java/ug/sparkpl/momoapi/network/collections/CollectionsClient.java @@ -9,14 +9,10 @@ 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 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; @@ -26,7 +22,7 @@ import retrofit2.converter.gson.GsonConverterFactory; import retrofit2.converter.scalars.ScalarsConverterFactory; -public class CollectionsClient { +public class CollectionsClient extends BaseClient { RequestOptions opts; @@ -45,10 +41,7 @@ public class CollectionsClient { */ public CollectionsClient(RequestOptions opts) { this.opts = opts; - this.gson = new GsonBuilder() - .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) - .registerTypeAdapter(DateTime.class, new DateTimeTypeConverter()) - .create(); + this.gson = getGson(); this.session = new CollectionSession(); From 0621e138049098c12e5e9fdded30c5605d846d7c Mon Sep 17 00:00:00 2001 From: Moses Mugisha Date: Wed, 8 May 2019 13:18:05 +0300 Subject: [PATCH 27/29] fix style issues --- .../collections/CollectionsAuthorizationInterceptor.java | 4 +++- .../DisbursementsAuthorizationInterceptor.java | 5 ++++- .../remittances/RemittancesAuthorizationInterceptor.java | 4 +++- src/test/java/ug/sparkpl/network/BaseTest.java | 2 +- .../network/collections/LiveUserProvisioningTest.java | 6 ++++-- 5 files changed, 15 insertions(+), 6 deletions(-) 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 6dbcdee..78d7969 100644 --- a/src/main/java/ug/sparkpl/momoapi/network/collections/CollectionsAuthorizationInterceptor.java +++ b/src/main/java/ug/sparkpl/momoapi/network/collections/CollectionsAuthorizationInterceptor.java @@ -147,12 +147,14 @@ public okhttp3.Response intercept(Chain chain) throws IOException { .method(mainRequest.method(), mainRequest.body()); mainResponse = chain.proceed(builder.build()); } - } else if (mainResponse.code() == 400 || mainResponse.code() == 500 || mainResponse.code() == 404) { + } else if (mainResponse.code() == 400 || mainResponse.code() == 500 + || mainResponse.code() == 404) { String error = ""; try { error = mainResponse.body().string(); } catch (IllegalStateException e) { + this.logger.log(Level.SEVERE, e.toString()); } 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 9a10f34..e4812f2 100644 --- a/src/main/java/ug/sparkpl/momoapi/network/disbursements/DisbursementsAuthorizationInterceptor.java +++ b/src/main/java/ug/sparkpl/momoapi/network/disbursements/DisbursementsAuthorizationInterceptor.java @@ -145,13 +145,16 @@ public okhttp3.Response intercept(Chain chain) throws IOException { } - } else if (mainResponse.code() == 400 || mainResponse.code() == 500 || mainResponse.code() == 404) { + } else if (mainResponse.code() == 400 || mainResponse.code() == 500 + || mainResponse.code() == 404) { String error = ""; try { error = mainResponse.body().string(); } catch (IllegalStateException e) { + this.logger.log(Level.SEVERE, e.toString()); + } 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 e90c882..f9f01a6 100644 --- a/src/main/java/ug/sparkpl/momoapi/network/remittances/RemittancesAuthorizationInterceptor.java +++ b/src/main/java/ug/sparkpl/momoapi/network/remittances/RemittancesAuthorizationInterceptor.java @@ -141,12 +141,14 @@ public okhttp3.Response intercept(Chain chain) throws IOException { .method(mainRequest.method(), mainRequest.body()); mainResponse = chain.proceed(builder.build()); } - } else if (mainResponse.code() == 400 || mainResponse.code() == 500 || mainResponse.code() == 404) { + } else if (mainResponse.code() == 400 || mainResponse.code() == 500 + || mainResponse.code() == 404) { String error = ""; try { error = mainResponse.body().string(); } catch (IllegalStateException e) { + this.logger.log(Level.SEVERE, e.toString()); } diff --git a/src/test/java/ug/sparkpl/network/BaseTest.java b/src/test/java/ug/sparkpl/network/BaseTest.java index 69e5f9f..3ef2d0d 100644 --- a/src/test/java/ug/sparkpl/network/BaseTest.java +++ b/src/test/java/ug/sparkpl/network/BaseTest.java @@ -66,7 +66,7 @@ public Gson getGson() { } /** - * Get retrofit token + * Get retrofit token. * * @param url String * @return Retrofit diff --git a/src/test/java/ug/sparkpl/network/collections/LiveUserProvisioningTest.java b/src/test/java/ug/sparkpl/network/collections/LiveUserProvisioningTest.java index 5466e2a..4660dab 100644 --- a/src/test/java/ug/sparkpl/network/collections/LiveUserProvisioningTest.java +++ b/src/test/java/ug/sparkpl/network/collections/LiveUserProvisioningTest.java @@ -66,10 +66,12 @@ public void testUserProvisioning() throws IOException { String token = UUID.randomUUID().toString(); Response res = apiService - .provisonUser(System.getenv("COLLECTION_PRIMARY_KEY"), token, new NewUser("ubuntudata.com")) + .provisonUser(System.getenv("COLLECTION_PRIMARY_KEY"), token, + new NewUser("ubuntudata.com")) .execute(); - Response user = apiService.getUser(token, System.getenv("COLLECTION_PRIMARY_KEY")).execute(); + Response user = apiService.getUser(token, + System.getenv("COLLECTION_PRIMARY_KEY")).execute(); assertNotNull(user); From 2b117abe1f139d682c5277c81a470b26ea9dd2bc Mon Sep 17 00:00:00 2001 From: Moses Mugisha Date: Sat, 2 Nov 2019 12:49:50 +0300 Subject: [PATCH 28/29] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cfcfeb7..b5bcea4 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Add this dependency to your project's POM: Add this dependency to your project's build file: ```groovy -compile "ug.sparkpl:mtnmomo-java:1.0.0" +compile "ug.sparkpl:mtnmomo-java:1.2.0" ``` # Sandbox Environment @@ -234,4 +234,4 @@ The library uses [Project Lombok][lombok]. While it is not a requirement, you mi [lombok]: https://projectlombok.org [lombok-plugins]: https://projectlombok.org/setup/overview -# Thank you. \ No newline at end of file +# Thank you. From 0ce975b3b0ea125041c02c03c4ef137ebc4b2d4e Mon Sep 17 00:00:00 2001 From: Ray Besiga Date: Mon, 14 Jul 2025 14:36:39 +0300 Subject: [PATCH 29/29] Update README.md --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index b5bcea4..3e99f1c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,18 @@ # 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