Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ import com.mifos.core.data.repository.SavingsAccountSummaryRepository
import com.mifos.core.data.repository.SavingsAccountTransactionReceiptRepository
import com.mifos.core.data.repository.SavingsAccountTransactionRepository
import com.mifos.core.data.repository.SearchRepository
import com.mifos.core.data.repository.ShareAccountRepository
import com.mifos.core.data.repository.SignatureRepository
import com.mifos.core.data.repository.SurveyListRepository
import com.mifos.core.data.repository.SurveySubmitRepository
Expand Down Expand Up @@ -123,6 +124,7 @@ import com.mifos.core.data.repositoryImp.SavingsAccountSummaryRepositoryImp
import com.mifos.core.data.repositoryImp.SavingsAccountTransactionReceiptRepositoryImpl
import com.mifos.core.data.repositoryImp.SavingsAccountTransactionRepositoryImp
import com.mifos.core.data.repositoryImp.SearchRepositoryImp
import com.mifos.core.data.repositoryImp.ShareAccountRepositoryImpl
import com.mifos.core.data.repositoryImp.SignatureRepositoryImp
import com.mifos.core.data.repositoryImp.SurveyListRepositoryImp
import com.mifos.core.data.repositoryImp.SurveySubmitRepositoryImp
Expand Down Expand Up @@ -223,6 +225,7 @@ val RepositoryModule = module {
singleOf(::SignatureRepositoryImp) bind SignatureRepository::class

singleOf(::RecurringAccountRepositoryImp) bind RecurringAccountRepository::class
singleOf(::ShareAccountRepositoryImpl) bind ShareAccountRepository::class

includes(platformModule)
single<PlatformDependentDataModule> { getPlatformDataModule }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright 2025 Mifos Initiative
*
* 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 https://mozilla.org/MPL/2.0/.
*
* See https://github.com/openMF/android-client/blob/master/LICENSE.md
*/
package com.mifos.core.data.repository

import com.mifos.core.common.utils.DataState
import com.mifos.core.network.model.share.ShareTemplate
import kotlinx.coroutines.flow.Flow

interface ShareAccountRepository {

fun getShareTemplate(clientId: Int): Flow<DataState<ShareTemplate>>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright 2025 Mifos Initiative
*
* 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 https://mozilla.org/MPL/2.0/.
*
* See https://github.com/openMF/android-client/blob/master/LICENSE.md
*/
package com.mifos.core.data.repositoryImp

import com.mifos.core.common.utils.DataState
import com.mifos.core.common.utils.asDataStateFlow
import com.mifos.core.data.repository.ShareAccountRepository
import com.mifos.core.network.datamanager.DataManagerShare
import com.mifos.core.network.model.share.ShareTemplate
import kotlinx.coroutines.flow.Flow

class ShareAccountRepositoryImpl(
private val dataManagerShare: DataManagerShare,
) : ShareAccountRepository {

override fun getShareTemplate(clientId: Int): Flow<DataState<ShareTemplate>> {
return dataManagerShare.getShareTemplate(clientId).asDataStateFlow()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,5 @@ object APIEndPoint {
const val DISBURSE = "disburse"
const val NOTES = "notes"
const val MAKER_CHECKER = "makercheckers"
const val SHARE = "share"
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import com.mifos.core.network.services.RecurringAccountService
import com.mifos.core.network.services.RunReportsService
import com.mifos.core.network.services.SavingsAccountService
import com.mifos.core.network.services.SearchService
import com.mifos.core.network.services.ShareAccountService
import com.mifos.core.network.services.StaffService
import com.mifos.core.network.services.SurveyService
import com.mifos.core.network.services.createCenterService
Expand All @@ -59,6 +60,7 @@ import com.mifos.core.network.services.createRecurringAccountService
import com.mifos.core.network.services.createRunReportsService
import com.mifos.core.network.services.createSavingsAccountService
import com.mifos.core.network.services.createSearchService
import com.mifos.core.network.services.createShareAccountService
import com.mifos.core.network.services.createStaffService
import com.mifos.core.network.services.createSurveyService
import de.jensklingenberg.ktorfit.Ktorfit
Expand Down Expand Up @@ -87,6 +89,7 @@ class BaseApiManager(
val collectionSheetService: CollectionSheetService = ktorfit.createCollectionSheetService()
val noteService: NoteService = ktorfit.createNoteService()
val runReportsService: RunReportsService = ktorfit.createRunReportsService()
val shareAccountService: ShareAccountService = ktorfit.createShareAccountService()

// sdk apis
val clientIdentifiersApi: ClientIdentifierApi = ktorfit.createClientIdentifierApi()
Expand All @@ -96,7 +99,6 @@ class BaseApiManager(
val groupApi: GroupsApi = ktorfit.createGroupsApi()
val staffApi: StaffApi = ktorfit.createStaffApi()
val dataTableApi: DataTablesApi = ktorfit.createDataTablesApi()

companion object {
fun build(prefManager: UserPreferencesRepository): BaseApiManager {
val ktorfitClient = KtorfitClient.builder()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright 2025 Mifos Initiative
*
* 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 https://mozilla.org/MPL/2.0/.
*
* See https://github.com/openMF/android-client/blob/master/LICENSE.md
*/
package com.mifos.core.network.datamanager

import com.mifos.core.network.BaseApiManager
import com.mifos.core.network.model.share.ShareTemplate
import kotlinx.coroutines.flow.Flow

class DataManagerShare(
private val baseApiManager: BaseApiManager,
) {

fun getShareTemplate(clientId: Int): Flow<ShareTemplate> =
baseApiManager.shareAccountService.shareProductTemplate(clientId)
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import com.mifos.core.network.datamanager.DataManagerOffices
import com.mifos.core.network.datamanager.DataManagerRunReport
import com.mifos.core.network.datamanager.DataManagerSavings
import com.mifos.core.network.datamanager.DataManagerSearch
import com.mifos.core.network.datamanager.DataManagerShare
import com.mifos.core.network.datamanager.DataManagerStaff
import com.mifos.core.network.datamanager.DataManagerSurveys
import org.koin.dsl.module
Expand All @@ -51,4 +52,5 @@ val DataManagerModule = module {
single { DataManagerStaff(get(), get(), get()) }
single { DataManagerSurveys(get(), get(), get()) }
single { DataManagerIdentifiers(get()) }
single { DataManagerShare(get()) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright 2025 Mifos Initiative
*
* 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 https://mozilla.org/MPL/2.0/.
*
* See https://github.com/openMF/android-client/blob/master/LICENSE.md
*/
package com.mifos.core.network.model.share

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class ProductOption(
@SerialName("id")
val id: Int,

@SerialName("name")
val name: String,

@SerialName("shortName")
val shortName: String,

@SerialName("totalShares")
val totalShares: Int,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright 2025 Mifos Initiative
*
* 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 https://mozilla.org/MPL/2.0/.
*
* See https://github.com/openMF/android-client/blob/master/LICENSE.md
*/
package com.mifos.core.network.model.share

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class ShareTemplate(
@SerialName("clientId")
val clientId: Int,

@SerialName(value = "clientName")
val clientName: String,

@SerialName("productOptions")
val productOptions: List<ProductOption> = emptyList(),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2025 Mifos Initiative
*
* 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 https://mozilla.org/MPL/2.0/.
*
* See https://github.com/openMF/android-client/blob/master/LICENSE.md
*/
package com.mifos.core.network.services

import com.mifos.core.network.model.share.ShareTemplate
import com.mifos.room.basemodel.APIEndPoint
import de.jensklingenberg.ktorfit.http.GET
import de.jensklingenberg.ktorfit.http.Query
import kotlinx.coroutines.flow.Flow

interface ShareAccountService {

@GET("accounts/" + APIEndPoint.SHARE + "/template")
fun shareProductTemplate(
@Query("clientId") clientId: Int,
): Flow<ShareTemplate>
Comment on lines +20 to +23
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Expose optional productId in the share template call.
Without the productId query arg we can only retrieve the bare template (client + product list). The Fineract share template API expects us to pass the selected share product id to receive the product-specific defaults (charges, currency, etc.) that the later Terms/Charges steps rely on. Add an optional productId parameter here and plumb it through the repository/DataManager. (demo.mifos.io)

-    fun shareProductTemplate(
-        @Query("clientId") clientId: Int,
-    ): Flow<ShareTemplate>
+    fun shareProductTemplate(
+        @Query("clientId") clientId: Int,
+        @Query("productId") productId: Int? = null,
+    ): Flow<ShareTemplate>
🤖 Prompt for AI Agents
In
core/network/src/commonMain/kotlin/com/mifos/core/network/services/ShareAccountService.kt
around lines 20 to 23, the shareProductTemplate endpoint needs to accept an
optional productId query parameter so the API can return product-specific
defaults; add a nullable productId: Int? parameter annotated with
@Query("productId") to the function signature (defaulting to null) and update
all callers by plumbing this parameter through the repository and DataManager
layers (add optional productId parameters to repository/DataManager methods and
pass them to the service call) so existing behavior remains unchanged when
productId is omitted.

}
Original file line number Diff line number Diff line change
Expand Up @@ -532,5 +532,21 @@
<!-- Screen Title -->
<string name="title_new_fixed_deposit_account">New Fixed Deposit Account</string>


<!-- Create Share Account -->
<string name="share_account_details">Details</string>
<string name="share_account_terms">Terms</string>
<string name="share_account_charges">Charges</string>
<string name="share_account_preview">Preview</string>
<string name="share_account_back">Back</string>
<string name="share_account_next">Next</string>

<string name="share_account_detail_product_name">Product Name*</string>
<string name="share_account_detail_submission_date">Submission Date*</string>
<string name="share_account_detail_external_id">External Id</string>
<string name="share_account_detail_date_select">Select</string>
<string name="share_account_detail_date_cancel">Cancel</string>

<!-- Handle Error-->
<string name="field_empty">This field cannot be empty</string>

</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ fun NavGraphBuilder.clientApplyNewApplicationRoute(
onNavigateBack: () -> Unit,
onNavigateApplyLoanAccount: (Int) -> Unit,
onNavigateApplySavingsAccount: (Int) -> Unit,
onNavigateApplyShareAccount: () -> Unit,
onNavigateApplyShareAccount: (Int) -> Unit,
onNavigateApplyRecurringAccount: () -> Unit,
onNavigateApplyFixedAccount: () -> Unit,
navController: NavController,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ internal fun ClientApplyNewApplicationsScreen(
onNavigateBack: () -> Unit,
onNavigateApplyLoanAccount: (Int) -> Unit,
onNavigateApplySavingsAccount: (Int) -> Unit,
onNavigateApplyShareAccount: () -> Unit,
onNavigateApplyShareAccount: (Int) -> Unit,
onNavigateApplyRecurringAccount: () -> Unit,
onNavigateApplyFixedAccount: () -> Unit,
navController: NavController,
Expand All @@ -84,7 +84,7 @@ internal fun ClientApplyNewApplicationsScreen(
state.clientId,
)

ClientApplyNewApplicationsItem.NewShareAccount -> onNavigateApplyShareAccount()
ClientApplyNewApplicationsItem.NewShareAccount -> onNavigateApplyShareAccount(state.clientId)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,24 @@ import androidx.navigation.compose.composable
import kotlinx.serialization.Serializable

@Serializable
data object ShareAccountRoute
data class CreateShareAccountRoute(
val clientId: Int,
)

fun NavGraphBuilder.shareAccountDestination() {
composable<ShareAccountRoute> {
ShareAccountScreen(
onNavigateBack = {},
fun NavGraphBuilder.createShareAccountDestination(navController: NavController) {
composable<CreateShareAccountRoute> {
CreateShareAccountScreen(
onNavigateBack = navController::popBackStack,
onFinish = {},
navController = navController,
)
Comment on lines +24 to 28
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Wire the finish callback to a navigation action.
Right now we pass onFinish = {} so when the flow emits ShareAccountEvent.Finish nothing happens—the user is stuck on the review screen after submitting. Hook the lambda up to navController::popBackStack (or the appropriate success destination) so the flow actually exits.

         CreateShareAccountScreen(
             onNavigateBack = navController::popBackStack,
-            onFinish = {},
+            onFinish = { navController.popBackStack() },
             navController = navController,
         )
🤖 Prompt for AI Agents
In
feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/CreateShareAccountRoute.kt
around lines 24 to 28, the onFinish callback is an empty lambda so
ShareAccountEvent.Finish doesn't navigate away; replace onFinish = {} with a
navigation action such as navController::popBackStack (or another success
destination) so the flow exits the review screen when finished.

}
}

fun NavController.navigateToShareAccountRoute() {
fun NavController.navigateToCreateShareAccountRoute(
clientId: Int,
) {
this.navigate(
ShareAccountRoute,
CreateShareAccountRoute(clientId = clientId),
)
}
Loading