From 5fa47937856d269376eab1322f107be3a20a373b Mon Sep 17 00:00:00 2001 From: Victor Kabata Date: Fri, 30 Aug 2024 15:39:48 +0300 Subject: [PATCH 01/14] Added koin bom and koin android --- samples/android/app/build.gradle.kts | 6 ++++++ samples/android/gradle/libs.versions.toml | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/samples/android/app/build.gradle.kts b/samples/android/app/build.gradle.kts index 6f0f9e7d..d6168ab5 100644 --- a/samples/android/app/build.gradle.kts +++ b/samples/android/app/build.gradle.kts @@ -59,11 +59,17 @@ dependencies { implementation(libs.androidx.ui.graphics) implementation(libs.androidx.ui.tooling.preview) implementation(libs.androidx.material3) + + implementation(platform(libs.koin.bom)) + implementation(libs.koin.android) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) androidTestImplementation(platform(libs.androidx.compose.bom)) androidTestImplementation(libs.androidx.ui.test.junit4) + debugImplementation(libs.androidx.ui.tooling) debugImplementation(libs.androidx.ui.test.manifest) } \ No newline at end of file diff --git a/samples/android/gradle/libs.versions.toml b/samples/android/gradle/libs.versions.toml index d4d4d6c2..eddd3b74 100644 --- a/samples/android/gradle/libs.versions.toml +++ b/samples/android/gradle/libs.versions.toml @@ -8,6 +8,7 @@ espressoCore = "3.6.1" lifecycleRuntimeKtx = "2.8.4" activityCompose = "1.9.1" composeBom = "2024.04.01" +koinBom = "3.5.6" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -25,6 +26,9 @@ androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-man androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } androidx-material3 = { group = "androidx.compose.material3", name = "material3" } +koin-bom = { module = "io.insert-koin:koin-bom", version.ref = "koinBom" } +koin-android = { module = "io.insert-koin:koin-androidx-compose" } + [plugins] android-application = { id = "com.android.application", version.ref = "agp" } jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } From a5dfb7ab5cd7881941add86d3badb71b46a18fda Mon Sep 17 00:00:00 2001 From: Victor Kabata Date: Fri, 30 Aug 2024 15:41:25 +0300 Subject: [PATCH 02/14] Added daraja lib --- samples/android/app/build.gradle.kts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/samples/android/app/build.gradle.kts b/samples/android/app/build.gradle.kts index d6168ab5..fe2b2e9e 100644 --- a/samples/android/app/build.gradle.kts +++ b/samples/android/app/build.gradle.kts @@ -62,7 +62,9 @@ dependencies { implementation(platform(libs.koin.bom)) implementation(libs.koin.android) - + + implementation("io.github.victorkabata:daraja-multiplatform:0.9.5") + testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) From 7f291f5ec69cbf41d6d182c9c67cdd973e8fa261 Mon Sep 17 00:00:00 2001 From: Victor Kabata Date: Fri, 30 Aug 2024 16:43:53 +0300 Subject: [PATCH 03/14] Update publish_kmp_lib.yml --- .github/workflows/publish_kmp_lib.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish_kmp_lib.yml b/.github/workflows/publish_kmp_lib.yml index b94f564d..19fa1e66 100644 --- a/.github/workflows/publish_kmp_lib.yml +++ b/.github/workflows/publish_kmp_lib.yml @@ -32,7 +32,7 @@ jobs: run: ./gradlew :daraja:allTests --stacktrace - name: Sign and Publish Android Library - run: ./gradlew :daraja:publishAllPublicationsToSonatypeRepository --max-workers 1 --stacktrace + run: ./gradlew clean publishAllPublicationsToSonatypeRepository --max-workers 1 --stacktrace env: OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} From 32b60920cbe0965707a730dedd73f2d99f339c12 Mon Sep 17 00:00:00 2001 From: Victor Kabata Date: Mon, 2 Sep 2024 08:44:13 +0300 Subject: [PATCH 04/14] Update daraja kmp version from v0.9.5 to v0.9.6 --- samples/android/app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/android/app/build.gradle.kts b/samples/android/app/build.gradle.kts index fe2b2e9e..ef1554c9 100644 --- a/samples/android/app/build.gradle.kts +++ b/samples/android/app/build.gradle.kts @@ -63,7 +63,7 @@ dependencies { implementation(platform(libs.koin.bom)) implementation(libs.koin.android) - implementation("io.github.victorkabata:daraja-multiplatform:0.9.5") + implementation("io.github.victorkabata:daraja-multiplatform:0.9.6") testImplementation(libs.junit) From b257af3d762a5d7af9f7d4099ade5e27566ff0ab Mon Sep 17 00:00:00 2001 From: Victor Kabata Date: Mon, 2 Sep 2024 09:47:40 +0300 Subject: [PATCH 05/14] Set up singleton instance of Daraja --- .../com/vickbt/daraja/android/di/AppModule.kt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 samples/android/app/src/main/java/com/vickbt/daraja/android/di/AppModule.kt diff --git a/samples/android/app/src/main/java/com/vickbt/daraja/android/di/AppModule.kt b/samples/android/app/src/main/java/com/vickbt/daraja/android/di/AppModule.kt new file mode 100644 index 00000000..78a5e801 --- /dev/null +++ b/samples/android/app/src/main/java/com/vickbt/daraja/android/di/AppModule.kt @@ -0,0 +1,16 @@ +package com.vickbt.daraja.android.di + +import com.vickbt.darajakmp.Daraja +import org.koin.dsl.module + +val appModule = module { + // Provide a single instance of Daraja + single { + Daraja.Builder() + .setConsumerKey("") + .setConsumerSecret("") + .setPassKey("") + .isSandbox() + .build() + } +} \ No newline at end of file From 49b8bfe9f7688ad56c924e31a3ded0dc33a90822 Mon Sep 17 00:00:00 2001 From: Victor Kabata Date: Mon, 2 Sep 2024 09:49:06 +0300 Subject: [PATCH 06/14] Set up artifact_id in deployment workflow --- .github/workflows/publish_kmp_lib.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/publish_kmp_lib.yml b/.github/workflows/publish_kmp_lib.yml index 19fa1e66..80a975f1 100644 --- a/.github/workflows/publish_kmp_lib.yml +++ b/.github/workflows/publish_kmp_lib.yml @@ -40,6 +40,7 @@ jobs: POM_NAME: ${{ secrets.POM_NAME }} POM_DESCRIPTION: ${{ secrets.POM_DESCRIPTION }} POM_GROUPID: ${{ secrets.POM_GROUPID }} + POM_ARTIFACTID: ${{secrets.POM_ARTIFACTID}} POM_URL: ${{ secrets.POM_URL }} POM_DEVELOPER_ID: ${{ secrets.POM_DEVELOPER_ID }} POM_DEVELOPER_NAME: ${{ secrets.POM_DEVELOPER_NAME }} From 0b56ecde4d14ccbeb0dac5ee73e0a90497c647fd Mon Sep 17 00:00:00 2001 From: Victor Kabata Date: Mon, 2 Sep 2024 14:54:24 +0300 Subject: [PATCH 07/14] Set up base android sample --- .../android/app/src/main/AndroidManifest.xml | 3 ++ .../android/DarajaAndroidApplication.kt | 20 ++++++++++++ .../android/ui/screen/MpesaExpressScreen.kt | 31 ++++++++++++------- 3 files changed, 42 insertions(+), 12 deletions(-) create mode 100644 samples/android/app/src/main/java/com/vickbt/daraja/android/DarajaAndroidApplication.kt diff --git a/samples/android/app/src/main/AndroidManifest.xml b/samples/android/app/src/main/AndroidManifest.xml index 5885a0c1..1408c004 100644 --- a/samples/android/app/src/main/AndroidManifest.xml +++ b/samples/android/app/src/main/AndroidManifest.xml @@ -2,7 +2,10 @@ + + Date: Mon, 2 Sep 2024 15:13:41 +0300 Subject: [PATCH 08/14] Set up mpesa express screen functionality --- .../com/vickbt/daraja/android/di/AppModule.kt | 6 +- .../android/ui/screen/MpesaExpressScreen.kt | 71 +++++++++++++------ 2 files changed, 51 insertions(+), 26 deletions(-) diff --git a/samples/android/app/src/main/java/com/vickbt/daraja/android/di/AppModule.kt b/samples/android/app/src/main/java/com/vickbt/daraja/android/di/AppModule.kt index 78a5e801..26e938f6 100644 --- a/samples/android/app/src/main/java/com/vickbt/daraja/android/di/AppModule.kt +++ b/samples/android/app/src/main/java/com/vickbt/daraja/android/di/AppModule.kt @@ -7,9 +7,9 @@ val appModule = module { // Provide a single instance of Daraja single { Daraja.Builder() - .setConsumerKey("") - .setConsumerSecret("") - .setPassKey("") + .setConsumerKey("consumer_key") + .setConsumerSecret("consumer_secret") + .setPassKey("pass_key") .isSandbox() .build() } diff --git a/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/screen/MpesaExpressScreen.kt b/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/screen/MpesaExpressScreen.kt index 3add0dba..e40ce14c 100644 --- a/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/screen/MpesaExpressScreen.kt +++ b/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/screen/MpesaExpressScreen.kt @@ -2,7 +2,10 @@ package com.vickbt.daraja.android.ui.screen +import android.util.Log +import android.widget.Toast import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.size @@ -11,6 +14,7 @@ import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.rounded.Send +import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.FloatingActionButtonDefaults @@ -27,23 +31,29 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.vickbt.darajakmp.Daraja import com.vickbt.darajakmp.utils.DarajaTransactionType +import com.vickbt.darajakmp.utils.onFailure +import com.vickbt.darajakmp.utils.onSuccess import org.koin.compose.koinInject @Composable fun MpesaExpressScreen(modifier: Modifier = Modifier, daraja: Daraja = koinInject()) { + val context = LocalContext.current + val tillNumber by remember { mutableStateOf("174379") } var amount by remember { mutableIntStateOf(1) } var phoneNumber by remember { mutableStateOf("") } + var isLoading by remember { mutableStateOf(false) } + Column( modifier = modifier.wrapContentSize(), verticalArrangement = Arrangement.spacedBy( @@ -86,29 +96,44 @@ fun MpesaExpressScreen(modifier: Modifier = Modifier, daraja: Daraja = koinInjec // keyboardActions = KeyboardOptions.Default.copy(imeAction = ImeAction.Done) ) - FloatingActionButton( - modifier = Modifier, - shape = CircleShape, - containerColor = MaterialTheme.colorScheme.primary, - contentColor = MaterialTheme.colorScheme.onPrimary, - elevation = FloatingActionButtonDefaults.elevation(), - onClick = { - daraja.mpesaExpress( - businessShortCode = tillNumber, - amount = amount, - phoneNumber = phoneNumber, - transactionType = DarajaTransactionType.CustomerPayBillOnline, - transactionDesc = "Empty transaction to test SDK", - callbackUrl = "https://mydomain.com", - accountReference = "CompanyX" + Log.e("VicKbt", "Is loading: $isLoading") + + Box(modifier = Modifier){ + FloatingActionButton( + modifier = Modifier.align(Alignment.Center), + shape = CircleShape, + containerColor = MaterialTheme.colorScheme.primary, + contentColor = MaterialTheme.colorScheme.onPrimary, + elevation = FloatingActionButtonDefaults.elevation(), + onClick = { + isLoading = true + + daraja.mpesaExpress( + businessShortCode = tillNumber, + amount = amount, + phoneNumber = phoneNumber, + transactionType = DarajaTransactionType.CustomerPayBillOnline, + transactionDesc = "Empty transaction to test SDK", + callbackUrl = "https://mydomain.com", + accountReference = "CompanyX" + ).onSuccess { + Toast.makeText(context, "Success: $it", Toast.LENGTH_SHORT).show() + }.onFailure { + Toast.makeText(context, "Error: ${it.errorMessage}", Toast.LENGTH_SHORT).show() + } + + }, + ) { + Icon( + modifier = Modifier.size(28.dp), + imageVector = Icons.AutoMirrored.Rounded.Send, + contentDescription = "Pay" ) - }, - ) { - Icon( - modifier = Modifier.size(28.dp), - imageVector = Icons.AutoMirrored.Rounded.Send, - contentDescription = "Pay" - ) + } + + if (isLoading){ + CircularProgressIndicator(modifier = Modifier.align(Alignment.Center), trackColor = MaterialTheme.colorScheme.onPrimary) + } } } } From 634bb056a0c4c2a3c95c77bc4badf8eeeae82a4d Mon Sep 17 00:00:00 2001 From: Victor Kabata Date: Wed, 4 Sep 2024 10:26:02 +0300 Subject: [PATCH 09/14] Fix github security warning --- .github/workflows/publish_swift_package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish_swift_package.yml b/.github/workflows/publish_swift_package.yml index 0be89cf1..7d2013e8 100644 --- a/.github/workflows/publish_swift_package.yml +++ b/.github/workflows/publish_swift_package.yml @@ -44,7 +44,7 @@ jobs: uses: actions/checkout@v4 - name: Download directory with swift package - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: swiftpackage path: swiftpackage From d7d276fd9da8b930cf9b0a3c1f91b1c395076d1c Mon Sep 17 00:00:00 2001 From: Victor Kabata <39780120+VictorKabata@users.noreply.github.com> Date: Tue, 17 Sep 2024 11:07:18 +0300 Subject: [PATCH 10/14] Create LICENSE --- LICENSE | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..319a0d1a --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2022 Victor Kabata + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. From 23b1dcc99f13e9bfcb69b722ac84d4e3654b5c86 Mon Sep 17 00:00:00 2001 From: Victor Kabata Date: Tue, 17 Sep 2024 11:08:32 +0300 Subject: [PATCH 11/14] Update readme doc --- README.md | 378 +------------------------------------------------- docs/index.md | 24 ++-- mkdocs.yml | 2 +- 3 files changed, 20 insertions(+), 384 deletions(-) diff --git a/README.md b/README.md index 14940062..e777bf0d 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,6 @@

-## ⚠️Work in progress - Sandbox Mode⚠️ - [Kotlin multiplatform](https://kotlinlang.org/docs/multiplatform.html) wrapper for Mpesa API dubbed [_Daraja API_](https://developer.safaricom.co.ke/) (Daraja means bridge in Swahili) that supports integration with your Android(Kotlin/Java), iOS(Swift) and JVM applications. @@ -16,27 +14,16 @@ supports integration with your Android(Kotlin/Java), iOS(Swift) and JVM applicat > M-PESA is a mobile money transfer service in Kenya that allows users to store and transfer money > through their mobile phones. +> > [!WARNING] +> Daraja Multiplatform is under heavy development and, despite being heavily tested, its API isn't yet stabilized; _breaking changes +> might happen on minor releases._ However, we will always provide migration guides. +> +> Report any issue or bug in the GitHub repository. + ## Table of Content - [Prerequisite](#prerequisite) - [Features](#features) -- [Usage](#usage) - - [Android - Kotlin](#android---kotlin) - - [Setting Up](#setting-up) - - [Request Access Token](#request-access-token) - - [Initiate M-Pesa Express STK Request](#initiate-m-pesa-express-stk-request) - - [Dynamic QR](#generate-dynamic-qr-code) - - [Query M-Pesa Transaction](#query-m-pesa-transaction) - - [Customer To Business(C2B)](#customer-to-businessc2b) - - [Account Balance](#account-balance) - - [iOS - Swift](#ios---swift) - - [Setting Up](#setting-up-1) - - [Request Access Token](#request-access-token) - - [Initiate M-Pesa Express STK Request](#initiate-m-pesa-express-stk-request-1) - - [Dynamic QR](#generate-dynamic-qr-code) - - [Query M-Pesa Transaction](#query-m-pesa-transaction-1) - - [Customer To Business(C2B)](#customer-to-businessc2b) - - [Account Balance](#account-balance) ## Prerequisite @@ -67,358 +54,7 @@ The SDK offers the following functionalities from the Daraja API: - [ ] Business Buy Goods - Pay for goods and services directly from your business account to a till number or merchant store number. -## Usage - -# Android - Kotlin - -### Setting Up - -- In your android application project-level gradle file add the following dependency: - -
-Kotlin - -```Kotlin - dependencies { - implementation("io.github.victorkabata:daraja-multiplatform:0.9.3") -} -``` - -
- -
-Groovy - -```Groovy - dependencies { - implementation 'io.github.victorkabata:daraja-multiplatform:0.9.3' -} -``` - -
- -- Add your consumer secret, consumer key and pass key to your project. You can get them from - the [Daraja API portal](https://developer.safaricom.co.ke/MyApps). - -> You should not add your daraja API environment variables in a production application because it is -> a vulnerability to expose your environment secrets/variables in your version control system. -> Ideally, you should add them to your `local.properties` files as demonstrated in -> the [sample](https://github.com/VictorKabata/DarajaMultiplatform/tree/main/app-android) android -> application. - -- Create an instance of the Daraja object by passing the daraja environment variables. The daraja - object provides functions to request for an access token and initiate M-Pesa express STK request. - -```Kotlin -val daraja: Daraja = Daraja.Builder() - .setConsumerSecret("your_consumer_secret") - .setConsumerKey("your_consumer_key") - .setPassKey("your_pass_key") - .isProduction() // Optional. Will default to sandbox_mode = true - .build() -``` - -> Network logging is enabled by default when using Daraja Multiplatform. in sandbox/testing mode. -> The logs can be accessed from the logcat in Android Studio under the `Daraja Multiplatform` tag. - -> Network logs are disabled in production mode. - -### Request Access Token - -- To request an access token from Daraja API, invoke the `authorization` function: - -```Kotlin -val accessTokenResult: DarajaResult = daraja.authorization() - -accessTokenResult - .onSuccess { accessToken -> - // Successfully fetched daraja access token - } - .onFailure { error -> - // Failure fetching daraja access token - } -``` - -### Initiate M-Pesa Express STK Request - -- To initiate M-Pesa Express(Lipa na M-Pesa Online) STK request, invoke the `mpesaExpress` function: - -```kotlin -val darajaPaymentResponse: DarajaResult = daraja.mpesaExpress( - businessShortCode = "174379", - amount = 1, - phoneNumber = "07xxxxxxxx", - transactionDesc = "M-Pesa payment", - callbackUrl = "your_callback_url", - accountReference = "CompanyName" -) - -darajaPaymentResponse.onSuccess { paymentResponse -> - // Successfully requested M-Pesa STK request -}.onFailure { error -> - // Failed to request M-Pesa STK -} -``` - -### Query M-Pesa Express STK - -- To check the status of M-Pesa Express(Lipa na M-Pesa Online) STK request, invoke the `mpesaExpressQuery` function: - -```kotlin -val darajaMpesaExpressQuery:DarajaResult = daraja.mpesaExpressQuery( - businessShortCode = "174379", - timeStamp = "20160216165627", - checkOutRequestID = "ws_CO_260520211133524545" -) - -darajaMpesaExpressQuery.onSuccess{ mpesaExpressQuery-> - // Successfully request M-Pesa STK request status -}.onFailure{ error-> - // Failed to request M-Pesa STK status -} -``` - - - - - -### Customer To Business(C2B) - -- To register the C2B validation and confirmation URL, invoke the `c2bRegistration` function: - -```kotlin -val darajaC2BRegistrationResponse: DarajaResult = daraja.c2bRegistration( - confirmationURL = "https://mydomain.com/confirmation", - responseType = C2BResponseType.COMPLETED, // C2BResponseType.CANCELLED - businessShortCode = 600981, - validationURL = "https://mydomain.com/validation" -) - -darajaC2BRegistrationResponse.onSuccess { - // Successfully registered confirmation and validation URL -}.onFailure { - // Failure registering confirmation and validation URL -} - -``` - -- To initiate a Customer to Business paybill, invoke the `c2b` function: - -```kotlin -val c2bResponse: DarajaResult = daraja.c2b( - amount = 1, - billReferenceNumber = "600977", - transactionType = DarajaTransactionType.CustomerBuyGoodsOnline, // DarajaTransactionType.CustomerPayBillOnline - phoneNumber = "0708374149", - businessShortCode = "600977" //Optional when using CustomerBuyGoodsOnline -) - -c2bResponse.onSuccess { - // Successfully invoked C2B request -}.onFailure { - // Failure invoking C2B request -} -``` - -### Account Balance - -Request the account balance of a short code. This can be used for both B2C, buy goods and pay bill -accounts. - -```kotlin - val accountBalanceResponse = daraja.accountBalance( - initiator = "testapi", - initiatorPassword = "Safaricom999!*!", - partyA = 600987, - identifierType = DarajaIdentifierType.TILL_NUMBER, - queueTimeOutURL = "https://mydomain.com/AccountBalance/queue/", - resultURL = "https://mydomain.com/AccountBalance/result/" -) - -accountBalanceResponse.onSuccess { - // Successfully request account balance -}.onFailure { - // Failed to request account balance -} -``` - -# iOS - Swift - -### Setting Up - -- To add **_DarajaMultiplatform_** package to your Xcode Project, open your Xcode project, navigate - to the File tab within the macOS bar and click **Select Packages** then **Add Package Dependency - **. Enter the package name ie. DarajaMultiplatform or the URL package GitHub URL: - -```curl -https://github.com/VictorKabata/DarajaSwiftPackage.git -``` - -https://github.com/VictorKabata/DarajaSwiftPackage/assets/39780120/b9283612-3c5e-4100-aff8-c2c0d9f31863 - -- Create an instance of the Daraja object by passing the daraja environment variables. The daraja - object provides functions to request for an access token and initiate M-Pesa express STK request. - -```swift -var daraja=Daraja( - consumerKey: "your_consumer_key", - consumerSecret: "your_customer_secret", - passKey:"your_pass_key", - environment: DarajaEnvironment.sandboxEnvironment - ) -``` - -> Network logging is enabled by default when using Daraja Multiplatform. in sandbox/testing mode. -> The logs can be accessed from the logs in XCode IDE - -> Network logs are strictly disabled in production mode ie. DarajaEnvironment.productionEnvironment - -### Request Access Token - -- To request an access token from Daraja API, invoke the `authorization` function: - -```swift -var accessTokenResult = daraja.authorization() - -accessTokenResult.onSuccess(action: { accessToken in - // Successfully fetched daraja access token - // Successfully fetched the access token - }).onFailure(action: { error in - // Failure fetching daraja access token - }) -``` - -### Initiate M-Pesa Express STK Request - -- To initiate M-Pesa Express(Lipa na M-Pesa Online) STK request, invoke the `mpesaExpress` function: - -```swift -var darajaResponse = daraja.mpesaExpress( - businessShortCode: "174379", - amount: 1, - phoneNumber: "07xxxxxxxx", - transactionType: DarajaTransactionType.customerpaybillonline, transactionDesc: "M-Pesa payment", - callbackUrl: "https://mydomain.com/path", - accountReference: "Company name") - - darajaResponse.onSuccess(action: { data in - // Successfully requested M-Pesa STK request - }) - .onFailure(action: { error in - // Failed to request M-Pesa STK - }) - -``` - -### Query M-Pesa Express STK - -- To check the status of M-Pesa Express(Lipa na M-Pesa Online) STK request, invoke the `mpesaExpressQuery` function: - -```swift -var mpesaExpressQuery = daraja.mpesaExpressQuery( - businessShortCode: "174379", - timestamp: "20160216165627", - checkoutRequestID: "ws_CO_260520211133524545" -) - -mpesaExpressQuery.onSuccess(action:{ data in -// Successfully requested M-Pesa STK request status -}) -.onFailure(action: {error in -// Failed to request M-Pesa STK status -}) -``` - - - - - - \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index ff324186..48bfceab 100644 --- a/docs/index.md +++ b/docs/index.md @@ -16,19 +16,19 @@ Currently, Daraja Multiplatform supports Kotlin and Swift applications. Core features include: -* [x] Authorization - Gives you a time bound access token to call allowed APIs. -- [x] M-Pesa Express - Merchant initiated online payments. -- [x] M-Pesa Express Query - Check the status of a Lipa Na M-Pesa Online Payment(M-Pesa Express). -- [ ] Dynamic QR - Generates a dynamic M-PESA QR code. -- [ ] Customer To Business (C2B) -- [ ] Business To Customer (B2C) - Transact between an M-Pesa short code to a phone number +* Authorization - Gives you a time bound access token to call allowed APIs. +- M-Pesa Express - Merchant initiated online payments. +- M-Pesa Express Query - Check the status of a Lipa Na M-Pesa Online Payment(M-Pesa Express). +- Dynamic QR - Generates a dynamic M-PESA QR code. +- Customer To Business (C2B) +- Business To Customer (B2C) - Transact between an M-Pesa short code to a phone number registered on M-Pesa. -- [ ] Transaction Status - Check the status of a transaction. -- [ ] Account Balance - Enquire the balance on an M-Pesa BuyGoods (Till Number) -- [ ] Reversal - Reverses an M-Pesa transaction. -- [ ] Tax Remittance - This API enables businesses to remit tax to Kenya Revenue Authority (KRA). -- [ ] Business Pay Bill - Pay bills directly from your business account to a pay bill number, or a +- Transaction Status - Check the status of a transaction. +- Account Balance - Enquire the balance on an M-Pesa BuyGoods (Till Number) +- Reversal - Reverses an M-Pesa transaction. +- Tax Remittance - This API enables businesses to remit tax to Kenya Revenue Authority (KRA). +- Business Pay Bill - Pay bills directly from your business account to a pay bill number, or a paybill store. -- [ ] Business Buy Goods - Pay for goods and services directly from your business account to a till number or merchant store number. +- Business Buy Goods - Pay for goods and services directly from your business account to a till number or merchant store number. diff --git a/mkdocs.yml b/mkdocs.yml index faf9731d..043b417b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -11,7 +11,7 @@ remote_branch: gh-pages nav: - Overview: index.md - Kotlin SDK: kotlin.md - - Swift SDK: swift.md +# - Swift SDK: swift.md theme: name: material From 5e4214fecc095213d369dcce0a245492726f9b9d Mon Sep 17 00:00:00 2001 From: Victor Kabata Date: Tue, 17 Sep 2024 11:24:22 +0300 Subject: [PATCH 12/14] Update mkdocs theme --- mkdocs.yml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/mkdocs.yml b/mkdocs.yml index 043b417b..d3aa1c01 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -16,6 +16,9 @@ nav: theme: name: material language: en + font: + text: Roboto + code: Roboto Mono features: - navigation.tabs - navigation.sections @@ -29,18 +32,18 @@ theme: - scheme: default media: "(prefers-color-scheme: light)" toggle: - icon: material/brightness-7 + icon: material/weather-night name: Switch to dark theme - primary: teal - accent: purple + primary: green + accent: green - scheme: slate media: "(prefers-color-scheme: dark)" toggle: - icon: material/brightness-4 + icon: material/weather-sunny name: Switch to light theme - primary: teal - accent: lime + primary: green + accent: green markdown_extensions: - pymdownx.highlight: From e4639c91552a0259fab3b0deb090a98b937a97dd Mon Sep 17 00:00:00 2001 From: Victor Kabata Date: Tue, 17 Sep 2024 11:30:05 +0300 Subject: [PATCH 13/14] Create documentation workflow --- .github/workflows/documentation.yml | 37 +++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/documentation.yml diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml new file mode 100644 index 00000000..33d9bac0 --- /dev/null +++ b/.github/workflows/documentation.yml @@ -0,0 +1,37 @@ +name: Deploy Documentation + +on: + workflow_dispatch: + push: + branches: + - main +permissions: + contents: write + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: 3.x + + - name: Set up cache + uses: actions/cache@v2 + with: + key: ${{ github.ref }} + path: .cache + + - name: Install MkDocs-Material + run: pip install mkdocs-material + + - name: Install Pillow CairoSVG + run: pip install pillow cairosvg + + - name: Deploy GH-Page + run: mkdocs gh-deploy --force \ No newline at end of file From ef266e34b5718d3953ce286689bcf48a879c1b40 Mon Sep 17 00:00:00 2001 From: Victor Kabata Date: Tue, 17 Sep 2024 11:31:51 +0300 Subject: [PATCH 14/14] Linting --- .github/workflows/documentation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 33d9bac0..635c36d4 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -7,7 +7,7 @@ on: - main permissions: contents: write - + jobs: deploy: runs-on: ubuntu-latest