| package io.mifos.individuallending.internal.service; |
| |
| import io.mifos.individuallending.api.v1.domain.product.AccountDesignators; |
| import io.mifos.individuallending.api.v1.domain.product.ChargeProportionalDesignator; |
| import io.mifos.individuallending.api.v1.domain.workflow.Action; |
| import io.mifos.portfolio.api.v1.domain.ChargeDefinition; |
| import io.mifos.portfolio.service.internal.service.ConfigurableChargeDefinitionService; |
| import org.springframework.beans.factory.annotation.Autowired; |
| import org.springframework.stereotype.Service; |
| |
| import javax.annotation.Nonnull; |
| import java.math.BigDecimal; |
| import java.time.temporal.ChronoUnit; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Map; |
| import java.util.stream.Collectors; |
| import java.util.stream.Stream; |
| |
| import static io.mifos.individuallending.api.v1.domain.product.ChargeIdentifiers.*; |
| |
| /** |
| * @author Myrle Krantz |
| */ |
| @Service |
| public class ChargeDefinitionService { |
| public static Stream<ChargeDefinition> defaultConfigurableIndividualLoanCharges() { |
| final List<ChargeDefinition> ret = new ArrayList<>(); |
| final ChargeDefinition processingFee = charge( |
| PROCESSING_FEE_NAME, |
| Action.DISBURSE, |
| BigDecimal.ONE, |
| AccountDesignators.CUSTOMER_LOAN_FEES, |
| AccountDesignators.PROCESSING_FEE_INCOME); |
| processingFee.setReadOnly(false); |
| |
| final ChargeDefinition loanOriginationFee = charge( |
| LOAN_ORIGINATION_FEE_NAME, |
| Action.DISBURSE, |
| BigDecimal.ONE, |
| AccountDesignators.CUSTOMER_LOAN_FEES, |
| AccountDesignators.ORIGINATION_FEE_INCOME); |
| loanOriginationFee.setReadOnly(false); |
| |
| final ChargeDefinition disbursementFee = charge( |
| DISBURSEMENT_FEE_NAME, |
| Action.DISBURSE, |
| BigDecimal.valueOf(0.1), |
| AccountDesignators.CUSTOMER_LOAN_FEES, |
| AccountDesignators.DISBURSEMENT_FEE_INCOME); |
| disbursementFee.setProportionalTo(ChargeProportionalDesignator.REQUESTED_DISBURSEMENT_DESIGNATOR.getValue()); |
| disbursementFee.setReadOnly(false); |
| |
| final ChargeDefinition lateFee = charge( |
| LATE_FEE_NAME, |
| Action.ACCEPT_PAYMENT, |
| BigDecimal.TEN, |
| AccountDesignators.CUSTOMER_LOAN_FEES, |
| AccountDesignators.LATE_FEE_INCOME); |
| lateFee.setAccrueAction(Action.MARK_LATE.name()); |
| lateFee.setAccrualAccountDesignator(AccountDesignators.LATE_FEE_ACCRUAL); |
| lateFee.setProportionalTo(ChargeProportionalDesignator.CONTRACTUAL_REPAYMENT_DESIGNATOR.getValue()); |
| lateFee.setChargeOnTop(true); |
| lateFee.setReadOnly(false); |
| |
| ret.add(processingFee); |
| ret.add(loanOriginationFee); |
| ret.add(disbursementFee); |
| ret.add(lateFee); |
| |
| return ret.stream(); |
| } |
| |
| static Stream<ChargeDefinition> individualLoanChargesDerivedFromConfiguration() { |
| final List<ChargeDefinition> ret = new ArrayList<>(); |
| |
| final ChargeDefinition disbursePayment = new ChargeDefinition(); |
| disbursePayment.setChargeAction(Action.DISBURSE.name()); |
| disbursePayment.setIdentifier(DISBURSE_PAYMENT_ID); |
| disbursePayment.setName(DISBURSE_PAYMENT_NAME); |
| disbursePayment.setDescription(DISBURSE_PAYMENT_NAME); |
| disbursePayment.setFromAccountDesignator(AccountDesignators.CUSTOMER_LOAN_PRINCIPAL); |
| disbursePayment.setToAccountDesignator(AccountDesignators.ENTRY); |
| disbursePayment.setProportionalTo(ChargeProportionalDesignator.REQUESTED_DISBURSEMENT_DESIGNATOR.getValue()); |
| disbursePayment.setChargeMethod(ChargeDefinition.ChargeMethod.PROPORTIONAL); |
| disbursePayment.setAmount(BigDecimal.valueOf(100)); |
| disbursePayment.setReadOnly(true); |
| |
| //TODO: Make multiple write off allowance defaultCharges. |
| /*final ChargeDefinition writeOffAllowanceCharge = charge( |
| ALLOW_FOR_WRITE_OFF_NAME, |
| Action.MARK_LATE, |
| BigDecimal.valueOf(30), |
| AccountDesignators.LOAN_FUNDS_SOURCE, |
| AccountDesignators.ARREARS_ALLOWANCE); |
| writeOffAllowanceCharge.setProportionalTo(ChargeProportionalDesignator.RUNNING_BALANCE_DESIGNATOR.getValue()); |
| writeOffAllowanceCharge.setReadOnly(true);*/ |
| |
| final ChargeDefinition interestCharge = charge( |
| INTEREST_NAME, |
| Action.ACCEPT_PAYMENT, |
| BigDecimal.valueOf(100), |
| AccountDesignators.CUSTOMER_LOAN_INTEREST, |
| AccountDesignators.INTEREST_INCOME); |
| interestCharge.setForCycleSizeUnit(ChronoUnit.YEARS); |
| interestCharge.setAccrueAction(Action.APPLY_INTEREST.name()); |
| interestCharge.setAccrualAccountDesignator(AccountDesignators.INTEREST_ACCRUAL); |
| interestCharge.setProportionalTo(ChargeProportionalDesignator.PRINCIPAL_DESIGNATOR.getValue()); |
| interestCharge.setChargeMethod(ChargeDefinition.ChargeMethod.INTEREST); |
| interestCharge.setReadOnly(true); |
| |
| final ChargeDefinition customerFeeRepaymentCharge = new ChargeDefinition(); |
| customerFeeRepaymentCharge.setChargeAction(Action.ACCEPT_PAYMENT.name()); |
| customerFeeRepaymentCharge.setIdentifier(REPAY_FEES_ID); |
| customerFeeRepaymentCharge.setName(REPAY_FEES_NAME); |
| customerFeeRepaymentCharge.setDescription(REPAY_FEES_NAME); |
| customerFeeRepaymentCharge.setFromAccountDesignator(AccountDesignators.ENTRY); |
| customerFeeRepaymentCharge.setToAccountDesignator(AccountDesignators.CUSTOMER_LOAN_FEES); |
| customerFeeRepaymentCharge.setProportionalTo(ChargeProportionalDesignator.TO_ACCOUNT_DESIGNATOR.getValue()); |
| customerFeeRepaymentCharge.setChargeMethod(ChargeDefinition.ChargeMethod.PROPORTIONAL); |
| customerFeeRepaymentCharge.setAmount(BigDecimal.valueOf(100)); |
| customerFeeRepaymentCharge.setReadOnly(true); |
| |
| final ChargeDefinition customerInterestRepaymentCharge = new ChargeDefinition(); |
| customerInterestRepaymentCharge.setChargeAction(Action.ACCEPT_PAYMENT.name()); |
| customerInterestRepaymentCharge.setIdentifier(REPAY_INTEREST_ID); |
| customerInterestRepaymentCharge.setName(REPAY_INTEREST_NAME); |
| customerInterestRepaymentCharge.setDescription(REPAY_INTEREST_NAME); |
| customerInterestRepaymentCharge.setFromAccountDesignator(AccountDesignators.ENTRY); |
| customerInterestRepaymentCharge.setToAccountDesignator(AccountDesignators.CUSTOMER_LOAN_INTEREST); |
| customerInterestRepaymentCharge.setProportionalTo(ChargeProportionalDesignator.TO_ACCOUNT_DESIGNATOR.getValue()); |
| customerInterestRepaymentCharge.setChargeMethod(ChargeDefinition.ChargeMethod.PROPORTIONAL); |
| customerInterestRepaymentCharge.setAmount(BigDecimal.valueOf(100)); |
| customerInterestRepaymentCharge.setReadOnly(true); |
| |
| final ChargeDefinition customerPrincipalRepaymentCharge = new ChargeDefinition(); |
| customerPrincipalRepaymentCharge.setChargeAction(Action.ACCEPT_PAYMENT.name()); |
| customerPrincipalRepaymentCharge.setIdentifier(REPAY_PRINCIPAL_ID); |
| customerPrincipalRepaymentCharge.setName(REPAY_PRINCIPAL_NAME); |
| customerPrincipalRepaymentCharge.setDescription(REPAY_PRINCIPAL_NAME); |
| customerPrincipalRepaymentCharge.setFromAccountDesignator(AccountDesignators.ENTRY); |
| customerPrincipalRepaymentCharge.setToAccountDesignator(AccountDesignators.CUSTOMER_LOAN_PRINCIPAL); |
| customerPrincipalRepaymentCharge.setProportionalTo(ChargeProportionalDesignator.REQUESTED_REPAYMENT_DESIGNATOR.getValue()); |
| customerPrincipalRepaymentCharge.setChargeMethod(ChargeDefinition.ChargeMethod.PROPORTIONAL); |
| customerPrincipalRepaymentCharge.setAmount(BigDecimal.valueOf(100)); |
| customerPrincipalRepaymentCharge.setReadOnly(true); |
| |
| ret.add(disbursePayment); |
| //ret.add(writeOffAllowanceCharge); |
| ret.add(interestCharge); |
| ret.add(customerPrincipalRepaymentCharge); |
| ret.add(customerInterestRepaymentCharge); |
| ret.add(customerFeeRepaymentCharge); |
| |
| return ret.stream(); |
| } |
| private final ConfigurableChargeDefinitionService configurableChargeDefinitionService; |
| |
| @Autowired |
| public ChargeDefinitionService( |
| final ConfigurableChargeDefinitionService configurableChargeDefinitionService) { |
| this.configurableChargeDefinitionService = configurableChargeDefinitionService; |
| } |
| |
| private Stream<ChargeDefinition> getAllChargeDefinitions(final String productIdentifier) { |
| final Stream<ChargeDefinition> configurableChargeDefinitions = configurableChargeDefinitionService.findAllEntities(productIdentifier); |
| final Stream<ChargeDefinition> derivedChargeDefinitions = individualLoanChargesDerivedFromConfiguration(); |
| return Stream.concat(configurableChargeDefinitions, derivedChargeDefinitions); |
| } |
| |
| @Nonnull |
| public Map<String, List<ChargeDefinition>> getChargeDefinitionsMappedByChargeAction( |
| final String productIdentifier) |
| { |
| final Stream<ChargeDefinition> chargeDefinitions = getAllChargeDefinitions(productIdentifier); |
| |
| return chargeDefinitions |
| .collect(Collectors.groupingBy(ChargeDefinition::getChargeAction, |
| Collectors.mapping(x -> x, Collectors.toList()))); |
| } |
| |
| @Nonnull |
| public Map<String, List<ChargeDefinition>> getChargeDefinitionsMappedByAccrueAction( |
| final String productIdentifier) |
| { |
| final Stream<ChargeDefinition> chargeDefinitions = getAllChargeDefinitions(productIdentifier); |
| |
| return chargeDefinitions |
| .filter(x -> x.getAccrueAction() != null) |
| .collect(Collectors.groupingBy(ChargeDefinition::getAccrueAction, |
| Collectors.mapping(x -> x, Collectors.toList()))); |
| } |
| |
| private static ChargeDefinition charge( |
| final String name, |
| final Action action, |
| final BigDecimal defaultAmount, |
| final String fromAccount, |
| final String toAccount) |
| { |
| final ChargeDefinition ret = new ChargeDefinition(); |
| |
| ret.setIdentifier(name.toLowerCase(Locale.US).replace(" ", "-")); |
| ret.setName(name); |
| ret.setDescription(name); |
| ret.setChargeAction(action.name()); |
| ret.setAmount(defaultAmount); |
| ret.setChargeMethod(ChargeDefinition.ChargeMethod.PROPORTIONAL); |
| ret.setProportionalTo(ChargeProportionalDesignator.MAXIMUM_BALANCE_DESIGNATOR.getValue()); |
| ret.setFromAccountDesignator(fromAccount); |
| ret.setToAccountDesignator(toAccount); |
| |
| return ret; |
| } |
| } |