Skip to content

Conversation

@Arinyadav1
Copy link
Contributor

@Arinyadav1 Arinyadav1 commented Dec 11, 2025

Fixes - Jira-#614

Screenshot 2025-12-11 150653 Screenshot 2025-12-11 150703 Screenshot 2025-12-11 150216

Summary by CodeRabbit

  • New Features

    • Added Preview page for reviewing recurring and fixed deposit account details before submission
    • Added Rate Chart dialog action for fixed deposits
    • Added recurring deposit frequency configuration options
    • Enhanced success feedback with snackbar notifications
  • Improvements

    • Improved network connectivity error handling and messaging across account creation flows
    • Better validation for recurring deposit operations

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 11, 2025

Walkthrough

This PR updates recurring deposit account creation to return generic responses instead of typed models, adds payload fields for penalty configurations, and introduces a network-availability wrapper pattern across feature modules. A comprehensive preview page is added to the recurring deposit flow with detailed account information rendering.

Changes

Cohort / File(s) Summary
Core data layer – Repository changes
core/data/src/commonMain/kotlin/com/mifos/core/data/repository/RecurringAccountRepository.kt, core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/RecurringAccountRepositoryImp.kt
Updated createRecurringDepositAccount return type from Flow<DataState<RecurringDeposit>> to Flow<DataState<GenericResponse>> with corresponding import changes.
Core network layer
core/network/src/commonMain/kotlin/com/mifos/core/network/services/RecurringAccountService.kt, core/network/src/commonMain/kotlin/com/mifos/core/network/datamanager/DataManagerRecurringAccount.kt
Changed service return type to Flow<HttpResponse> and data manager to Flow<GenericResponse> with error handling for non-success responses and exception extraction.
Core model – Recurring deposit payload
core/model/src/commonMain/kotlin/com/mifos/core/model/objects/payloads/RecurringDepositAccountPayload.kt
Changed mandatoryRecommendedDepositAmount type from Int? to Double?; added preClosurePenalApplicable, preClosurePenalInterest, and preClosurePenalInterestOnTypeId fields.
Feature network helpers
feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/CreateShareAccountViewModel.kt, feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountViewModel.kt, feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/SavingsAccountViewModel.kt
Added isOnline(content: suspend () -> Unit) helper function to conditionally execute operations and set error state when offline; refactored inline network checks to use this wrapper.
Feature loan state management
feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountViewModel.kt
Removed networkConnection boolean parameter from NewLoanAccountState constructor; refactored data loading to use isOnline guards.
Feature client screen cleanup
feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/CreateShareAccountScreen.kt
Removed Logger import and debug logging statement for SuccessResponseStatus.
Recurring deposit – Strings and routing
feature/recurringDeposit/src/commonMain/composeResources/values/feature_recurring_deposit_string.xml, feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountRoute.kt
Added new string resources for preview, account creation, frequency, and network error; wired onNavigateBack to navController::popBackStack for actual back navigation.
Recurring deposit – Screen and dialog
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountScreen.kt
Integrated SnackbarHostState and PreviewPage into the UI flow; added snackbar display on SuccessResponseStatus with optional post-success navigation delay; renamed overlay loading flag from isOverlayLoading to isOverlayLoadingActive.
Recurring deposit – ViewModel overhaul
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountViewModel.kt
Introduced isOnline wrapper for network-aware operations; expanded account payload construction with template-derived fields; replaced isOnline boolean flag with isOverlayLoadingActive and launchEffectKey; added OnSubmitRecurringAccount, OnRecurringFrequencyChange, and OnRecurringFrequencyTypeIndexChange actions; added SuccessResponseStatus dialog state; enhanced validation for recurring frequency and deposit amount fields; updated state mutations for frequency-related settings.
Recurring deposit – New preview page
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/PreviewPage.kt
New composable module containing PreviewPage, InterestCard, SettingCard, TermsCard, and DetailsCard components that render a comprehensive account preview with scrollable detail sections and navigation.
Recurring deposit – Settings page
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/SettingsPage.kt
Added UI block for recurring deposit frequency configuration when "deposit frequency same as meeting" is disabled; added conditional frequency type dropdown; improved error message formatting with multi-line resource calls.
Recurring deposit – Interest page
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/InterestPage.kt
Replaced internet-connection string reference with rate-chart string; added template-derived name, end date, and description fields to data map.
Loan string resources
feature/loan/src/commonMain/composeResources/values/strings.xml
Added feature_error_network_not_available string resource.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

  • RecurringAccountViewModel: Significant refactoring with new actions, state field additions/removals, expanded payload construction, and frequency validation logic; requires careful review of state mutations and action handlers.
  • PreviewPage composable: New file with multiple nested card components and complex conditional rendering; verify card data population and alignment with state structure.
  • Payload type change: mandatoryRecommendedDepositAmount changed from Int? to Double? may affect serialization/deserialization; verify JSON mapping consistency.
  • Network helper pattern: Ensure isOnline helper is correctly applied across all call sites in multiple modules and that offline error states are properly triggered.
  • State constructor removal: Confirm removal of networkConnection parameter from NewLoanAccountState doesn't break downstream consumers.

