Skip to content

Commit ca2b7b3

Browse files
committed
feat(loan): Implement Loan Charge-Off Screen
1 parent 525e6d1 commit ca2b7b3

27 files changed

Lines changed: 897 additions & 5 deletions

File tree

core/data/src/commonMain/kotlin/com/mifos/core/data/di/RepositoryModule.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import com.mifos.core.data.repository.LoanAccountDisbursementRepository
4545
import com.mifos.core.data.repository.LoanAccountRepository
4646
import com.mifos.core.data.repository.LoanAccountSummaryRepository
4747
import com.mifos.core.data.repository.LoanChargeFormRepository
48+
import com.mifos.core.data.repository.LoanChargeOffRepository
4849
import com.mifos.core.data.repository.LoanChargeRepository
4950
import com.mifos.core.data.repository.LoanRepaymentRepository
5051
import com.mifos.core.data.repository.LoanRepaymentScheduleRepository
@@ -114,6 +115,7 @@ import com.mifos.core.data.repositoryImp.LoanAccountDisbursementRepositoryImp
114115
import com.mifos.core.data.repositoryImp.LoanAccountRepositoryImp
115116
import com.mifos.core.data.repositoryImp.LoanAccountSummaryRepositoryImp
116117
import com.mifos.core.data.repositoryImp.LoanChargeFormRepositoryImp
118+
import com.mifos.core.data.repositoryImp.LoanChargeOffRepositoryImpl
117119
import com.mifos.core.data.repositoryImp.LoanChargeRepositoryImp
118120
import com.mifos.core.data.repositoryImp.LoanRepaymentRepositoryImp
119121
import com.mifos.core.data.repositoryImp.LoanRepaymentScheduleRepositoryImp
@@ -197,6 +199,7 @@ val RepositoryModule = module {
197199
singleOf(::LoanRepaymentScheduleRepositoryImp) bind LoanRepaymentScheduleRepository::class
198200
singleOf(::LoanTransactionsRepositoryImp) bind LoanTransactionsRepository::class
199201
singleOf(::LoanReschedulesRepositoryImpl) bind LoanReschedulesRepository::class
202+
singleOf(::LoanChargeOffRepositoryImpl) bind LoanChargeOffRepository::class
200203

201204
// Account Transfer
202205
singleOf(::AmountTransferRepositoryImp) bind AmountTransferRepository::class
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright 2026 Mifos Initiative
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this
6+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
7+
*
8+
* See https://github.com/openMF/mifos-x-field-officer-app/blob/master/LICENSE.md
9+
*/
10+
package com.mifos.core.data.mappers.loan
11+
12+
import com.mifos.core.model.objects.account.loan.ChargeOffReasonOption
13+
import com.mifos.core.network.dto.loans.ChargeOffReasonOptionDto
14+
15+
fun ChargeOffReasonOptionDto.toModel(): ChargeOffReasonOption = ChargeOffReasonOption(
16+
id = id,
17+
name = name,
18+
position = position,
19+
description = description,
20+
active = active,
21+
mandatory = mandatory,
22+
)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright 2026 Mifos Initiative
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this
6+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
7+
*
8+
* See https://github.com/openMF/mifos-x-field-officer-app/blob/master/LICENSE.md
9+
*/
10+
package com.mifos.core.data.mappers.loan
11+
12+
import com.mifos.core.model.objects.account.loan.LoanChargeOffInput
13+
import com.mifos.core.network.dto.loans.LoanChargeOffRequestDto
14+
15+
fun LoanChargeOffInput.toDto(): LoanChargeOffRequestDto = LoanChargeOffRequestDto(
16+
chargeOffReasonId = chargeOffReasonId,
17+
transactionDate = transactionDate,
18+
externalId = externalId,
19+
note = note,
20+
locale = locale,
21+
dateFormat = dateFormat,
22+
)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright 2026 Mifos Initiative
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this
6+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
7+
*
8+
* See https://github.com/openMF/mifos-x-field-officer-app/blob/master/LICENSE.md
9+
*/
10+
package com.mifos.core.data.repository
11+
12+
import com.mifos.core.common.utils.DataState
13+
import com.mifos.core.model.objects.account.loan.ChargeOffReasonOption
14+
import com.mifos.core.model.objects.account.loan.LoanChargeOffInput
15+
16+
interface LoanChargeOffRepository {
17+
18+
suspend fun chargeOff(loanId: Int, loanChargeOffInput: LoanChargeOffInput): DataState<Unit>
19+
20+
suspend fun getChargeOffTemplate(loanId: Int): DataState<List<ChargeOffReasonOption>>
21+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright 2026 Mifos Initiative
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this
6+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
7+
*
8+
* See https://github.com/openMF/mifos-x-field-officer-app/blob/master/LICENSE.md
9+
*/
10+
package com.mifos.core.data.repositoryImp
11+
12+
import com.mifos.core.common.utils.DataState
13+
import com.mifos.core.data.mappers.loan.toDto
14+
import com.mifos.core.data.mappers.loan.toModel
15+
import com.mifos.core.data.repository.LoanChargeOffRepository
16+
import com.mifos.core.data.util.NetworkMonitor
17+
import com.mifos.core.data.util.runAsDataState
18+
import com.mifos.core.model.objects.account.loan.ChargeOffReasonOption
19+
import com.mifos.core.model.objects.account.loan.LoanChargeOffInput
20+
import com.mifos.core.network.datamanager.DataManagerLoan
21+
import template.core.base.common.manager.DispatcherManager
22+
23+
class LoanChargeOffRepositoryImpl(
24+
private val dataManagerLoan: DataManagerLoan,
25+
private val networkMonitor: NetworkMonitor,
26+
private val dispatcher: DispatcherManager,
27+
) : LoanChargeOffRepository {
28+
override suspend fun chargeOff(
29+
loanId: Int,
30+
loanChargeOffInput: LoanChargeOffInput,
31+
): DataState<Unit> {
32+
return runAsDataState(
33+
networkMonitor = networkMonitor,
34+
context = dispatcher.io,
35+
) {
36+
dataManagerLoan.chargeOff(loanId, loanChargeOffInput.toDto())
37+
}
38+
}
39+
40+
override suspend fun getChargeOffTemplate(loanId: Int): DataState<List<ChargeOffReasonOption>> {
41+
return runAsDataState(
42+
networkMonitor = networkMonitor,
43+
context = dispatcher.io,
44+
) {
45+
dataManagerLoan.getChargeOffTemplate(loanId).chargeOffReasonOptions.map { it.toModel() }
46+
}
47+
}
48+
}

core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/icon/MifosIcons.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import androidx.compose.material.icons.filled.Link
4747
import androidx.compose.material.icons.filled.LocationOn
4848
import androidx.compose.material.icons.filled.Lock
4949
import androidx.compose.material.icons.filled.Menu
50+
import androidx.compose.material.icons.filled.MoneyOff
5051
import androidx.compose.material.icons.filled.Notifications
5152
import androidx.compose.material.icons.filled.Paid
5253
import androidx.compose.material.icons.filled.Payments
@@ -265,6 +266,7 @@ object MifosIcons {
265266
val Camera = Icons.Outlined.Camera
266267

267268
val Export = Icons.Default.IosShare
269+
val chargeOff = Icons.Default.MoneyOff
268270
val DonutLarge = Icons.Outlined.DonutLarge
269271
val Schedule = Icons.Outlined.Schedule
270272
val Adjust = Icons.Default.Adjust

core/domain/src/commonMain/kotlin/com/mifos/core/domain/di/UseCaseModule.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ import com.mifos.core.domain.useCases.ValidateServerEndPointUseCase
8989
import com.mifos.core.domain.useCases.ValidateServerPortUseCase
9090
import com.mifos.core.domain.useCases.ValidateServerProtocolUseCase
9191
import com.mifos.core.domain.useCases.ValidateServerTenantUseCase
92+
import com.mifos.core.domain.useCases.loanChargeOff.GetLoanChargeOffTemplateUseCase
93+
import com.mifos.core.domain.useCases.loanChargeOff.LoanChargeOffUseCase
9294
import org.koin.core.module.dsl.factoryOf
9395
import org.koin.dsl.module
9496

@@ -173,4 +175,6 @@ val UseCaseModule = module {
173175
factoryOf(::DeleteNoteUseCase)
174176
factoryOf(::CreateSignatureUseCase)
175177
factoryOf(::UpdateSignatureUseCase)
178+
factoryOf(::GetLoanChargeOffTemplateUseCase)
179+
factoryOf(::LoanChargeOffUseCase)
176180
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright 2026 Mifos Initiative
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this
6+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
7+
*
8+
* See https://github.com/openMF/mifos-x-field-officer-app/blob/master/LICENSE.md
9+
*/
10+
package com.mifos.core.domain.useCases.loanChargeOff
11+
12+
import com.mifos.core.common.utils.DataState
13+
import com.mifos.core.data.repository.LoanChargeOffRepository
14+
import com.mifos.core.model.objects.account.loan.ChargeOffReasonOption
15+
16+
class GetLoanChargeOffTemplateUseCase(
17+
val repository: LoanChargeOffRepository,
18+
) {
19+
suspend operator fun invoke(
20+
loanId: Int,
21+
): DataState<List<ChargeOffReasonOption>> = repository.getChargeOffTemplate(loanId)
22+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright 2026 Mifos Initiative
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this
6+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
7+
*
8+
* See https://github.com/openMF/mifos-x-field-officer-app/blob/master/LICENSE.md
9+
*/
10+
package com.mifos.core.domain.useCases.loanChargeOff
11+
12+
import com.mifos.core.common.utils.DataState
13+
import com.mifos.core.data.repository.LoanChargeOffRepository
14+
import com.mifos.core.model.objects.account.loan.LoanChargeOffInput
15+
16+
class LoanChargeOffUseCase(
17+
val repository: LoanChargeOffRepository,
18+
) {
19+
suspend operator fun invoke(
20+
loanId: Int,
21+
loanChargeOffInput: LoanChargeOffInput,
22+
): DataState<Unit> = repository.chargeOff(loanId, loanChargeOffInput)
23+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Copyright 2026 Mifos Initiative
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this
6+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
7+
*
8+
* See https://github.com/openMF/mifos-x-field-officer-app/blob/master/LICENSE.md
9+
*/
10+
package com.mifos.core.model.objects.account.loan
11+
12+
data class ChargeOffReasonOption(
13+
val id: Int,
14+
val name: String,
15+
val position: Int,
16+
val description: String,
17+
val active: Boolean,
18+
val mandatory: Boolean,
19+
)

0 commit comments

Comments
 (0)