diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..0139eac
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,36 @@
+---
+name: Bug report
+about: Report a bug to help us improve
+title: "[BUG]"
+labels: bug
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**This issue addresses below module/s**
+- [ ] app
+- [ ] core
+- [ ] other/documentation
+
+**Device Information:**
+ - Device: [e.g. Pixel 4]
+ - Version: [e.g. 8.0]
+
+**Additional context**
+Add any other context about the problem here.
+
+**Would you like to work on this issue**
+- [ ] Yes
+- [ ] No
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..586590b
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,29 @@
+---
+name: Feature request
+about: Request new feature to make sdk more optimized
+title: "[Feature]"
+labels: feature
+assignees: ''
+
+---
+
+**Describe the new feature**
+A clear and concise description of what the feature is about.
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
+
+**Device Information:**
+Add device information if feature is device specific
+ - Device: [e.g. Pixel XL4]
+ - Version: [e.g. 8.0]
+
+**Would you like to work on this issue**
+- [ ] Yes
+- [ ] No
\ No newline at end of file
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..67d557e
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,17 @@
+Fixes #issue_number
+
+**Description**
+Include a summary of the change and which issue is fixed. List any dependencies that are required for this change.
+
+**Please Add Screenshots If there are any UI changes.**
+Use `` syntax to add screenshot.
+
+**This app make changes to below module/s**
+- [ ] app
+- [ ] core
+- [ ] other/documentation
+
+**Please make sure these boxes are checked before submitting your pull request - thanks!**
+- [ ] Build the project with `./gradlew build` to make sure you didn't break anything
+- [ ] Added the comments particularly in hard-to-understand areas
+- [ ] In case of multiple commits please squash them
\ No newline at end of file
diff --git a/.github/workflows/build_check.yml b/.github/workflows/build_check.yml
new file mode 100644
index 0000000..f9bc8d3
--- /dev/null
+++ b/.github/workflows/build_check.yml
@@ -0,0 +1,36 @@
+name: Project Build
+
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+ branches:
+ - master
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v1
+
+ # Cache dependencies
+ - name: Cache Gradle packages
+ uses: actions/cache@v2
+ with:
+ path: |
+ ~/.gradle/caches
+ ~/.gradle/wrapper
+ key: ${{ runner.OS }}-gradle-cache-${{ hashFiles('**/build.gradle') }}
+
+ # jdk 17
+ - name: Set Up JDK
+ uses: actions/setup-java@v1
+ with:
+ java-version: 17
+
+ - name: Run test
+ run: ./gradlew check
+
+ - name: Build
+ run: ./gradlew build
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7facdb5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+*.iml
+.gradle
+/local.properties
+/.idea
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..a612ad9
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,373 @@
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+ means each individual or legal entity that creates, contributes to
+ the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+ means the combination of the Contributions of others (if any) used
+ by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+ means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+ means Source Code Form to which the initial Contributor has attached
+ the notice in Exhibit A, the Executable Form of such Source Code
+ Form, and Modifications of such Source Code Form, in each case
+ including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+ means
+
+ (a) that the initial Contributor has attached the notice described
+ in Exhibit B to the Covered Software; or
+
+ (b) that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the
+ terms of a Secondary License.
+
+1.6. "Executable Form"
+ means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+ means a work that combines Covered Software with other material, in
+ a separate file or files, that is not Covered Software.
+
+1.8. "License"
+ means this document.
+
+1.9. "Licensable"
+ means having the right to grant, to the maximum extent possible,
+ whether at the time of the initial grant or subsequently, any and
+ all of the rights conveyed by this License.
+
+1.10. "Modifications"
+ means any of the following:
+
+ (a) any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered
+ Software; or
+
+ (b) any new file in Source Code Form that contains any Covered
+ Software.
+
+1.11. "Patent Claims" of a Contributor
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the
+ License, by the making, using, selling, offering for sale, having
+ made, import, or transfer of either its Contributions or its
+ Contributor Version.
+
+1.12. "Secondary License"
+ means either the GNU General Public License, Version 2.0, the GNU
+ Lesser General Public License, Version 2.1, the GNU Affero General
+ Public License, Version 3.0, or any later versions of those
+ licenses.
+
+1.13. "Source Code Form"
+ means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, "You" includes any entity that
+ controls, is controlled by, or is under common control with You. For
+ purposes of this definition, "control" means (a) the power, direct
+ or indirect, to cause the direction or management of such entity,
+ whether by contract or otherwise, or (b) ownership of more than
+ fifty percent (50%) of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+ for sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+ or
+
+(b) for infringements caused by: (i) Your and any other third party's
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+ Form, as described in Section 3.1, and You must inform recipients of
+ the Executable Form how they can obtain a copy of such Source Code
+ Form by reasonable means in a timely manner, at a charge no more
+ than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter
+ the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+* *
+* 6. Disclaimer of Warranty *
+* ------------------------- *
+* *
+* Covered Software is provided under this License on an "as is" *
+* basis, without warranty of any kind, either expressed, implied, or *
+* statutory, including, without limitation, warranties that the *
+* Covered Software is free of defects, merchantable, fit for a *
+* particular purpose or non-infringing. The entire risk as to the *
+* quality and performance of the Covered Software is with You. *
+* Should any Covered Software prove defective in any respect, You *
+* (not any Contributor) assume the cost of any necessary servicing, *
+* repair, or correction. This disclaimer of warranty constitutes an *
+* essential part of this License. No use of any Covered Software is *
+* authorized under this License except under this disclaimer. *
+* *
+************************************************************************
+
+************************************************************************
+* *
+* 7. Limitation of Liability *
+* -------------------------- *
+* *
+* Under no circumstances and under no legal theory, whether tort *
+* (including negligence), contract, or otherwise, shall any *
+* Contributor, or anyone who distributes Covered Software as *
+* permitted above, be liable to You for any direct, indirect, *
+* special, incidental, or consequential damages of any character *
+* including, without limitation, damages for lost profits, loss of *
+* goodwill, work stoppage, computer failure or malfunction, or any *
+* and all other commercial damages or losses, even if such party *
+* shall have been informed of the possibility of such damages. This *
+* limitation of liability shall not apply to liability for death or *
+* personal injury resulting from such party's negligence to the *
+* extent applicable law prohibits such limitation. Some *
+* jurisdictions do not allow the exclusion or limitation of *
+* incidental or consequential damages, so this exclusion and *
+* limitation may not apply to You. *
+* *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+ This Source Code Form is subject to the terms of the Mozilla Public
+ License, v. 2.0. If a copy of the MPL was not distributed with this
+ file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+ This Source Code Form is "Incompatible With Secondary Licenses", as
+ defined by the Mozilla Public License, v. 2.0.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..f6dea7f
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+# Fineract SDK
\ No newline at end of file
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 0000000..eeba5a8
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,94 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: "kotlinx-serialization"
+apply plugin: "de.jensklingenberg.ktorfit"
+apply plugin: "org.jetbrains.kotlin.plugin.serialization"
+
+android {
+ namespace 'org.mifos'
+ compileSdk rootProject.ext.compileSdkVersion
+ buildToolsVersion rootProject.ext.buildToolsVersion
+
+ defaultConfig {
+ minSdkVersion rootProject.ext.minSdkVersion
+ targetSdkVersion rootProject.ext.targetSdkVersion
+ versionCode 1
+ versionName "1.0.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ lintOptions {
+ abortOnError false
+ }
+
+ packagingOptions {
+ exclude 'META-INF/DEPENDENCIES'
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_17
+ targetCompatibility JavaVersion.VERSION_17
+ }
+ kotlinOptions {
+ jvmTarget = '17'
+ }
+
+}
+
+dependencies {
+// implementation "androidx.multidex:multidex:$rootProject.multidexVersion"
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+ implementation "androidx.appcompat:appcompat:$rootProject.appCompatVersion"
+ testImplementation "junit:junit:$rootProject.jUnitVersion"
+ androidTestImplementation "androidx.test.ext:junit:$rootProject.androidJUnitVersion"
+ androidTestImplementation "androidx.test.espresso:espresso-core:$rootProject.androidEsspressoVersion"
+
+ // RecyclerView and CardView dependencies
+ implementation "androidx.cardview:cardview:$rootProject.cardviewVersion"
+
+ // rx Java dependencies
+ implementation "io.reactivex:rxandroid:$rootProject.rxAndroidVersion"
+ implementation "io.reactivex:rxjava:$rootProject.rxJavaVersion"
+
+ // Lifecycle dependency
+ implementation "androidx.lifecycle:lifecycle-extensions:$rootProject.lifecycleVersion"
+
+ //Square dependencies
+ implementation("com.squareup.retrofit2:retrofit:$retrofitVersionLatest") {
+ // exclude Retrofit’s OkHttp peer-dependency module and define your own module import
+ exclude module: 'okhttp'
+ }
+ implementation "com.squareup.retrofit2:converter-gson:$retrofitVersionLatest"
+ implementation "com.squareup.retrofit2:converter-scalars:$retrofitVersionLatest"
+ implementation "com.squareup.retrofit2:adapter-rxjava:$retrofitVersionLatest"
+ implementation "com.squareup.okhttp3:okhttp:$okHttp3Version"
+ implementation "com.squareup.okhttp3:logging-interceptor:$okHttp3Version"
+
+ implementation project(':core')
+
+ // fineract dependency
+ implementation ("com.github.openMF:fineract-client-cmp:0.0.1")
+
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0'
+ implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.8.5"
+
+ // Add Ktorfit
+ implementation "de.jensklingenberg.ktorfit:ktorfit-lib:2.1.0"
+
+ // Add Ktor dependencies
+ implementation "io.ktor:ktor-client-core:2.3.12"
+ implementation "io.ktor:ktor-client-cio:2.3.12"
+ implementation "io.ktor:ktor-client-logging:2.3.12"
+ implementation "io.ktor:ktor-client-auth:2.3.12"
+ implementation "io.ktor:ktor-network-tls-certificates:2.3.12"
+ implementation "io.ktor:ktor-client-content-negotiation:2.3.12"
+ implementation "io.ktor:ktor-serialization-kotlinx-json:2.3.12"
+ implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1")
+}
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/app/src/androidTest/java/org/mifos/ExampleInstrumentedTest.kt b/app/src/androidTest/java/org/mifos/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..bd1a405
--- /dev/null
+++ b/app/src/androidTest/java/org/mifos/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package org.mifos
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("org.mifos", appContext.packageName)
+ }
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..5688530
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/org/mifos/ui/HomeActivity.kt b/app/src/main/java/org/mifos/ui/HomeActivity.kt
new file mode 100644
index 0000000..5d9f98a
--- /dev/null
+++ b/app/src/main/java/org/mifos/ui/HomeActivity.kt
@@ -0,0 +1,51 @@
+package org.mifos.ui
+
+import android.os.Build
+import android.os.Bundle
+import android.widget.TextView
+import androidx.annotation.RequiresApi
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.lifecycleScope
+import kotlinx.coroutines.launch
+import org.mifos.R
+import org.mifos.core.apimanager.BaseApiManager
+import org.mifos.core.apimanager.BaseUrl.Companion.API_ENDPOINT
+import org.mifos.core.apimanager.BaseUrl.Companion.API_PATH
+import org.mifos.core.apimanager.BaseUrl.Companion.PROTOCOL_HTTPS
+import org.mifos.utils.toast
+import org.openapitools.client.models.PostAuthenticationRequest
+
+class HomeActivity : AppCompatActivity() {
+
+ private val baseUrl = PROTOCOL_HTTPS + API_ENDPOINT + API_PATH
+ private val tenant = "default"
+ private lateinit var baseApiManager: BaseApiManager
+
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_home)
+
+ baseApiManager = BaseApiManager.getInstance()
+ baseApiManager.createService("mifos", "password", baseUrl, tenant, false)
+
+ val req = PostAuthenticationRequest(username = "mifos", password = "password")
+
+ lifecycleScope.launch {
+ val response = baseApiManager.getAuthApi().authenticate(req, true)
+ setText(response.toString())
+ getClient()
+ }
+ }
+
+ private fun getClient() {
+ lifecycleScope.launch {
+ val response = baseApiManager.getClientsApi().retrieveOne11(1, false)
+ this@HomeActivity.toast(response.toString())
+ }
+ }
+
+ private fun setText(text: String) {
+ findViewById(R.id.text).text = text
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/mifos/utils/ViewUtils.kt b/app/src/main/java/org/mifos/utils/ViewUtils.kt
new file mode 100644
index 0000000..fdfb2a0
--- /dev/null
+++ b/app/src/main/java/org/mifos/utils/ViewUtils.kt
@@ -0,0 +1,20 @@
+package org.mifos.utils
+
+import android.content.Context
+import android.view.View
+import android.widget.Toast
+
+/**
+ * Created by grandolf49 on 17-06-2020
+ */
+fun Context.toast(message: String) {
+ Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
+}
+
+fun View.show() {
+ visibility = View.VISIBLE
+}
+
+fun View.hide() {
+ visibility = View.GONE
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_home.xml b/app/src/main/res/layout/activity_home.xml
new file mode 100644
index 0000000..6ce849b
--- /dev/null
+++ b/app/src/main/res/layout/activity_home.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/layout_api_item.xml b/app/src/main/res/layout/layout_api_item.xml
new file mode 100644
index 0000000..d51310d
--- /dev/null
+++ b/app/src/main/res/layout/layout_api_item.xml
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..a571e60
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..61da551
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c41dd28
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..db5080a
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..6dba46d
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..da31a87
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..15ac681
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..b216f2d
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..f25a419
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..e96783c
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..0e5838e
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,7 @@
+
+
+ #6200EE
+ #3700B3
+ #03DAC5
+ #000000
+
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..72348af
--- /dev/null
+++ b/app/src/main/res/values/dimens.xml
@@ -0,0 +1,12 @@
+
+
+ 8dp
+ 24sp
+ 8dp
+ 20sp
+ 8dp
+ 8dp
+ 8dp
+ 16dp
+ 16sp
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..744eef2
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,8 @@
+
+ Mifos Android Architecture
+ API Name
+ API Description
+ Test API
+ Loading API Response…
+ Copy Response
+
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..5885930
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/app/src/test/java/org/mifos/ExampleUnitTest.kt b/app/src/test/java/org/mifos/ExampleUnitTest.kt
new file mode 100644
index 0000000..c5c010d
--- /dev/null
+++ b/app/src/test/java/org/mifos/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package org.mifos
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..f3b1c3b
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,89 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ ext.kotlin_version = '1.9.22'
+ repositories {
+ google()
+ mavenCentral()
+ maven {
+ url = uri("https://plugins.gradle.org/m2/")
+ }
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:8.1.0'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath "de.jensklingenberg.ktorfit:ktorfit-gradle-plugin:2.1.0"
+ classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+ext {
+ // Sdk and tools
+ minSdkVersion = 26
+ targetSdkVersion = 34
+ compileSdkVersion = 34
+ buildToolsVersion = '28.0.3'
+
+ // multidex version
+ multidexVersion = '2.0.1'
+
+ // cardView dependency
+ cardviewVersion = '1.0.0'
+
+ //
+ lifecycleVersion = '2.2.0'
+
+ // appcompat version
+ appCompatVersion = '1.6.1'
+
+ // jUnit version
+ jUnitVersion = '4.13.2'
+
+ // androidJunit
+ androidJUnitVersion = '1.1.5'
+
+ // android espresso
+ androidEsspressoVersion = '3.5.1'
+
+ // App dependencies
+ supportLibraryVersion = '27.1.1'
+
+ // espresso version
+ espressoVersion = '2.2.2'
+
+ // retrofit version
+ retrofitVersionLatest = '2.9.0'
+
+ // okHttp3 version
+ okHttp3Version = '4.11.0'
+
+ // preference version
+ preference = '1.2.1'
+
+ // rxJava version
+ rxJavaVersion = '1.3.8'
+
+ // rxJavaAndroid version
+ rxAndroidVersion = '1.2.1'
+
+ // fineract version
+ fineractClientVersion = '2.0.3'
+
+ // truth version
+ truthVersion = '1.1.3'
+}
+
+allprojects {
+ repositories {
+ google()
+ mavenCentral()
+ maven { url 'https://jitpack.io' }
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/core/.gitignore b/core/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/core/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/core/build.gradle b/core/build.gradle
new file mode 100644
index 0000000..50ac705
--- /dev/null
+++ b/core/build.gradle
@@ -0,0 +1,102 @@
+apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-kapt'
+apply plugin: 'maven-publish'
+apply plugin: "kotlinx-serialization"
+apply plugin: "de.jensklingenberg.ktorfit"
+apply plugin: "org.jetbrains.kotlin.plugin.serialization"
+
+android {
+ namespace 'org.mifos.core'
+ compileSdk 33
+ buildToolsVersion "29.0.3"
+
+ defaultConfig {
+ minSdkVersion 26
+ targetSdkVersion 33
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles 'consumer-rules.pro'
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ packagingOptions {
+ exclude 'META-INF/core_release.kotlin_module'
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_17
+ targetCompatibility JavaVersion.VERSION_17
+ }
+ kotlinOptions {
+ jvmTarget = '17'
+ }
+}
+
+dependencies {
+ implementation "androidx.appcompat:appcompat:$rootProject.appCompatVersion"
+ testImplementation "junit:junit:$rootProject.jUnitVersion"
+ androidTestImplementation "androidx.test.ext:junit:$rootProject.androidJUnitVersion"
+ androidTestImplementation "androidx.test.espresso:espresso-core:$rootProject.androidEsspressoVersion"
+
+
+ //testing dependency
+ androidTestImplementation "com.google.truth:truth:$rootProject.truthVersion"
+
+ // Kotlin standard library dependency
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+
+ // rxJava dependency
+ implementation "io.reactivex:rxjava:$rxJavaVersion"
+
+ //Square dependencies
+ implementation("com.squareup.retrofit2:retrofit:$retrofitVersionLatest") {
+ // exclude Retrofit’s OkHttp peer-dependency module and define your own module import
+ exclude module: 'okhttp'
+ }
+ implementation "com.squareup.retrofit2:converter-gson:$retrofitVersionLatest"
+ implementation "com.squareup.retrofit2:converter-scalars:$retrofitVersionLatest"
+ implementation "com.squareup.retrofit2:adapter-rxjava:$retrofitVersionLatest"
+ implementation "com.squareup.okhttp3:okhttp:$okHttp3Version"
+ implementation "com.squareup.okhttp3:logging-interceptor:$okHttp3Version"
+
+ //Shared Preferences dependency
+ implementation "androidx.preference:preference-ktx:$preference"
+
+ // fineractClient dependency
+ implementation ("com.github.openMF:fineract-client-cmp:0.0.1")
+
+ // Add Ktorfit
+ implementation "de.jensklingenberg.ktorfit:ktorfit-lib:2.1.0"
+
+ // Add Ktor dependencies
+ implementation "io.ktor:ktor-client-core:2.3.12"
+ implementation "io.ktor:ktor-client-cio:2.3.12"
+ implementation "io.ktor:ktor-client-logging:2.3.12"
+ implementation "io.ktor:ktor-client-auth:2.3.12"
+ implementation "io.ktor:ktor-network-tls-certificates:2.3.12"
+ implementation "io.ktor:ktor-client-content-negotiation:2.3.12"
+ implementation "io.ktor:ktor-serialization-kotlinx-json:2.3.12"
+ implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1")
+}
+
+publishing {
+ publications {
+ release(MavenPublication) {
+ groupId = 'com.github.openMF'
+ artifactId = 'mifos-android-sdk-arch'
+ version = '1.0.6'
+
+ afterEvaluate {
+ from components.release
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/consumer-rules.pro b/core/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/core/proguard-rules.pro b/core/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/core/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/core/src/androidTest/java/org/mifos/core/ExampleInstrumentedTest.kt b/core/src/androidTest/java/org/mifos/core/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..6ee0b80
--- /dev/null
+++ b/core/src/androidTest/java/org/mifos/core/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package org.mifos.core
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("org.mifos.core.test", appContext.packageName)
+ }
+}
diff --git a/core/src/main/AndroidManifest.xml b/core/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..944d58c
--- /dev/null
+++ b/core/src/main/AndroidManifest.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/src/main/java/org/mifos/core/apimanager/BaseApiManager.kt b/core/src/main/java/org/mifos/core/apimanager/BaseApiManager.kt
new file mode 100644
index 0000000..88c66d3
--- /dev/null
+++ b/core/src/main/java/org/mifos/core/apimanager/BaseApiManager.kt
@@ -0,0 +1,75 @@
+package org.mifos.core.apimanager
+
+import org.openapitools.client.apis.AuditsApi
+import org.openapitools.client.apis.AuthenticationHTTPBasicApi
+import org.openapitools.client.apis.CentersApi
+import org.openapitools.client.apis.ChargesApi
+import org.openapitools.client.apis.ClientApi
+import org.openapitools.client.apis.DataTablesApi
+import org.openapitools.client.apis.DocumentsApi
+import org.openapitools.client.apis.GroupsApi
+import org.openapitools.client.apis.LoanReschedulingApi
+import org.openapitools.client.apis.LoansApi
+import org.openapitools.client.apis.NotesApi
+import org.openapitools.client.apis.OfficesApi
+import org.openapitools.client.apis.RunReportsApi
+import org.openapitools.client.apis.SavingsAccountApi
+import org.openapitools.client.apis.SearchAPIApi
+import org.openapitools.client.apis.SpmSurveysApi
+import org.openapitools.client.apis.StaffApi
+import org.openapitools.client.infrastructure.FineractClient
+
+interface BaseApiManager {
+
+ companion object {
+ fun getInstance(): BaseApiManager {
+ return BaseApiManagerImpl()
+ }
+ }
+
+ fun createService(
+ username: String,
+ password: String,
+ baseUrl: String,
+ tenant: String = "default",
+ secured: Boolean = true
+ )
+
+ fun getClient(): FineractClient
+
+ fun getAuthApi(): AuthenticationHTTPBasicApi
+
+ fun getCenterApi(): CentersApi
+
+ fun getClientsApi(): ClientApi
+
+ fun getDataTableApi(): DataTablesApi
+
+ fun getLoanApi(): LoansApi
+
+ fun getSavingsApi(): SavingsAccountApi
+
+ fun getSearchApi(): SearchAPIApi
+
+ fun getGroupApi(): GroupsApi
+
+ fun getDocumentApi(): DocumentsApi
+
+ fun getOfficeApi(): OfficesApi
+
+ fun getStaffApi(): StaffApi
+
+ fun getSurveyApi(): SpmSurveysApi
+
+ fun getChargeApi(): ChargesApi
+
+ fun getRunReportsService(): RunReportsApi
+
+ fun getNoteApi(): NotesApi
+
+ fun getCollectionSheetApi(): CentersApi
+
+ fun getCheckerInboxApi(): AuditsApi
+
+ fun getRescheduleLoansApi(): LoanReschedulingApi
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/mifos/core/apimanager/BaseApiManagerImpl.kt b/core/src/main/java/org/mifos/core/apimanager/BaseApiManagerImpl.kt
new file mode 100644
index 0000000..826734b
--- /dev/null
+++ b/core/src/main/java/org/mifos/core/apimanager/BaseApiManagerImpl.kt
@@ -0,0 +1,86 @@
+package org.mifos.core.apimanager
+
+import org.openapitools.client.apis.AuditsApi
+import org.openapitools.client.apis.AuthenticationHTTPBasicApi
+import org.openapitools.client.apis.CentersApi
+import org.openapitools.client.apis.ChargesApi
+import org.openapitools.client.apis.ClientApi
+import org.openapitools.client.apis.DataTablesApi
+import org.openapitools.client.apis.DocumentsApi
+import org.openapitools.client.apis.GroupsApi
+import org.openapitools.client.apis.LoanReschedulingApi
+import org.openapitools.client.apis.LoansApi
+import org.openapitools.client.apis.NotesApi
+import org.openapitools.client.apis.OfficesApi
+import org.openapitools.client.apis.RunReportsApi
+import org.openapitools.client.apis.SavingsAccountApi
+import org.openapitools.client.apis.SearchAPIApi
+import org.openapitools.client.apis.SpmSurveysApi
+import org.openapitools.client.apis.StaffApi
+import org.openapitools.client.infrastructure.FineractClient
+
+/**
+ * Created by Aditya Gupta on 19-09-2024
+ *
+ * A class to provide the ktorfit service to the SDK
+ */
+class BaseApiManagerImpl : BaseApiManager {
+
+ private lateinit var client: FineractClient
+
+ override fun createService(
+ username: String,
+ password: String,
+ baseUrl: String,
+ tenant: String,
+ secured: Boolean
+ ) {
+ val builder = FineractClient.builder()
+ .baseURL(baseUrl)
+ .basicAuth(username, password)
+ .inSecure(!secured)
+ .tenant(tenant)
+
+ client = builder.build()
+ }
+
+ override fun getClient(): FineractClient {
+ return client
+ }
+
+ override fun getAuthApi(): AuthenticationHTTPBasicApi = client.authentication
+
+ override fun getCenterApi(): CentersApi = client.centers
+
+ override fun getClientsApi(): ClientApi = client.clients
+
+ override fun getDataTableApi(): DataTablesApi = client.dataTables
+
+ override fun getLoanApi(): LoansApi = client.loans
+
+ override fun getSavingsApi(): SavingsAccountApi = client.savingsAccounts
+
+ override fun getSearchApi(): SearchAPIApi = client.search
+
+ override fun getGroupApi(): GroupsApi = client.groups
+
+ override fun getDocumentApi(): DocumentsApi = client.documents
+
+ override fun getOfficeApi(): OfficesApi = client.offices
+
+ override fun getStaffApi(): StaffApi = client.staff
+
+ override fun getSurveyApi(): SpmSurveysApi = client.spmSurveys
+
+ override fun getChargeApi(): ChargesApi = client.charges
+
+ override fun getRunReportsService(): RunReportsApi = client.reportsRun
+
+ override fun getNoteApi(): NotesApi = client.notes
+
+ override fun getCollectionSheetApi(): CentersApi = client.centers
+
+ override fun getCheckerInboxApi(): AuditsApi = client.audits
+
+ override fun getRescheduleLoansApi(): LoanReschedulingApi = client.loanSchedules
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/mifos/core/apimanager/BaseUrl.kt b/core/src/main/java/org/mifos/core/apimanager/BaseUrl.kt
new file mode 100644
index 0000000..f4e93fb
--- /dev/null
+++ b/core/src/main/java/org/mifos/core/apimanager/BaseUrl.kt
@@ -0,0 +1,15 @@
+package org.mifos.core.apimanager
+
+/**
+ * Created by grandolf49 on 15-06-2020
+ *
+ * A class to store default values of the Base URLs
+ */
+class BaseUrl {
+ companion object {
+ const val PROTOCOL_HTTPS = "https://"
+ const val API_ENDPOINT = "dev.mifos.io"
+ const val API_PATH = "/fineract-provider/api/"
+ const val PORT = "80"
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/mifos/core/apimanager/MifosOkHttpClient.kt b/core/src/main/java/org/mifos/core/apimanager/MifosOkHttpClient.kt
new file mode 100644
index 0000000..33abefa
--- /dev/null
+++ b/core/src/main/java/org/mifos/core/apimanager/MifosOkHttpClient.kt
@@ -0,0 +1,58 @@
+package org.mifos.core.apimanager
+
+import android.annotation.SuppressLint
+import okhttp3.OkHttpClient
+import okhttp3.logging.HttpLoggingInterceptor
+import java.security.SecureRandom
+import java.security.cert.CertificateException
+import java.security.cert.X509Certificate
+import java.util.concurrent.TimeUnit
+import javax.net.ssl.*
+
+
+/**
+ * Created by grandolf49 on 18-06-2020
+ *
+ * OkHttpClient to disable SSL certificate validation in Retrofit
+ */
+object MifosOkHttpClient {
+
+ val mifosOkHttpClient: OkHttpClient
+ get() = try {
+ val trustAllCerts = arrayOf(object : X509TrustManager {
+ @SuppressLint("TrustAllX509TrustManager")
+ @Throws(CertificateException::class)
+ override fun checkClientTrusted(chain: Array, authType: String) {
+ }
+
+ @SuppressLint("TrustAllX509TrustManager")
+ @Throws(CertificateException::class)
+ override fun checkServerTrusted(chain: Array, authType: String) {
+ }
+
+ override fun getAcceptedIssuers(): Array {
+ return arrayOf()
+ }
+ })
+ val sslContext = SSLContext.getInstance("SSL")
+ sslContext.init(null, trustAllCerts, SecureRandom())
+ val builder = OkHttpClient.Builder()
+
+ builder.sslSocketFactory(sslContext.socketFactory,trustAllCerts[0] as X509TrustManager)
+ builder.hostnameVerifier(HostnameVerifier { _, _ -> true })
+
+ //Enable Full Body Logging
+ val logger = HttpLoggingInterceptor()
+ logger.setLevel(HttpLoggingInterceptor.Level.BODY)
+
+ //Setting Timeout 30 Seconds
+ builder.connectTimeout(60, TimeUnit.SECONDS)
+ builder.readTimeout(60, TimeUnit.SECONDS)
+
+ //Interceptor :> Full Body Logger and ApiRequest Header
+ builder.addInterceptor(logger)
+ builder.build()
+ } catch (e: Exception) {
+ throw RuntimeException(e)
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/mifos/core/data/AbstractMapper.kt b/core/src/main/java/org/mifos/core/data/AbstractMapper.kt
new file mode 100644
index 0000000..cf84b96
--- /dev/null
+++ b/core/src/main/java/org/mifos/core/data/AbstractMapper.kt
@@ -0,0 +1,12 @@
+package org.mifos.core.data
+
+abstract class AbstractMapper: EntityMapper {
+
+ override fun mapFromEntityList(entities: List): List {
+ return entities.map { mapFromEntity(it) }
+ }
+
+ override fun mapToEntityList(domainModels: List): List {
+ return domainModels.map { mapToEntity(it) }
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/mifos/core/data/EntityMapper.kt b/core/src/main/java/org/mifos/core/data/EntityMapper.kt
new file mode 100644
index 0000000..f479b64
--- /dev/null
+++ b/core/src/main/java/org/mifos/core/data/EntityMapper.kt
@@ -0,0 +1,16 @@
+package org.mifos.core.data
+
+/**
+ * The generic interface for mapping data from api to specific domain,
+ * create concrete class for specific models implementing this mapper
+ * and use it while making the api request
+ * @author Danish Jamal - http://github.com/danishjamal104/
+ * @param Entity the generic class which belongs outside of this app
+ * @param DomainModel the generic class which holds data for this specific app/domain
+ */
+interface EntityMapper {
+ fun mapFromEntity(entity: Entity): DomainModel
+ fun mapToEntity(domainModel: DomainModel): Entity
+ fun mapFromEntityList(entities: List): List
+ fun mapToEntityList(domainModels: List): List
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/mifos/core/sharedpreference/BasePreferenceManager.kt b/core/src/main/java/org/mifos/core/sharedpreference/BasePreferenceManager.kt
new file mode 100644
index 0000000..f7e8da5
--- /dev/null
+++ b/core/src/main/java/org/mifos/core/sharedpreference/BasePreferenceManager.kt
@@ -0,0 +1,106 @@
+package org.mifos.core.sharedpreference
+
+import android.content.SharedPreferences
+import com.google.gson.Gson
+
+/**
+ * The base class for managing all the shared preference related task
+ * @author Danish Jamal - http://github.com/danishjamal104/
+ */
+abstract class BasePreferenceManager {
+
+ abstract val preference: SharedPreferences
+ private val editor: SharedPreferences.Editor get() = preference.edit()
+ val gson = Gson()
+
+ fun clear() = editor.clear().apply()
+
+ /**
+ * The generic method for putting data into shared preference
+ * @param T The generic type of data
+ * @param key The key of the data to be put in, of type [Key]
+ * @param value The actual value of data of type [T]
+ */
+ fun put(key: Key, value: T?) {
+ when (value) {
+ is String -> editor.putString(key.value, value).apply()
+ is Boolean -> editor.putBoolean(key.value, value).apply()
+ is Int -> editor.putInt(key.value, value).apply()
+ is Long -> editor.putLong(key.value, value).apply()
+ is Float -> editor.putFloat(key.value, value).apply()
+ is MutableSet<*> -> editor.putStringSet(key.value, value as MutableSet).apply()
+ else -> editor.putString(key.value, value.objectToJson()).apply()
+ }
+ }
+
+ /**
+ * The generic method for getting data from shared preference
+ * @param T The type of data to be fetched
+ * @param key The key of the data to be fetched, of type [Key]
+ * @return the value fetched from preference of type [T]
+ */
+ inline fun get(key: Key, default: T? = null): T {
+ return when (T::class) {
+ String::class -> {
+ preference.getString(key.value, default?.let { it as String } ?: "") as T
+ }
+ Boolean::class -> {
+ preference.getBoolean(key.value, default?.let { it as Boolean } ?: false) as T
+ }
+ Int::class -> {
+ preference.getInt(key.value, default?.let { it as Int } ?: -1) as T
+ }
+ Long::class -> {
+ preference.getLong(key.value, default?.let { it as Long } ?: -1L) as T
+ }
+ Float::class -> {
+ preference.getFloat(key.value, default?.let { it as Float } ?: -1F) as T
+ }
+ MutableSet::class -> {
+ preference.getStringSet(
+ key.value,
+ default?.let { it as MutableSet } ?: mutableSetOf()) as T
+ }
+ else -> {
+ preference.getString(key.value, default?.let { it as String } ?: "{}")
+ ?.jsonToObject() ?: gson.fromJson("{}", T::class.java)
+ }
+ }
+ }
+
+ /**
+ * Extension function for converting any data of type [T] to string using [gson]
+ * @param T The generic type of data which is to per converted
+ * @return The JSON string of [T]
+ */
+ private fun T.objectToJson() = gson.toJson(this)
+
+ /**
+ * Extension function for converting json string to object of type [T]
+ * @param T The generic type of object to which json is to be converted
+ * @return The concrete object of type [T]
+ */
+ inline fun String.jsonToObject(): T {
+ return gson.fromJson(this, T::class.java)
+ }
+}
+
+/**
+ * Contains all the supported keys, these keys are to be used for fetching and putting the data in
+ * shared preferences.
+ * @see BasePreferenceManager.get
+ * @see BasePreferenceManager.put
+ * @see openMF/android-client-PrefManager.java
+ */
+sealed class Key(val value: String) {
+ object USER_ID: Key("preferences_user_id")
+ object TOKEN: Key("preferences_token")
+ object TENANT: Key("preferences_tenant")
+ object INSTANCE_URL: Key("preferences_instance")
+ object INSTANCE_DOMAIN: Key("preferences_domain")
+ object PORT: Key("preferences_port")
+ object USER_STATUS: Key("user_status")
+ object PASSCODE: Key("passcode")
+ object PASSCODE_STATUS: Key("passcode_status")
+ data class Custom(val customKeyValue: String): Key(customKeyValue)
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/mifos/core/sharedpreference/UserPreferences.kt b/core/src/main/java/org/mifos/core/sharedpreference/UserPreferences.kt
new file mode 100644
index 0000000..a1fb760
--- /dev/null
+++ b/core/src/main/java/org/mifos/core/sharedpreference/UserPreferences.kt
@@ -0,0 +1,93 @@
+package org.mifos.core.sharedpreference
+
+import android.text.TextUtils
+import org.mifos.core.apimanager.BaseUrl
+
+/**
+ * Shared preferences abstract class for managing user related data
+ * @author Danish Jamal - http://github.com/danishjamal104/
+ * @constructor returns the [UserPreferences] instance for managing user related data
+ * @param USER the generic user class
+ */
+abstract class UserPreferences : BasePreferenceManager() {
+
+ abstract fun saveUser(user: USER)
+
+ abstract fun getUser(): USER
+
+ /**
+ * Authentication
+ */
+
+ fun saveToken(token: String?) = put(Key.TOKEN, token)
+
+ fun clearToken() = put(Key.TOKEN, "")
+
+ fun getToken() = get(Key.TOKEN)
+
+ fun isAuthenticated() = !TextUtils.isEmpty(getToken())
+
+ fun getUserId() = get(Key.USER_ID)
+
+ fun setUserId(id: Int) = put(Key.USER_ID, id)
+
+ fun getTenant() = get(Key.TENANT, "default")
+
+ fun setTenant(tenant: String?) {
+ if (!TextUtils.isEmpty(tenant)) {
+ put(Key.TENANT, tenant)
+ }
+ }
+
+ fun getInstanceUrl() = get(Key.INSTANCE_URL)
+
+ /**
+ * Connection
+ */
+ fun setInstanceUrl(instanceUrl: String?) = put(Key.INSTANCE_URL, instanceUrl)
+
+ fun getInstanceDomain() = get(Key.INSTANCE_DOMAIN, BaseUrl.API_ENDPOINT)
+
+ fun setInstanceDomain(instanceDomain: String?) = put(Key.INSTANCE_DOMAIN, instanceDomain)
+
+ fun getPort() = get(Key.PORT, BaseUrl.PORT)
+
+ fun setPort(port: String?) {
+ if (!TextUtils.isEmpty(port)) {
+ put(Key.PORT, port)
+ }
+ }
+
+ fun getPassCode() = get(Key.PASSCODE, "")
+
+ fun setPassCode(passCode: String?) {
+ put(Key.PASSCODE, passCode)
+ setPassCodeStatus(true)
+ }
+
+ /**
+ * Set User Status,
+ * If O then user is Online
+ * If 1 then User is offline
+ */
+ fun setUserStatus(statusCode: Int) = put(Key.USER_STATUS, statusCode)
+
+ /**
+ * @return the Pref value of User status.
+ * default is 0(User is online)
+ */
+ fun getUserStatus() = get(Key.USER_STATUS, 0)
+
+ /**
+ * Set Pass Code Status,
+ * If `false` then pass code is not set
+ * If `true` then pass code is set
+ */
+ fun setPassCodeStatus(statusCode: Boolean) = put(Key.PASSCODE_STATUS, statusCode)
+
+ /**
+ * @return the Pref value of pass code status.
+ * default is false(pass code is not set)
+ */
+ fun getPassCodeStatus() = get(Key.PASSCODE_STATUS, false)
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/mifos/core/utils/JsonDateSerializer.kt b/core/src/main/java/org/mifos/core/utils/JsonDateSerializer.kt
new file mode 100644
index 0000000..e0a0501
--- /dev/null
+++ b/core/src/main/java/org/mifos/core/utils/JsonDateSerializer.kt
@@ -0,0 +1,21 @@
+package org.mifos.core.utils
+
+import com.google.gson.JsonElement
+import com.google.gson.JsonPrimitive
+import com.google.gson.JsonSerializationContext
+import com.google.gson.JsonSerializer
+import java.lang.reflect.Type
+import java.text.SimpleDateFormat
+import java.util.*
+
+class JsonDateSerializer: JsonSerializer {
+ override fun serialize(
+ src: Date?,
+ typeOfSrc: Type?,
+ context: JsonSerializationContext?
+ ): JsonElement {
+ val output = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
+ val formattedTime = output.format(src)
+ return JsonPrimitive(formattedTime)
+ }
+}
\ No newline at end of file
diff --git a/core/src/test/java/org/mifos/core/ExampleUnitTest.kt b/core/src/test/java/org/mifos/core/ExampleUnitTest.kt
new file mode 100644
index 0000000..aae3c45
--- /dev/null
+++ b/core/src/test/java/org/mifos/core/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package org.mifos.core
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..3f75c3b
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,21 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx4608m -Dfile.encoding=UTF-8
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Automatically convert third-party libraries to use AndroidX
+android.enableJetifier=true
+# Kotlin code style for this project: "official" or "obsolete":
+kotlin.code.style=official
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..f6b961f
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..afc4b8f
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Sat Jun 06 09:46:10 IST 2020
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
diff --git a/gradlew b/gradlew
new file mode 100644
index 0000000..cccdd3d
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..f955316
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/jitpack.yml b/jitpack.yml
new file mode 100644
index 0000000..1e41e00
--- /dev/null
+++ b/jitpack.yml
@@ -0,0 +1,2 @@
+jdk:
+ - openjdk17
\ No newline at end of file
diff --git a/renovate.json b/renovate.json
new file mode 100644
index 0000000..f45d8f1
--- /dev/null
+++ b/renovate.json
@@ -0,0 +1,5 @@
+{
+ "extends": [
+ "config:base"
+ ]
+}
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..1f2dbde
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,3 @@
+rootProject.name='Fineract-sdk-cmp'
+include ':app'
+include ':core'