Possibly related PRs

  • #2550: Directly modifies recurring-deposit ViewModel and UI surface with overlapping state and action changes.
  • #2552: Adds interest rate chart functionality to recurring deposits with related dialog and action handling.
  • #2528: Modifies recurring deposit payloads and ViewModel with overlapping structural changes.

Suggested reviewers

  • revanthkumarJ
  • biplab1

Poem

🐰 A hop through the network we go,
With helpers that check if we're online, you know,
Deposits that preview with care,
Penalties tucked in the air,
The recurring dream flows just so!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main objective of the pull request, which is to add a new preview step in the recurring deposits account creation flow.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/InterestPage.kt (1)

103-111: The naming of isRateChartEmpty is semantically inverted and should be corrected.

The field is defined as !template.accountChart?.chartSlabs.isNullOrEmpty(), which means:

  • isRateChartEmpty = true when chartSlabs contains data (is NOT empty)
  • isRateChartEmpty = false when chartSlabs is empty or null

This contradicts the field name. For clarity, rename to hasRateChart or isRateChartAvailable, or invert the logic definition. The same issue exists in the FixedDeposit feature (line 543 of CreateFixedDepositAccountViewmodel.kt).

♻️ Duplicate comments (1)
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/PreviewPage.kt (1)

183-191: Same inverted logic issue as InterestPage.

This has the same potentially confusing logic where isRateChartEmpty = true shows the chart label and enables the button, while isRateChartEmpty = false shows "No Interest Rate Chart available". See comment on InterestPage.kt for details.

🧹 Nitpick comments (14)
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountScreen.kt (2)

117-128: Review the snackbar timing and delay logic.

The current flow has a potential UX issue:

  1. showSnackbar() suspends until the snackbar is dismissed (default Short duration is ~4 seconds)
  2. Then waits an additional 1000ms delay
  3. Then navigates back

This results in the user waiting 5+ seconds after a successful action, which may feel sluggish.

Consider either:

  • Removing the extra delay since showSnackbar already handles the display duration
  • Or specifying a shorter snackbar duration and relying solely on the delay
         is RecurringAccountState.DialogState.SuccessResponseStatus -> {
             LaunchedEffect(state.launchEffectKey) {
                 snackbarHostState.showSnackbar(
                     message = state.dialogState.msg,
+                    duration = SnackbarDuration.Short,
                 )
-
                 if (state.dialogState.successStatus) {
-                    delay(1000)
                     onAction(RecurringAccountAction.NavigateBack)
                 }
             }
         }

Also, verify that state.launchEffectKey is properly updated when a new success response is triggered, otherwise subsequent success responses may not re-trigger the effect.


86-91: Consider making RecurringAccountDialog private.

RecurringAccountDialog is public while RecurringAccountScreen is internal and RecurringAccountScaffold is private. For consistency and proper encapsulation, consider making this function private since it appears to only be used within this file.

 @Composable
