├── .idea
├── .name
├── codeStyles
│ ├── codeStyleConfig.xml
│ └── Project.xml
├── vcs.xml
├── misc.xml
├── runConfigurations.xml
├── gradle.xml
└── jarRepositories.xml
├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── colors.xml
│ │ │ │ ├── strings.xml
│ │ │ │ └── styles.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── menu
│ │ │ │ └── menu_main.xml
│ │ │ ├── layout
│ │ │ │ ├── content_main.xml
│ │ │ │ ├── fragment_second.xml
│ │ │ │ ├── activity_main.xml
│ │ │ │ └── fragment_first.xml
│ │ │ ├── navigation
│ │ │ │ └── nav_graph.xml
│ │ │ ├── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ └── drawable
│ │ │ │ └── ic_launcher_background.xml
│ │ ├── java
│ │ │ └── bs
│ │ │ │ └── payhero
│ │ │ │ └── app
│ │ │ │ ├── mpesa
│ │ │ │ ├── model
│ │ │ │ │ ├── Environment.kt
│ │ │ │ │ ├── AccessToken.kt
│ │ │ │ │ ├── STKResponse.kt
│ │ │ │ │ └── STKPush.kt
│ │ │ │ ├── interceptor
│ │ │ │ │ ├── AuthInterceptor.kt
│ │ │ │ │ └── AccessTokenInterceptor.kt
│ │ │ │ └── services
│ │ │ │ │ ├── STKPushService.kt
│ │ │ │ │ ├── Constants.kt
│ │ │ │ │ ├── Utils.kt
│ │ │ │ │ └── DarajaApiClient.kt
│ │ │ │ ├── SecondFragment.kt
│ │ │ │ ├── MainActivity.kt
│ │ │ │ └── FirstFragment.kt
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── bs
│ │ │ └── payhero
│ │ │ └── app
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── bs
│ │ └── payhero
│ │ └── app
│ │ └── ExampleInstrumentedTest.kt
├── proguard-rules.pro
└── build.gradle
├── Mpesa Android
├── .gitignore
├── consumer-rules.pro
├── src
│ ├── main
│ │ ├── java
│ │ │ └── bensalcie
│ │ │ │ └── payhero
│ │ │ │ └── mpesa
│ │ │ │ └── mpesa
│ │ │ │ ├── services
│ │ │ │ ├── Constants.kt
│ │ │ │ ├── Environment.kt
│ │ │ │ ├── STKPushService.kt
│ │ │ │ ├── Utils.kt
│ │ │ │ └── DarajaApiClient.kt
│ │ │ │ ├── model
│ │ │ │ ├── AccessToken.kt
│ │ │ │ ├── STKResponse.kt
│ │ │ │ └── STKPush.kt
│ │ │ │ └── interceptor
│ │ │ │ ├── AuthInterceptor.kt
│ │ │ │ └── AccessTokenInterceptor.kt
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── bensalcie
│ │ │ └── payhero
│ │ │ └── mpesa
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── bensalcie
│ │ └── payhero
│ │ └── mpesa
│ │ └── ExampleInstrumentedTest.kt
├── proguard-rules.pro
└── build.gradle
├── screen.jpg
├── screentwo.jpg
├── settings.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── .github
└── FUNDING.yml
├── gradle.properties
├── gradlew.bat
├── README.md
└── gradlew
/.idea/.name:
--------------------------------------------------------------------------------
1 | Pay Hero
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/Mpesa Android/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/Mpesa Android/consumer-rules.pro:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/screen.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bensalcie/payhero-android-mpesa/HEAD/screen.jpg
--------------------------------------------------------------------------------
/screentwo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bensalcie/payhero-android-mpesa/HEAD/screentwo.jpg
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':Mpesa Android'
2 | include ':app'
3 | rootProject.name = "Pay Hero"
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 16dp
3 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bensalcie/payhero-android-mpesa/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bensalcie/payhero-android-mpesa/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bensalcie/payhero-android-mpesa/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bensalcie/payhero-android-mpesa/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bensalcie/payhero-android-mpesa/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bensalcie/payhero-android-mpesa/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bensalcie/payhero-android-mpesa/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bensalcie/payhero-android-mpesa/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bensalcie/payhero-android-mpesa/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bensalcie/payhero-android-mpesa/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bensalcie/payhero-android-mpesa/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #6200EE
4 | #3700B3
5 | #03DAC5
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 |
--------------------------------------------------------------------------------
/Mpesa Android/src/main/java/bensalcie/payhero/mpesa/mpesa/services/Constants.kt:
--------------------------------------------------------------------------------
1 | package bensalcie.payhero.mpesa.mpesa.services
2 |
3 | object Constants {
4 | const val CONNECT_TIMEOUT = 60 * 1000
5 | const val READ_TIMEOUT = 60 * 1000
6 | const val WRITE_TIMEOUT = 60 * 1000
7 | }
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Oct 03 20:46:26 EAT 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
7 |
--------------------------------------------------------------------------------
/Mpesa Android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/java/bs/payhero/app/mpesa/model/Environment.kt:
--------------------------------------------------------------------------------
1 | package bs.payhero.app.mpesa.model
2 |
3 | object Environment {
4 | const val PRODUCTION = "https://api.safaricom.co.ke/"
5 | const val SANDBOX = "https://sandbox.safaricom.co.ke/"
6 |
7 | object TransactionType {
8 | const val CustomerPayBillOnline = "CustomerPayBillOnline"
9 | }
10 | }
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Mpesa Android/src/main/java/bensalcie/payhero/mpesa/mpesa/services/Environment.kt:
--------------------------------------------------------------------------------
1 | package bensalcie.payhero.mpesa.mpesa.services
2 |
3 | object Environment {
4 | const val PRODUCTION = "https://api.safaricom.co.ke/"
5 | const val SANDBOX = "https://sandbox.safaricom.co.ke/"
6 |
7 | object TransactionType {
8 | const val CustomerPayBillOnline = "CustomerPayBillOnline"
9 | }
10 | }
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: # bensalcie
4 | patreon: # bensalcie
5 | open_collective: # bensalcie
6 | ko_fi: # bensalcie
7 | tidelift: # [npn/bensalcie]
8 | community_bridge: # ben-salcie
9 | liberapay: # bensalcie
10 | issuehunt: # bensalcie
11 | otechie: # bensalcie
12 | custom: # ['http://bensalcie.likesyou.org/?i=1', 'http://bensalcie.likesyou.org/?i=1']
13 |
--------------------------------------------------------------------------------
/app/src/main/java/bs/payhero/app/mpesa/model/AccessToken.kt:
--------------------------------------------------------------------------------
1 | package bs.payhero.app.mpesa.model
2 |
3 | import com.google.gson.annotations.Expose
4 | import com.google.gson.annotations.SerializedName
5 |
6 | data class AccessToken (
7 | @SerializedName("access_token")
8 | @Expose
9 | val accessToken:String ?=null,
10 | @SerializedName("expires_in")
11 | @Expose
12 | val expiresIn:String?=null
13 | )
--------------------------------------------------------------------------------
/Mpesa Android/src/main/java/bensalcie/payhero/mpesa/mpesa/model/AccessToken.kt:
--------------------------------------------------------------------------------
1 | package bensalcie.payhero.mpesa.mpesa.model
2 |
3 | import com.google.gson.annotations.Expose
4 | import com.google.gson.annotations.SerializedName
5 |
6 | data class AccessToken (
7 | @SerializedName("access_token")
8 | @Expose
9 | val accessToken:String ?=null,
10 | @SerializedName("expires_in")
11 | @Expose
12 | val expiresIn:String?=null
13 | )
--------------------------------------------------------------------------------
/app/src/test/java/bs/payhero/app/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package bs.payhero.app
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Mpesa Android/src/test/java/bensalcie/payhero/mpesa/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package bensalcie.payhero.mpesa
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/bs/payhero/app/mpesa/model/STKResponse.kt:
--------------------------------------------------------------------------------
1 | package bs.payhero.app.mpesa.model
2 |
3 |
4 | import com.google.gson.annotations.SerializedName
5 |
6 | data class STKResponse(
7 | @SerializedName("CheckoutRequestID")
8 | val checkoutRequestID: String,
9 | @SerializedName("CustomerMessage")
10 | val customerMessage: String,
11 | @SerializedName("MerchantRequestID")
12 | val merchantRequestID: String,
13 | @SerializedName("ResponseCode")
14 | val responseCode: String,
15 | @SerializedName("ResponseDescription")
16 | val responseDescription: String
17 | )
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Pay Hero
3 | Settings
4 |
5 | First Fragment
6 | Second Fragment
7 | Next
8 | Previous
9 |
10 | Hello first fragment
11 | Hello second fragment. Arg: %1$s
12 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/Mpesa Android/src/main/java/bensalcie/payhero/mpesa/mpesa/model/STKResponse.kt:
--------------------------------------------------------------------------------
1 | package bensalcie.payhero.mpesa.mpesa.model
2 |
3 |
4 | import com.google.gson.annotations.SerializedName
5 |
6 | data class STKResponse(
7 | @SerializedName("CheckoutRequestID")
8 | val checkoutRequestID: String,
9 | @SerializedName("CustomerMessage")
10 | val customerMessage: String,
11 | @SerializedName("MerchantRequestID")
12 | val merchantRequestID: String,
13 | @SerializedName("ResponseCode")
14 | val responseCode: String,
15 | @SerializedName("ResponseDescription")
16 | val responseDescription: String
17 | )
--------------------------------------------------------------------------------
/app/src/main/java/bs/payhero/app/mpesa/interceptor/AuthInterceptor.kt:
--------------------------------------------------------------------------------
1 | package bs.payhero.app.mpesa.interceptor
2 |
3 | import okhttp3.Interceptor
4 | import okhttp3.Request
5 | import okhttp3.Response
6 | import java.io.IOException
7 |
8 |
9 | class AuthInterceptor(private val mAuthToken: String) :Interceptor {
10 | @Throws(IOException::class)
11 | override fun intercept(chain: Interceptor.Chain): Response? {
12 | val request: Request = chain.request().newBuilder()
13 | .addHeader("Authorization", "Bearer $mAuthToken")
14 | .build()
15 | return chain.proceed(request)
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/bs/payhero/app/mpesa/services/STKPushService.kt:
--------------------------------------------------------------------------------
1 | package bs.payhero.app.mpesa.services
2 |
3 | import bs.payhero.app.mpesa.model.AccessToken
4 | import bs.payhero.app.mpesa.model.STKPush
5 | import bs.payhero.app.mpesa.model.STKResponse
6 | import retrofit2.Call
7 | import retrofit2.http.Body
8 | import retrofit2.http.GET
9 | import retrofit2.http.POST
10 |
11 |
12 | interface STKPushService {
13 | @POST("mpesa/stkpush/v1/processrequest")
14 | fun sendPush(@Body stkPush: STKPush): Call
15 |
16 | @GET("oauth/v1/generate?grant_type=client_credentials")
17 | fun getAccessToken(): Call
18 | }
--------------------------------------------------------------------------------
/Mpesa Android/src/main/java/bensalcie/payhero/mpesa/mpesa/interceptor/AuthInterceptor.kt:
--------------------------------------------------------------------------------
1 | package bensalcie.payhero.mpesa.mpesa.interceptor
2 |
3 | import okhttp3.Interceptor
4 | import okhttp3.Request
5 | import okhttp3.Response
6 | import java.io.IOException
7 |
8 |
9 | class AuthInterceptor(private val mAuthToken: String) :Interceptor {
10 | @Throws(IOException::class)
11 | override fun intercept(chain: Interceptor.Chain): Response? {
12 | val request: Request = chain.request().newBuilder()
13 | .addHeader("Authorization", "Bearer $mAuthToken")
14 | .build()
15 | return chain.proceed(request)
16 | }
17 | }
--------------------------------------------------------------------------------
/Mpesa Android/src/main/java/bensalcie/payhero/mpesa/mpesa/services/STKPushService.kt:
--------------------------------------------------------------------------------
1 | package bensalcie.payhero.mpesa.mpesa.services
2 |
3 | import bensalcie.payhero.mpesa.mpesa.model.AccessToken
4 | import bensalcie.payhero.mpesa.mpesa.model.STKPush
5 | import bensalcie.payhero.mpesa.mpesa.model.STKResponse
6 | import retrofit2.Call
7 | import retrofit2.http.Body
8 | import retrofit2.http.GET
9 | import retrofit2.http.POST
10 |
11 |
12 | interface STKPushService {
13 | @POST("mpesa/stkpush/v1/processrequest")
14 | fun sendPush(@Body stkPush: STKPush): Call
15 |
16 | @GET("oauth/v1/generate?grant_type=client_credentials")
17 | fun getAccessToken(): Call
18 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/bs/payhero/app/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package bs.payhero.app
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("bs.payhero.app", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/Mpesa Android/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/Mpesa Android/src/androidTest/java/bensalcie/payhero/mpesa/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package bensalcie.payhero.mpesa
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("bensalcie.payhero.mpesa.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/bs/payhero/app/mpesa/interceptor/AccessTokenInterceptor.kt:
--------------------------------------------------------------------------------
1 | package bs.payhero.app.mpesa.interceptor
2 |
3 | import android.util.Base64
4 | import okhttp3.Interceptor
5 | import okhttp3.Request
6 | import okhttp3.Response
7 | import java.io.IOException
8 |
9 |
10 | class AccessTokenInterceptor(private val consumerkey: String, private val consumersecret: String) :
11 | Interceptor {
12 | @Throws(IOException::class)
13 | override fun intercept(chain: Interceptor.Chain): Response? {
14 | val keys: String = "$consumerkey:$consumersecret"
15 | val request: Request = chain.request().newBuilder()
16 | .addHeader(
17 | "Authorization",
18 | "Basic " + Base64.encodeToString(keys.toByteArray(), Base64.NO_WRAP)
19 | )
20 | .build()
21 | return chain.proceed(request)
22 | }
23 | }
--------------------------------------------------------------------------------
/Mpesa Android/src/main/java/bensalcie/payhero/mpesa/mpesa/interceptor/AccessTokenInterceptor.kt:
--------------------------------------------------------------------------------
1 | package bensalcie.payhero.mpesa.mpesa.interceptor
2 |
3 | import android.util.Base64
4 | import okhttp3.Interceptor
5 | import okhttp3.Request
6 | import okhttp3.Response
7 | import java.io.IOException
8 |
9 |
10 | class AccessTokenInterceptor(private val consumerkey:String,private val consumersecret:String):Interceptor {
11 | @Throws(IOException::class)
12 | override fun intercept(chain: Interceptor.Chain): Response? {
13 | val keys = "$consumerkey:$consumersecret"
14 | val request: Request = chain.request().newBuilder()
15 | .addHeader(
16 | "Authorization",
17 | "Basic " + Base64.encodeToString(keys.toByteArray(), Base64.NO_WRAP)
18 | )
19 | .build()
20 | return chain.proceed(request)
21 | }
22 | }
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/java/bs/payhero/app/mpesa/model/STKPush.kt:
--------------------------------------------------------------------------------
1 | package bs.payhero.app.mpesa.model
2 |
3 |
4 | import com.google.gson.annotations.SerializedName
5 | data class STKPush(
6 | @SerializedName("AccountReference")
7 | val accountReference: String,
8 | @SerializedName("Amount")
9 | val amount: String,
10 | @SerializedName("BusinessShortCode")
11 | val businessShortCode: String,
12 | @SerializedName("CallBackURL")
13 | val callBackURL: String,
14 | @SerializedName("PartyA")
15 | val partyA: String,
16 | @SerializedName("PartyB")
17 | val partyB: String,
18 | @SerializedName("Password")
19 | val password: String,
20 | @SerializedName("PhoneNumber")
21 | val phoneNumber: String,
22 | @SerializedName("Timestamp")
23 | val timestamp: String,
24 | @SerializedName("TransactionDesc")
25 | val transactionDesc: String,
26 | @SerializedName("TransactionType")
27 | val transactionType: String
28 | )
--------------------------------------------------------------------------------
/Mpesa Android/src/main/java/bensalcie/payhero/mpesa/mpesa/model/STKPush.kt:
--------------------------------------------------------------------------------
1 | package bensalcie.payhero.mpesa.mpesa.model
2 |
3 |
4 | import com.google.gson.annotations.SerializedName
5 | data class STKPush(
6 | @SerializedName("AccountReference")
7 | val accountReference: String,
8 | @SerializedName("Amount")
9 | val amount: String,
10 | @SerializedName("BusinessShortCode")
11 | val businessShortCode: String,
12 | @SerializedName("CallBackURL")
13 | val callBackURL: String,
14 | @SerializedName("PartyA")
15 | val partyA: String,
16 | @SerializedName("PartyB")
17 | val partyB: String,
18 | @SerializedName("Password")
19 | val password: String,
20 | @SerializedName("PhoneNumber")
21 | val phoneNumber: String,
22 | @SerializedName("Timestamp")
23 | val timestamp: String,
24 | @SerializedName("TransactionDesc")
25 | val transactionDesc: String,
26 | @SerializedName("TransactionType")
27 | val transactionType: String
28 | )
--------------------------------------------------------------------------------
/app/src/main/res/layout/content_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
--------------------------------------------------------------------------------
/app/src/main/java/bs/payhero/app/mpesa/services/Constants.kt:
--------------------------------------------------------------------------------
1 | package bs.payhero.app.mpesa.services
2 |
3 | object Constants {
4 | const val CONNECT_TIMEOUT = 60 * 1000
5 |
6 | const val READ_TIMEOUT = 60 * 1000
7 |
8 | const val WRITE_TIMEOUT = 60 * 1000
9 |
10 | // const val BASE_URL = "https://sandbox.safaricom.co.ke/"
11 | // const val PRODUCTION_BASE_URL = "https://api.safaricom.co.ke/"
12 | //mpesa/stkpush/v1/processrequest
13 | // https://api.safaricom.co.ke/mpesa/stkpush/v1/processrequest
14 | const val BUSINESS_SHORT_CODE = "4060195"
15 |
16 | // const val BUSINESS_SHORT_CODE = "174379"
17 | val PASSKEY = "6ef546b207f07d6582f52ae916b0711b76064e6e7a47a2c439c2a2cb5dd9fad3"
18 | const val TRANSACTION_TYPE = "CustomerPayBillOnline"
19 |
20 | // const val PARTYB = "174379" //same as business shortcode above
21 | const val PARTYB = "4060195" //same as business shortcode above
22 |
23 | const val CALLBACKURL = "https://payherokenya.com/phk/c2bcallback.php"
24 |
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/bs/payhero/app/mpesa/services/Utils.kt:
--------------------------------------------------------------------------------
1 | package bs.payhero.app.mpesa.services
2 |
3 | import android.util.Base64;
4 |
5 | import java.text.SimpleDateFormat;
6 | import java.util.Date;
7 | import java.util.Locale;
8 |
9 | object Utils {
10 | fun getTimestamp(): String? {
11 | return SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault()).format(Date())
12 | }
13 |
14 | fun sanitizePhoneNumber(phone: String): String? {
15 | if (phone == "") {
16 | return ""
17 | }
18 | if (phone.length < 11 && phone.startsWith("0")) {
19 | return phone.replaceFirst("^0".toRegex(), "254")
20 | }
21 | return if (phone.length == 13 && phone.startsWith("+")) {
22 | phone.replaceFirst("^+".toRegex(), "")
23 | } else phone
24 | }
25 |
26 | fun getPassword(businessShortCode: String, passkey: String, timestamp: String): String? {
27 | val str = businessShortCode + passkey + timestamp
28 | //encode the password to Base64
29 | return Base64.encodeToString(str.toByteArray(), Base64.NO_WRAP)
30 | }
31 | }
--------------------------------------------------------------------------------
/app/src/main/java/bs/payhero/app/SecondFragment.kt:
--------------------------------------------------------------------------------
1 | package bs.payhero.app
2 |
3 | import android.os.Bundle
4 | import androidx.fragment.app.Fragment
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import android.widget.Button
9 | import androidx.navigation.fragment.findNavController
10 |
11 | /**
12 | * A simple [Fragment] subclass as the second destination in the navigation.
13 | */
14 | class SecondFragment : Fragment() {
15 |
16 | override fun onCreateView(
17 | inflater: LayoutInflater, container: ViewGroup?,
18 | savedInstanceState: Bundle?
19 | ): View? {
20 | // Inflate the layout for this fragment
21 | return inflater.inflate(R.layout.fragment_second, container, false)
22 | }
23 |
24 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
25 | super.onViewCreated(view, savedInstanceState)
26 |
27 | view.findViewById