-fun RecurringAccountDialog(
+private fun RecurringAccountDialog(
     state: RecurringAccountState,
     onAction: (RecurringAccountAction) -> Unit,
     snackbarHostState: SnackbarHostState,
 ) {
feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountViewModel.kt (1)

62-67: Sequential loading in init may delay UI readiness.

loadAllLoans() and loadCollaterals() are called sequentially. Since they appear to be independent operations, consider launching them concurrently for faster initialization:

     init {
         viewModelScope.launch {
-            loadAllLoans()
-            loadCollaterals()
+            launch { loadAllLoans() }
+            launch { loadCollaterals() }
         }
     }
feature/recurringDeposit/src/commonMain/composeResources/values/feature_recurring_deposit_string.xml (1)

77-79: LGTM with minor naming inconsistency.

The new strings support the preview flow well. However, feature_error_network_not_available uses a generic feature_error_ prefix instead of the file's convention of feature_recurring_deposit_. Consider renaming to feature_recurring_deposit_error_network_not_available for consistency, or alternatively, move this generic error string to a shared/common resources file if it's intended to be reused across features.

feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/PreviewPage.kt (1)

85-88: Use design token for consistent spacing.

Line 87 uses a hardcoded 20.dp value while the rest of the file uses DesignToken.padding.* values for consistency.

         Column(
             modifier = modifier.weight(1f).verticalScroll(rememberScrollState()),
-            verticalArrangement = Arrangement.spacedBy(20.dp),
+            verticalArrangement = Arrangement.spacedBy(DesignToken.padding.large),
         ) {
core/network/src/commonMain/kotlin/com/mifos/core/network/datamanager/DataManagerRecurringAccount.kt (1)

12-42: Error handling and GenericResponse decoding look solid; consider centralizing JSON parsing if reused

The new flow—inspecting response.status, extracting an error message, and decoding the body into GenericResponse with ignoreUnknownKeys—looks correct and matches the service’s new Flow<HttpResponse> signature. If you end up repeating this pattern for other endpoints, consider extracting a shared helper or reusing a common Json instance to keep error handling and serialization config consistent.

feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/SavingsAccountViewModel.kt (2)

48-52: Centralized isOnline helper + call sites look correct, but consider tightening visibility and reuse

The new isOnline suspend helper and its usage in submitSavingsApplication, loadClientTemplate, loadSavingsProductTemplate, and handleRetry are consistent and correctly scoped inside coroutines; offline handling via ScreenState.Error is clear and avoids starting the flows when offline. Two small refinements you might consider:

  • Mark isOnline as private to keep the ViewModel’s public API lean, since it’s only used internally here.
  • This same pattern now exists in multiple ViewModels; longer‑term, you could extract a small shared helper (e.g., in BaseViewModel or a utility with an injected error message) to avoid duplication, while still allowing feature‑specific strings.

Also applies to: 58-70, 180-181, 569-575, 577-583, 586-588


161-161: Make the lockinPeriodFrequencyType expression a bit clearer

The takeIf { state.frequency.toIntOrNull() != null } guard is logically correct (you only send a type when the frequency parses), but the current single line is quite dense. For readability, consider restructuring:

val lockinFrequency = state.frequency.toIntOrNull()
lockinPeriodFrequency = lockinFrequency
lockinPeriodFrequencyType =
    if (lockinFrequency != null) {
        state.savingsProductTemplate
            ?.lockinPeriodFrequencyTypeOptions
            ?.getOrNull(state.freqTypeIndex)
            ?.id
    } else {
        null
    }

This keeps the same behavior but makes the dependency between the two fields explicit.

feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/CreateShareAccountViewModel.kt (1)

54-66: isOnline wrapper and wrapped share account calls are correct; consider reuse and visibility

The isOnline helper here correctly guards createShareAccount, loadShareTemplateFromProduct, and loadShareTemplate so that repository flows are only started when online, and it centralizes offline UI feedback via ScreenState.Error(feature_client_error_network_not_available). Loading/overlay flags are managed consistently within the flows, and offline paths don’t leave spinners stuck.

Given the same isOnline pattern now exists in multiple ViewModels, you might:

  • Make this helper private in this class.
  • Later, extract a shared helper (e.g., an extension or BaseViewModel utility that takes the error string as a parameter) to reduce duplication across features.

Also applies to: 87-137, 140-181, 183-219

feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/CreateFixedDepositAccountViewmodel.kt (2)

53-65: Online guard around fixed‑deposit template loads is sound; consider small cleanup

The new isOnline helper and its use in both loadFixedDepositTemplate and loadRecurringAccountTemplateWithProduct correctly prevent template fetches when offline and surface a clear network error via ScreenState.Error(feature_client_error_network_not_available). The DataState branches still set screenState/isOverlayLoading in a consistent way, so loading indicators and error states should behave as before (with the added offline guard).

As with the other ViewModels:

  • You can safely mark isOnline as private here.
  • Longer‑term, extracting a reusable helper (e.g., base/utility taking the error string as a parameter) would reduce duplication across fixed‑deposit, share, savings, loan, and RD ViewModels.

Also applies to: 279-313, 315-351


265-271: Rate chart dialog action wiring looks good; consider renaming isRateChartEmpty

Hooking OnShowRateChart up to set dialogState = DialogState.RateChartDialog is straightforward and consistent with how other dialogs are controlled in this ViewModel.

One minor naming nit: val isRateChartEmpty = !template.accountChart?.chartSlabs.isNullOrEmpty() is actually true when there are slabs (non‑empty list). Renaming this to something like hasRateChart or inverting the boolean would make the intent clearer.

feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountViewModel.kt (3)

271-274: isOnline wrapper and template loading flow are clean; consider minor overlay tweak

The new suspend fun isOnline(content: suspend () -> Unit) centralizes online/offline checks nicely, and both loadRecurringAccountTemplate and loadRecurringAccountTemplateWithProduct correctly use it to gate repository calls and set ScreenState based on DataState.

One small refinement you might consider: in the else branch of isOnline, also clear isOverlayLoadingActive (for safety, in case a previous operation left it true) so that an offline error never leaves a stale overlay spinner visible.

Also applies to: 315-347, 349-385, 387-399, 401-405


579-590: Recurring frequency & amount validation logic is sound; keep state/ID usage consistent

The switch to recurringDepositDetails.depositAmount with doubleNumberValidator, plus explicit recurringFrequency/recurringFrequencyTypeIndex fields and the recurringErrorHandle gate, makes the settings step validation clearer. Tying the recurring‑frequency errors to depositFrequencySameAsGroupCenterMeeting (and clearing/resetting them on toggle and on change) avoids spurious errors when the calendar is inherited.

Once the ID/index mismatch raised earlier is fixed for the related frequency‑type fields, this validation block and the new OnRecurringFrequencyChange / OnRecurringFrequencyTypeIndexChange actions will provide a solid UX.

Also applies to: 612-623, 638-648, 650-682, 684-704, 980-985, 1095-1097


836-849: Charge edit mapping via indexOfFirst is reasonable; consider handling the “not found” case

Using indexOfFirst { it.id == selectedEditCharge.chargeId } to derive chooseChargeIndex from chargeId is a good improvement over assuming list indices are stable.

If for any reason the charge ID is no longer present in template.chargeOptions, indexOfFirst will return -1, which will propagate to chooseChargeIndex and may later cause issues when dereferencing chargeOptions[chooseChargeIndex!!]. It might be worth treating -1/null here as “non‑editable” (e.g., disable the save button or show an error) rather than relying on downstream code to handle it implicitly.

Also applies to: 884-898

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9bbe791 and 6d2d345.

📒 Files selected for processing (18)
  • core/data/src/commonMain/kotlin/com/mifos/core/data/repository/RecurringAccountRepository.kt (2 hunks)
  • core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/RecurringAccountRepositoryImp.kt (2 hunks)
  • core/model/src/commonMain/kotlin/com/mifos/core/model/objects/payloads/RecurringDepositAccountPayload.kt (1 hunks)
  • core/network/src/commonMain/kotlin/com/mifos/core/network/datamanager/DataManagerRecurringAccount.kt (1 hunks)
  • core/network/src/commonMain/kotlin/com/mifos/core/network/services/RecurringAccountService.kt (1 hunks)
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/CreateShareAccountScreen.kt (0 hunks)
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/CreateShareAccountViewModel.kt (4 hunks)
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/CreateFixedDepositAccountViewmodel.kt (4 hunks)
  • feature/loan/src/commonMain/composeResources/values/strings.xml (1 hunks)
  • feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountViewModel.kt (10 hunks)
  • feature/recurringDeposit/src/commonMain/composeResources/values/feature_recurring_deposit_string.xml (2 hunks)
  • feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountRoute.kt (1 hunks)
  • feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountScreen.kt (10 hunks)
  • feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountViewModel.kt (17 hunks)
  • feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/InterestPage.kt (3 hunks)
  • feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/PreviewPage.kt (1 hunks)
  • feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/SettingsPage.kt (4 hunks)
  • feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/SavingsAccountViewModel.kt (6 hunks)
💤 Files with no reviewable changes (1)
  • feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/CreateShareAccountScreen.kt
🧰 Additional context used
🧬 Code graph analysis (7)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/CreateShareAccountViewModel.kt (4)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/CreateFixedDepositAccountViewmodel.kt (1)
  • isOnline (53-65)
feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountViewModel.kt (1)
  • isOnline (69-85)
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountViewModel.kt (1)
  • isOnline (387-399)
feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/SavingsAccountViewModel.kt (1)
  • isOnline (58-70)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/CreateFixedDepositAccountViewmodel.kt (4)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/CreateShareAccountViewModel.kt (1)
  • isOnline (54-66)
feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountViewModel.kt (1)
  • isOnline (69-85)
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountViewModel.kt (1)
  • isOnline (387-399)
feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/SavingsAccountViewModel.kt (1)
  • isOnline (58-70)
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/PreviewPage.kt (3)
core/ui/src/commonMain/kotlin/com/mifos/core/ui/components/MifosRowWithTextAndButton.kt (1)
  • MifosRowWithTextAndButton (35-95)
core/ui/src/commonMain/kotlin/com/mifos/core/ui/components/MifosTwoButtonRow.kt (1)
  • MifosTwoButtonRow (31-91)
core/ui/src/commonMain/kotlin/com/mifos/core/ui/components/MifosListingComponent.kt (1)
  • MifosDefaultListingComponentFromStringResources (244-267)
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountScreen.kt (1)
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/PreviewPage.kt (1)
  • PreviewPage (76-143)
feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountViewModel.kt (4)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/CreateShareAccountViewModel.kt (1)
  • isOnline (54-66)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/CreateFixedDepositAccountViewmodel.kt (1)
  • isOnline (53-65)
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountViewModel.kt (1)
  • isOnline (387-399)
feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/SavingsAccountViewModel.kt (1)
  • isOnline (58-70)
feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/SavingsAccountViewModel.kt (4)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/createShareAccount/CreateShareAccountViewModel.kt (1)
  • isOnline (54-66)
feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/CreateFixedDepositAccountViewmodel.kt (1)
  • isOnline (53-65)
feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountViewModel.kt (1)
  • isOnline (69-85)
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountViewModel.kt (1)
  • isOnline (387-399)
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/SettingsPage.kt (3)
core/ui/src/commonMain/kotlin/com/mifos/core/ui/components/MifosCheckBox.kt (1)
  • MifosCheckBox (24-46)
core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/component/MifosOutlinedTextField.kt (4)
  • MifosOutlinedTextField (66-124)
  • MifosOutlinedTextField (126-243)
  • MifosOutlinedTextField (245-308)
  • MifosOutlinedTextField (415-487)
core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/component/MifosTextFieldDropdown.kt (1)
  • MifosTextFieldDropdown (39-112)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: PR Checks / Static Analysis Check
🔇 Additional comments (15)
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountScreen.kt (2)

171-176: LGTM!

The PreviewPage step is properly integrated into the stepper flow. The composable parameters match the expected signature from PreviewPage.kt, with modifier using its default value.


179-218: LGTM!

The scaffold implementation correctly integrates the snackbarHostState and the overlay loading indicator. The property rename to isOverlayLoadingActive aligns with the state model changes.

feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountRoute.kt (1)

26-30: LGTM!

The back navigation is now properly wired to the NavController.

Minor observation: Both navController and onNavigateBack are passed to RecurringAccountScreen. If onNavigateBack always calls popBackStack(), consider whether passing only one is cleaner, though current approach allows flexibility.

feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountViewModel.kt (1)

69-85: LGTM - isOnline pattern is consistent with codebase.

The network-aware helper follows the same pattern used in other ViewModels (RecurringAccountViewModel, SavingsAccountViewModel, CreateShareAccountViewModel, etc.), maintaining consistency across the codebase. Based on relevant code snippets.

feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/SettingsPage.kt (1)

254-310: LGTM - Conditional frequency configuration block.

The new AnimatedVisibility block correctly shows the recurring frequency fields when depositFrequencySameAsGroupCenterMeeting is disabled. The implementation:

  • Follows the same pattern as the existing pre-mature closure section
  • Includes proper validation with error states (recurringFrequencyError, recurringFrequencyTypeError)
  • Uses consistent spacing and component structure
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/InterestPage.kt (1)

73-84: LGTM - Enhanced interest chart details.

The additional fields (name, end_date, description) provide more comprehensive information about the interest rate chart, improving the user experience.

feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/PreviewPage.kt (1)

76-143: Well-structured preview page.

The PreviewPage composable is well-organized with clear section separations for Details, Terms, Settings, Interest, and Charges. The composition follows the established patterns in the codebase.

core/model/src/commonMain/kotlin/com/mifos/core/model/objects/payloads/RecurringDepositAccountPayload.kt (1)

35-43: Confirm amount type change and new pre-closure fields against backend schema

Switching mandatoryRecommendedDepositAmount to Double? and adding the three preClosure* fields looks consistent with other amount fields, but it is a wire-format change. Please double-check these names and types match the backend API and that any callers previously treating mandatoryRecommendedDepositAmount as Int are updated.

core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/RecurringAccountRepositoryImp.kt (1)

16-41: Repository impl now correctly propagates GenericResponse

The implementation cleanly switches createRecurringDepositAccount to Flow<DataState<GenericResponse>> and continues delegating to DataManagerRecurringAccount with asDataStateFlow(). The change is cohesive with the updated DataManager signature and doesn’t introduce extra behavior.

core/data/src/commonMain/kotlin/com/mifos/core/data/repository/RecurringAccountRepository.kt (1)

15-27: Repository API now returns DataState; ensure all callers handle the new shape

Changing createRecurringDepositAccount to return Flow<DataState<GenericResponse>> instead of DataState<RecurringDeposit> is an intentional but breaking API change. As long as all call sites have been updated to consume GenericResponse (and any UI logic expecting a full RecurringDeposit model has been adjusted), this interface looks good.

core/network/src/commonMain/kotlin/com/mifos/core/network/services/RecurringAccountService.kt (1)

19-27: Returning Flow matches the new DataManager logic; confirm Ktorfit supports this shape

Switching createRecurringDepositAccount to Flow<HttpResponse> aligns with the manual parsing in DataManagerRecurringAccount. Please confirm this return type is supported by your Ktorfit configuration (or matches patterns used in other services) so that the Flow adapter and call serialization behave as expected.

feature/savings/src/commonMain/kotlin/com/mifos/feature/savings/savingsAccountv2/SavingsAccountViewModel.kt (2)

288-292: Robust handling of edited charge index mapping

Using indexOfFirst with safe calls and ?: -1 when mapping selectedEditCharge back to chargeOptions is a good improvement: it handles savingsProductTemplate/chargeOptions being null and gracefully falls back when the charge id is not found. No functional issues here.


460-472: Index initialization from template options remains sound

The reflowed index calculations for posting period, interest calculation, compounding period, and days‑in‑year types still correctly default to -1 when the corresponding option or selected value is missing. This keeps state initialization resilient to incomplete templates, which is good.

feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountViewModel.kt (2)

73-158: Account creation payload & dialog/overlay handling look consistent

The expanded RecurringDepositAccountPayload wiring (charges, recurring frequency, lock‑in, and pre‑closure penalty fields) is coherent and null‑safe, and the DataState handling correctly drives isOverlayLoadingActive plus the new SuccessResponseStatus dialog for both success and the IllegalStateException error case.

Assuming the repository emits IllegalStateException only for API‑level “business” errors, this split between inline dialog vs. full‑screen error is a reasonable UX choice, and the launchEffectKey = Random.nextInt() pattern should work well for triggering one‑shot effects in the UI.

Also applies to: 188-205, 918-924, 931-937


271-274: Submit action wiring and retry flow look correct

The introduction of RecurringAccountAction.OnSubmitRecurringAccount and its handling via createRecurringDepositAccount() wires the new preview step cleanly into the flow, and reusing the same retry()/loadRecurringAccountTemplate() path under RecurringAccountAction.Retry keeps the error‑recovery story simple.

No functional issues spotted here.

Also applies to: 400-405, 884-898, 900-903, 1037-1037

Comment on lines +14 to +15
<string name="feature_error_network_not_available">Network is not Available</string>

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Duplicate network error string with inconsistent naming and text.

This file already contains feature_loan_error_network_not_available at line 88 with value "Network not available". The new string:

  • Uses different naming convention (missing feature_loan_ prefix)
  • Has different text capitalization ("Network is not Available" vs "Network not available")

Consider removing one and standardizing on a single network error string, or if both are intentionally different, align the naming convention.

🤖 Prompt for AI Agents
In feature/loan/src/commonMain/composeResources/values/strings.xml around lines
14-15, you added a duplicate network error string with a different key and
capitalization; remove the new <string
name="feature_error_network_not_available"> entry and use the existing
feature_loan_error_network_not_available (line 88) with the standardized text
"Network not available"; if both variants are intentionally required, rename the
new key to include the feature_loan_ prefix and align its text to the project's
canonical wording, then update any callers to reference the chosen key.

Comment on lines 916 to 924
Res.string.installment_paid to (
dataState.data.repaymentSchedule.periods
?.count { it.complete == true }
?.toString()
?: "N/A"
dataState.data.repaymentSchedule.periods?.count { it.complete == true }
?.toString() ?: "N/A"
),
Res.string.installment_paid to (
dataState.data.repaymentSchedule.periods
?.count { it.complete == false }
?.toString()
?: "N/A"
dataState.data.repaymentSchedule.periods?.count { it.complete == false }
?.toString() ?: "N/A"
),
Res.string.total_installments to dataState.data.termFrequency.toString(),
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Bug: Duplicate map key causes data loss.

Res.string.installment_paid is used as the key for both entries at lines 916 and 920. In a Kotlin mapOf, duplicate keys result in only the last value being retained, so the count of completed installments is lost.

Based on the filter logic (complete == true vs complete == false), the second entry should likely use Res.string.installment_left.

Apply this diff to fix the duplicate key:

                         Res.string.installment_paid to (
                             dataState.data.repaymentSchedule.periods?.count { it.complete == true }
                                 ?.toString() ?: "N/A"
                             ),
-                        Res.string.installment_paid to (
+                        Res.string.installment_left to (
                             dataState.data.repaymentSchedule.periods?.count { it.complete == false }
                                 ?.toString() ?: "N/A"
                             ),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Res.string.installment_paid to (
dataState.data.repaymentSchedule.periods
?.count { it.complete == true }
?.toString()
?: "N/A"
dataState.data.repaymentSchedule.periods?.count { it.complete == true }
?.toString() ?: "N/A"
),
Res.string.installment_paid to (
dataState.data.repaymentSchedule.periods
?.count { it.complete == false }
?.toString()
?: "N/A"
dataState.data.repaymentSchedule.periods?.count { it.complete == false }
?.toString() ?: "N/A"
),
Res.string.total_installments to dataState.data.termFrequency.toString(),
Res.string.installment_paid to (
dataState.data.repaymentSchedule.periods?.count { it.complete == true }
?.toString() ?: "N/A"
),
Res.string.installment_left to (
dataState.data.repaymentSchedule.periods?.count { it.complete == false }
?.toString() ?: "N/A"
),
Res.string.total_installments to dataState.data.termFrequency.toString(),
🤖 Prompt for AI Agents
In
feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountViewModel.kt
around lines 916 to 924, there is a duplicate map key
(Res.string.installment_paid) used for both completed and incomplete installment
counts which causes the first value to be overwritten; change the second key to
Res.string.installment_left so the map contains both "installments paid" and
"installments left" entries, keeping the existing count logic and formatting
unchanged.

Comment on lines +291 to +301
Res.string.feature_recurring_deposit_penal_interest_percentage to state.recurringDepositAccountSettings.preMatureClosure.penalInterest,

Res.string.feature_recurring_deposit_period to if (state.recurringDepositAccountSettings.preMatureClosure.interestPeriodIndex != -1) {
state.template.preClosurePenalInterestOnTypeOptions?.getOrNull(
state.recurringDepositAccountSettings.preMatureClosure.interestPeriodIndex,
)?.value.orEmpty()
} else {
""
},

Res.string.feature_recurring_deposit_period to state.recurringDepositAccountSettings.preMatureClosure.minimumBalanceForInterestCalculation,
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Bug: Duplicate map key feature_recurring_deposit_period causes data loss.

Res.string.feature_recurring_deposit_period is used as a key twice in this map (lines 293 and 301). The second entry will overwrite the first, losing the pre-closure interest period data.

Line 293 shows the interest period type, while line 301 shows the minimum balance for interest calculation. These should have distinct keys.

Consider using a different string resource key for line 301, such as a new feature_recurring_deposit_minimum_balance_for_interest or similar:

             Res.string.feature_recurring_deposit_period to if (state.recurringDepositAccountSettings.preMatureClosure.interestPeriodIndex != -1) {
                 state.template.preClosurePenalInterestOnTypeOptions?.getOrNull(
                     state.recurringDepositAccountSettings.preMatureClosure.interestPeriodIndex,
                 )?.value.orEmpty()
             } else {
                 ""
             },

-            Res.string.feature_recurring_deposit_period to state.recurringDepositAccountSettings.preMatureClosure.minimumBalanceForInterestCalculation,
+            Res.string.feature_recurring_deposit_minimum_balance_for_interest to state.recurringDepositAccountSettings.preMatureClosure.minimumBalanceForInterestCalculation,

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/PreviewPage.kt
around lines 291 to 301, the map uses the same key
Res.string.feature_recurring_deposit_period twice so the second entry overwrites
the first; change the second key to a distinct string resource (e.g.,
Res.string.feature_recurring_deposit_minimum_balance_for_interest or an existing
appropriate key), update resources if needed, and ensure the map entry value
remains
state.recurringDepositAccountSettings.preMatureClosure.minimumBalanceForInterestCalculation.

Comment on lines +354 to +356
Res.string.feature_recurring_deposit_product_name to state.template.productOptions?.get(
state.recurringDepositAccountDetail.loanProductSelected,
)?.name.orEmpty(),
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for loanProductSelected definition and usage
rg -n "loanProductSelected" --type=kotlin -B 3 -A 3 | head -100

Repository: openMF/android-client

Length of output: 15302


🏁 Script executed:

#!/bin/bash
# Find RecurringAccountDetail definition
rg -n "data class RecurringAccountDetail|class RecurringAccountDetail" --type=kotlin -A 20

Repository: openMF/android-client

Length of output: 8116


🏁 Script executed:

#!/bin/bash
# Check for similar product selection properties in recurring deposit context
rg -n "productSelected|ProductSelected" feature/recurringDeposit --type=kotlin | head -50

Repository: openMF/android-client

Length of output: 1875


Rename loanProductSelected to recurringDepositProductSelected in RecurringAccountDetailsState.

The property loanProductSelected is defined in RecurringAccountDetailsState and uses "loan" terminology despite being part of the recurring deposit feature. This appears to be a copy-paste oversight from the loan account feature. The property is accessed as an index into recurring deposit product options and should be renamed for semantic clarity. This change affects 8 usages across the recurring deposit module (RecurringAccountViewModel, PreviewPage, and DetailsPage).

🤖 Prompt for AI Agents
In
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/PreviewPage.kt
around lines 354-356, the state property loanProductSelected is incorrectly
named for recurring deposits; rename it to recurringDepositProductSelected in
RecurringAccountDetailsState and update all usages (RecurringAccountViewModel,
PreviewPage, DetailsPage and any other 7 remaining references) to use the new
name, keeping the same type and nullability, update any serialization/parcel/map
keys or constructor parameters that reference the old name, and run a build to
fix compiler errors and adjust tests or migrations accordingly.

import kotlin.time.ExperimentalTime

const val TOTAL_STEPS = 4
const val TOTAL_STEPS = 6
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

Guard against negative currentStep on back press and re‑confirm TOTAL_STEPS semantics

moveToNextStep uses if (state.currentStep < state.totalSteps) currentStep++ else Finish, and NavigateToStep allows index in 0..state.totalSteps. With TOTAL_STEPS = 6, that means you’re treating totalSteps as the max step index (0..6) rather than a pure “count”. That’s fine, but it’s worth double‑checking that the UI step indicators also assume 0‑based indices up to TOTAL_STEPS, not 1..TOTAL_STEPS.

More critically, OnBackPress now unconditionally does currentStep = current - 1, which can drive currentStep negative if invoked on step 0. Safer would be to delegate to NavigateBack when at the first step:

             RecurringAccountAction.OnBackPress -> {
-                val current = state.currentStep
-                mutableStateFlow.update {
-                    it.copy(
-                        currentStep = current - 1,
-                    )
-                }
+                val current = state.currentStep
+                if (current <= 0) {
+                    sendEvent(RecurringAccountEvent.NavigateBack)
+                } else {
+                    mutableStateFlow.update {
+                        it.copy(
+                            currentStep = current - 1,
+                        )
+                    }
+                }
             }

This avoids negative indices and cleanly exits the flow when backing from the first step.

Also applies to: 60-71, 750-761, 763-770

Comment on lines +84 to +88
depositPeriodFrequencyId = (
state.template.periodFrequencyTypeOptions?.getOrNull(
state.recurringDepositAccountSettings.depositPeriod.periodType,
)?.id
),
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

Fix ID/index mismatch for period/lock‑in/pre‑closure option mapping

In several places you store option IDs into fields that are named and later treated as indices, then look them up again with get/getOrNull when building the payload. That will resolve the wrong option (or null) when IDs and list positions diverge, so the server can receive incorrect depositPeriodFrequencyId, lockinPeriodFrequencyType, or preClosurePenalInterestOnTypeId values.

Concretely:

  • SetDepositPeriodType writes periodType = options?.get(action.periodType)?.id, but depositPeriodFrequencyId later does options?.getOrNull(depositPeriod.periodType)?.id.
  • SetLockInPeriodType writes frequencyTypeIndex = options?.get(action.frequencyTypeIndex)?.id, but the payload uses it as an index in getOrNull(...).
  • SetPreMatureClosureInterestPeriodIndex writes interestPeriodIndex = options?.get(action.interestPeriodIndex)?.id, and the payload again treats it as an index.

Align these by keeping indices in state and only converting to IDs when constructing the payload. For example:

-                    is RecurringAccountAction.RecurringAccountSettingsAction.SetDepositPeriodType -> {
-                        mutableStateFlow.update { state ->
-                            state.copy(
-                                recurringDepositAccountSettings = state.recurringDepositAccountSettings.copy(
-                                    depositPeriod = state.recurringDepositAccountSettings.depositPeriod.copy(
-                                        periodType = state.template.periodFrequencyTypeOptions?.get(
-                                            action.periodType,
-                                        )?.id ?: -1,
-                                    ),
-                                    depositPeriodTypeError = null,
-                                ),
-                            )
-                        }
-                    }
+                    is RecurringAccountAction.RecurringAccountSettingsAction.SetDepositPeriodType -> {
+                        mutableStateFlow.update { state ->
+                            state.copy(
+                                recurringDepositAccountSettings = state.recurringDepositAccountSettings.copy(
+                                    // keep the selected index; map to ID when building the payload
+                                    depositPeriod = state.recurringDepositAccountSettings.depositPeriod.copy(
+                                        periodType = action.periodType,
+                                    ),
+                                    depositPeriodTypeError = null,
+                                ),
+                            )
+                        }
+                    }
-                    is RecurringAccountAction.RecurringAccountSettingsAction.SetLockInPeriodType -> {
-                        mutableStateFlow.update { state ->
-                            state.copy(
-                                recurringDepositAccountSettings = state.recurringDepositAccountSettings.copy(
-                                    lockInPeriod = state.recurringDepositAccountSettings.lockInPeriod.copy(
-                                        frequencyTypeIndex = state.template.lockinPeriodFrequencyTypeOptions?.get(
-                                            action.frequencyTypeIndex,
-                                        )?.id ?: -1,
-                                    ),
-                                ),
-                            )
-                        }
-                    }
+                    is RecurringAccountAction.RecurringAccountSettingsAction.SetLockInPeriodType -> {
+                        mutableStateFlow.update { state ->
+                            state.copy(
+                                recurringDepositAccountSettings = state.recurringDepositAccountSettings.copy(
+                                    lockInPeriod = state.recurringDepositAccountSettings.lockInPeriod.copy(
+                                        // store index; payload maps index -> ID
+                                        frequencyTypeIndex = action.frequencyTypeIndex,
+                                    ),
+                                ),
+                            )
+                        }
+                    }
-                    is RecurringAccountAction.RecurringAccountSettingsAction.SetPreMatureClosureInterestPeriodIndex -> {
-                        mutableStateFlow.update {
-                            state.copy(
-                                recurringDepositAccountSettings = state.recurringDepositAccountSettings.copy(
-                                    preMatureClosure = state.recurringDepositAccountSettings.preMatureClosure.copy(
-                                        interestPeriodIndex = state.template.preClosurePenalInterestOnTypeOptions?.get(
-                                            action.interestPeriodIndex,
-                                        )?.id ?: -1,
-                                    ),
-                                ),
-                            )
-                        }
-                    }
+                    is RecurringAccountAction.RecurringAccountSettingsAction.SetPreMatureClosureInterestPeriodIndex -> {
+                        mutableStateFlow.update {
+                            state.copy(
+                                recurringDepositAccountSettings = state.recurringDepositAccountSettings.copy(
+                                    preMatureClosure = state.recurringDepositAccountSettings.preMatureClosure.copy(
+                                        // keep the selected index; payload maps index -> ID
+                                        interestPeriodIndex = action.interestPeriodIndex,
+                                    ),
+                                ),
+                            )
+                        }
+                    }

With this change, the existing payload lookups using getOrNull(<index>)?.id become consistent and deterministic.

Also applies to: 134-140, 151-157, 422-435, 449-461, 541-553

🤖 Prompt for AI Agents
feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountViewModel.kt
lines 84-88 (also apply same fix to ranges 134-140, 151-157, 422-435, 449-461,
541-553): state fields currently store option IDs where later code treats them
as list indices, causing wrong lookups; change the reducers to store the
selected option index (the raw index from the action) in state and only map
index->id when building the payload (i.e., keep
periodType/frequencyTypeIndex/interestPeriodIndex as indices in state, remove
storing .id there), then when constructing depositPeriodFrequencyId,
lockinPeriodFrequencyType, preClosurePenalInterestOnTypeId call
options?.getOrNull(index)?.id to convert to IDs; update all affected setters and
any state names if necessary to reflect they hold indices, ensuring consistency
across the listed line ranges.

@therajanmaurya therajanmaurya merged commit 8ff56ce into openMF:development Dec 12, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants