FINERACT-1932: Fineract modularization Fineract progressive loan module
This commit is contained in:
committed by
Adam Saghy
parent
f59ae64222
commit
53f4864980
@@ -243,9 +243,13 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
@Column(name = "loan_transaction_strategy_name")
|
||||
private String transactionProcessingStrategyName;
|
||||
|
||||
// TODO FINERACT-1932-Fineract modularization: Move to fineract-progressive-loan module after removing association
|
||||
// from Loan entity
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true, fetch = FetchType.LAZY)
|
||||
private List<LoanPaymentAllocationRule> paymentAllocationRules = new ArrayList<>();
|
||||
|
||||
// TODO FINERACT-1932-Fineract modularization: Move to fineract-progressive-loan module after removing association
|
||||
// from Loan entity
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true, fetch = FetchType.LAZY)
|
||||
private List<LoanCreditAllocationRule> creditAllocationRules = new ArrayList<>();
|
||||
|
||||
|
||||
+1
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.domain;
|
||||
|
||||
// TODO FINERACT-1932-Fineract modularization: Move to fineract-progressive-loan module after refactor of Loan and LoanTransaction classes
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Convert;
|
||||
import jakarta.persistence.Entity;
|
||||
|
||||
+1
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.domain;
|
||||
|
||||
// TODO FINERACT-1932-Fineract modularization: Move to fineract-progressive-loan module after refactor of Loan and LoanTransaction classes
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Convert;
|
||||
import jakarta.persistence.Entity;
|
||||
|
||||
+1
@@ -32,6 +32,7 @@ import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDa
|
||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||
|
||||
// TODO FINERACT-1932-Fineract modularization: Move to fineract-progressive-loan module after refactor of Loan and LoanTransaction classes
|
||||
@Entity
|
||||
@Table(name = "m_loan_reage_parameter")
|
||||
@AllArgsConstructor
|
||||
|
||||
+1
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.domain.reaging;
|
||||
|
||||
// TODO FINERACT-1932-Fineract modularization: Move to fineract-progressive-loan module after refactor of Loan and LoanTransaction classes
|
||||
import java.util.Optional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
-1358
File diff suppressed because it is too large
Load Diff
-98
@@ -1,98 +0,0 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import java.time.LocalDate;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.Optional;
|
||||
import lombok.Getter;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@Getter
|
||||
public class ChargeOrTransaction implements Comparable<ChargeOrTransaction> {
|
||||
|
||||
private final Optional<LoanCharge> loanCharge;
|
||||
private final Optional<LoanTransaction> loanTransaction;
|
||||
|
||||
public ChargeOrTransaction(LoanCharge loanCharge) {
|
||||
this.loanCharge = Optional.of(loanCharge);
|
||||
this.loanTransaction = Optional.empty();
|
||||
}
|
||||
|
||||
public ChargeOrTransaction(LoanTransaction loanTransaction) {
|
||||
this.loanTransaction = Optional.of(loanTransaction);
|
||||
this.loanCharge = Optional.empty();
|
||||
}
|
||||
|
||||
private LocalDate getEffectiveDate() {
|
||||
if (loanCharge.isPresent()) {
|
||||
if (isBackdatedCharge()) {
|
||||
return loanCharge.get().getDueDate();
|
||||
} else {
|
||||
return loanCharge.get().getSubmittedOnDate();
|
||||
}
|
||||
} else if (loanTransaction.isPresent()) {
|
||||
return loanTransaction.get().getTransactionDate();
|
||||
} else {
|
||||
throw new RuntimeException("Either charge or transaction should be present");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isBackdatedCharge() {
|
||||
return loanCharge.get().getDueDate().isBefore(loanCharge.get().getSubmittedOnDate());
|
||||
}
|
||||
|
||||
private LocalDate getSubmittedOnDate() {
|
||||
if (loanCharge.isPresent()) {
|
||||
return loanCharge.get().getSubmittedOnDate();
|
||||
} else if (loanTransaction.isPresent()) {
|
||||
return loanTransaction.get().getSubmittedOnDate();
|
||||
} else {
|
||||
throw new RuntimeException("Either charge or transaction should be present");
|
||||
}
|
||||
}
|
||||
|
||||
private OffsetDateTime getCreatedDateTime() {
|
||||
if (loanCharge.isPresent() && loanCharge.get().getCreatedDate().isPresent()) {
|
||||
return loanCharge.get().getCreatedDate().get();
|
||||
} else if (loanTransaction.isPresent()) {
|
||||
return loanTransaction.get().getCreatedDateTime();
|
||||
} else {
|
||||
throw new RuntimeException("Either charge with createdDate or transaction created datetime should be present");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressFBWarnings(value = "EQ_COMPARETO_USE_OBJECT_EQUALS", justification = "TODO: fix this! See: https://stackoverflow.com/questions/2609037/findbugs-how-to-solve-eq-compareto-use-object-equals")
|
||||
public int compareTo(@NotNull ChargeOrTransaction o) {
|
||||
int datePortion = this.getEffectiveDate().compareTo(o.getEffectiveDate());
|
||||
if (datePortion == 0) {
|
||||
int submittedDate = this.getSubmittedOnDate().compareTo(o.getSubmittedOnDate());
|
||||
if (submittedDate == 0) {
|
||||
return this.getCreatedDateTime().compareTo(o.getCreatedDateTime());
|
||||
}
|
||||
return submittedDate;
|
||||
}
|
||||
return datePortion;
|
||||
}
|
||||
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.loanschedule.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelPeriod;
|
||||
|
||||
public final class LoanScheduleModelDownPaymentPeriod implements LoanScheduleModelPeriod {
|
||||
|
||||
private final int periodNumber;
|
||||
private final LocalDate periodDate;
|
||||
private Money principalDue;
|
||||
private final Money outstandingLoanBalance;
|
||||
|
||||
public static LoanScheduleModelDownPaymentPeriod downPayment(final int periodNumber, final LocalDate periodDate,
|
||||
final Money principalDue, final Money outstandingLoanBalance) {
|
||||
|
||||
return new LoanScheduleModelDownPaymentPeriod(periodNumber, periodDate, principalDue, outstandingLoanBalance);
|
||||
}
|
||||
|
||||
private LoanScheduleModelDownPaymentPeriod(int periodNumber, LocalDate periodDate, Money principalDue, Money outstandingLoanBalance) {
|
||||
this.periodNumber = periodNumber;
|
||||
this.periodDate = periodDate;
|
||||
this.principalDue = principalDue;
|
||||
this.outstandingLoanBalance = outstandingLoanBalance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoanSchedulePeriodData toData() {
|
||||
return LoanSchedulePeriodData.downPaymentOnlyPeriod(this.periodNumber, this.periodDate, this.principalDue.getAmount(),
|
||||
this.outstandingLoanBalance.getAmount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRepaymentPeriod() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDownPaymentPeriod() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer periodNumber() {
|
||||
return this.periodNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDate periodFromDate() {
|
||||
return this.periodDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDate periodDueDate() {
|
||||
return this.periodDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal principalDue() {
|
||||
BigDecimal value = BigDecimal.ZERO;
|
||||
if (this.principalDue != null) {
|
||||
value = this.principalDue.getAmount();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal interestDue() {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal feeChargesDue() {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal penaltyChargesDue() {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLoanCharges(BigDecimal feeCharge, BigDecimal penaltyCharge) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRecalculatedInterestComponent() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPrincipalAmount(Money principalDue) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInterestAmount(Money interestDue) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<LoanInterestRecalcualtionAdditionalDetails> getLoanCompoundingDetails() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEMIFixedSpecificToInstallmentTrue() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEMIFixedSpecificToInstallment() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal rescheduleInterestPortion() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRescheduleInterestPortion(BigDecimal rescheduleInterestPortion) {
|
||||
|
||||
}
|
||||
}
|
||||
+532
@@ -0,0 +1,532 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.loanschedule.data;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.RecalculationDetail;
|
||||
|
||||
public final class LoanScheduleParams {
|
||||
|
||||
// Actual period Number as per the schedule
|
||||
private int periodNumber;
|
||||
// Actual period Number plus interest only repayments
|
||||
private int instalmentNumber;
|
||||
|
||||
private LocalDate periodStartDate;
|
||||
private LocalDate actualRepaymentDate;
|
||||
|
||||
// variables for cumulative totals
|
||||
private Money totalCumulativePrincipal;
|
||||
private Money totalCumulativeInterest;
|
||||
private Money totalFeeChargesCharged;
|
||||
private Money totalPenaltyChargesCharged;
|
||||
private Money totalRepaymentExpected;
|
||||
private Money totalOutstandingInterestPaymentDueToGrace;
|
||||
|
||||
// early payments will be added here and as per the selected strategy
|
||||
// action will be performed on this value
|
||||
private Money reducePrincipal;
|
||||
|
||||
// principal changes will be added along with date(after applying rest)
|
||||
// from when these amounts will effect the outstanding balance for
|
||||
// interest calculation
|
||||
private final Map<LocalDate, Money> principalPortionMap;
|
||||
|
||||
// compounding(principal) amounts will be added along with
|
||||
// date(after applying compounding frequency)
|
||||
// from when these amounts will effect the outstanding balance for
|
||||
// interest calculation
|
||||
private final Map<LocalDate, Money> latePaymentMap;
|
||||
|
||||
// compounding(interest/Fee) amounts will be added along with
|
||||
// date(after applying compounding frequency)
|
||||
// from when these amounts will effect the outstanding balance for
|
||||
// interest calculation
|
||||
private final Map<LocalDate, Money> compoundingMap;
|
||||
private final Map<LocalDate, Map<LocalDate, Money>> compoundingDateVariations = new HashMap<>();
|
||||
private Money unCompoundedAmount;
|
||||
private Money compoundedInLastInstallment;
|
||||
|
||||
public Money getCompoundedInLastInstallment() {
|
||||
return this.compoundedInLastInstallment;
|
||||
}
|
||||
|
||||
public void setCompoundedInLastInstallment(Money compoundedInLastInstallment) {
|
||||
this.compoundedInLastInstallment = compoundedInLastInstallment;
|
||||
}
|
||||
|
||||
// disbursement map for tranche details(will added to outstanding
|
||||
// balance as per the start date)
|
||||
private final Map<LocalDate, Money> disburseDetailMap;
|
||||
private Money principalToBeScheduled;
|
||||
private Money outstandingBalance;
|
||||
|
||||
// total outstanding balance as per rest for interest calculation.
|
||||
private Money outstandingBalanceAsPerRest;
|
||||
|
||||
private final List<LoanRepaymentScheduleInstallment> installments;
|
||||
private final Collection<RecalculationDetail> recalculationDetails;
|
||||
private final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor;
|
||||
private final LocalDate scheduleTillDate;
|
||||
private final boolean partialUpdate;
|
||||
private int loanTermInDays;
|
||||
private final MonetaryCurrency currency;
|
||||
private final boolean applyInterestRecalculation;
|
||||
|
||||
private LoanScheduleParams(final int periodNumber, final int instalmentNumber, int loanTermInDays, LocalDate periodStartDate,
|
||||
final LocalDate actualRepaymentDate, final Money totalCumulativePrincipal, final Money totalCumulativeInterest,
|
||||
final Money totalFeeChargesCharged, final Money totalPenaltyChargesCharged, final Money totalRepaymentExpected,
|
||||
Money totalOutstandingInterestPaymentDueToGrace, final Money reducePrincipal, final Map<LocalDate, Money> principalPortionMap,
|
||||
final Map<LocalDate, Money> latePaymentMap, final Map<LocalDate, Money> compoundingMap, final Money unCompoundedAmount,
|
||||
final Map<LocalDate, Money> disburseDetailMap, Money principalToBeScheduled, final Money outstandingBalance,
|
||||
final Money outstandingBalanceAsPerRest, final List<LoanRepaymentScheduleInstallment> installments,
|
||||
final Collection<RecalculationDetail> recalculationDetails,
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, final LocalDate scheduleTillDate,
|
||||
final boolean partialUpdate, final MonetaryCurrency currency, final boolean applyInterestRecalculation) {
|
||||
this.periodNumber = periodNumber;
|
||||
this.instalmentNumber = instalmentNumber;
|
||||
this.loanTermInDays = loanTermInDays;
|
||||
this.periodStartDate = periodStartDate;
|
||||
this.actualRepaymentDate = actualRepaymentDate;
|
||||
this.totalCumulativePrincipal = totalCumulativePrincipal;
|
||||
this.totalCumulativeInterest = totalCumulativeInterest;
|
||||
this.totalFeeChargesCharged = totalFeeChargesCharged;
|
||||
this.totalPenaltyChargesCharged = totalPenaltyChargesCharged;
|
||||
this.totalRepaymentExpected = totalRepaymentExpected;
|
||||
this.totalOutstandingInterestPaymentDueToGrace = totalOutstandingInterestPaymentDueToGrace;
|
||||
this.reducePrincipal = reducePrincipal;
|
||||
this.principalPortionMap = principalPortionMap;
|
||||
this.latePaymentMap = latePaymentMap;
|
||||
this.compoundingMap = compoundingMap;
|
||||
this.unCompoundedAmount = unCompoundedAmount;
|
||||
this.disburseDetailMap = disburseDetailMap;
|
||||
this.principalToBeScheduled = principalToBeScheduled;
|
||||
this.outstandingBalance = outstandingBalance;
|
||||
this.outstandingBalanceAsPerRest = outstandingBalanceAsPerRest;
|
||||
this.installments = installments;
|
||||
this.recalculationDetails = recalculationDetails;
|
||||
this.loanRepaymentScheduleTransactionProcessor = loanRepaymentScheduleTransactionProcessor;
|
||||
this.scheduleTillDate = scheduleTillDate;
|
||||
this.partialUpdate = partialUpdate;
|
||||
this.currency = currency;
|
||||
this.applyInterestRecalculation = applyInterestRecalculation;
|
||||
if (this.currency != null) {
|
||||
this.compoundedInLastInstallment = Money.zero(this.currency);
|
||||
}
|
||||
}
|
||||
|
||||
public static LoanScheduleParams createLoanScheduleParamsForPartialUpdate(final int periodNumber, final int instalmentNumber,
|
||||
int loanTermInDays, LocalDate periodStartDate, final LocalDate actualRepaymentDate, final Money totalCumulativePrincipal,
|
||||
final Money totalCumulativeInterest, final Money totalFeeChargesCharged, final Money totalPenaltyChargesCharged,
|
||||
final Money totalRepaymentExpected, Money totalOutstandingInterestPaymentDueToGrace, final Money reducePrincipal,
|
||||
final Map<LocalDate, Money> principalPortionMap, final Map<LocalDate, Money> latePaymentMap,
|
||||
final Map<LocalDate, Money> compoundingMap, Money unCompoundedAmount, final Map<LocalDate, Money> disburseDetailMap,
|
||||
final Money principalToBeScheduled, final Money outstandingBalance, final Money outstandingBalanceAsPerRest,
|
||||
final List<LoanRepaymentScheduleInstallment> installments, final Collection<RecalculationDetail> recalculationDetails,
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, final LocalDate scheduleTillDate,
|
||||
final MonetaryCurrency currency, final boolean applyInterestRecalculation) {
|
||||
final boolean partialUpdate = true;
|
||||
return new LoanScheduleParams(periodNumber, instalmentNumber, loanTermInDays, periodStartDate, actualRepaymentDate,
|
||||
totalCumulativePrincipal, totalCumulativeInterest, totalFeeChargesCharged, totalPenaltyChargesCharged,
|
||||
totalRepaymentExpected, totalOutstandingInterestPaymentDueToGrace, reducePrincipal, principalPortionMap, latePaymentMap,
|
||||
compoundingMap, unCompoundedAmount, disburseDetailMap, principalToBeScheduled, outstandingBalance,
|
||||
outstandingBalanceAsPerRest, installments, recalculationDetails, loanRepaymentScheduleTransactionProcessor,
|
||||
scheduleTillDate, partialUpdate, currency, applyInterestRecalculation);
|
||||
}
|
||||
|
||||
public static LoanScheduleParams createLoanScheduleParamsForCompleteUpdate(final Collection<RecalculationDetail> recalculationDetails,
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, final LocalDate scheduleTillDate,
|
||||
final boolean applyInterestRecalculation) {
|
||||
final int periodNumber = 1;
|
||||
final int instalmentNumber = 1;
|
||||
final LocalDate periodStartDate = null;
|
||||
final LocalDate actualRepaymentDate = null;
|
||||
final Money totalCumulativePrincipal = null;
|
||||
final Money totalCumulativeInterest = null;
|
||||
final Money totalFeeChargesCharged = null;
|
||||
final Money totalPenaltyChargesCharged = null;
|
||||
final Money totalRepaymentExpected = null;
|
||||
final Money reducePrincipal = null;
|
||||
final Map<LocalDate, Money> principalPortionMap = null;
|
||||
final Map<LocalDate, Money> latePaymentMap = null;
|
||||
final Map<LocalDate, Money> compoundingMap = null;
|
||||
final Map<LocalDate, Money> disburseDetailMap = null;
|
||||
final Money principalToBeScheduled = null;
|
||||
final Money outstandingBalance = null;
|
||||
final Money outstandingBalanceAsPerRest = null;
|
||||
final List<LoanRepaymentScheduleInstallment> installments = new ArrayList<>();
|
||||
final boolean partialUpdate = false;
|
||||
final int loanTermInDays = 0;
|
||||
final Money totalOutstandingInterestPaymentDueToGrace = null;
|
||||
final MonetaryCurrency currency = null;
|
||||
final Money unCompoundedAmount = null;
|
||||
return new LoanScheduleParams(periodNumber, instalmentNumber, loanTermInDays, periodStartDate, actualRepaymentDate,
|
||||
totalCumulativePrincipal, totalCumulativeInterest, totalFeeChargesCharged, totalPenaltyChargesCharged,
|
||||
totalRepaymentExpected, totalOutstandingInterestPaymentDueToGrace, reducePrincipal, principalPortionMap, latePaymentMap,
|
||||
compoundingMap, unCompoundedAmount, disburseDetailMap, principalToBeScheduled, outstandingBalance,
|
||||
outstandingBalanceAsPerRest, installments, recalculationDetails, loanRepaymentScheduleTransactionProcessor,
|
||||
scheduleTillDate, partialUpdate, currency, applyInterestRecalculation);
|
||||
}
|
||||
|
||||
public static LoanScheduleParams createLoanScheduleParams(final MonetaryCurrency currency, final Money chargesDueAtTimeOfDisbursement,
|
||||
final LocalDate periodStartDate, final Money principalToBeScheduled) {
|
||||
final int loanTermInDays = 0;
|
||||
final int periodNumber = 1;
|
||||
final int instalmentNumber = 1;
|
||||
final Money totalCumulativePrincipal = Money.zero(currency);
|
||||
final Money totalCumulativeInterest = Money.zero(currency);
|
||||
final Money totalOutstandingInterestPaymentDueToGrace = Money.zero(currency);
|
||||
final LocalDate actualRepaymentDate = periodStartDate;
|
||||
final Money totalFeeChargesCharged = chargesDueAtTimeOfDisbursement;
|
||||
final Money totalPenaltyChargesCharged = Money.zero(currency);
|
||||
final Money totalRepaymentExpected = chargesDueAtTimeOfDisbursement;
|
||||
final Money reducePrincipal = Money.zero(currency);
|
||||
final Map<LocalDate, Money> principalPortionMap = new HashMap<>();
|
||||
final Map<LocalDate, Money> latePaymentMap = new HashMap<>();
|
||||
final Map<LocalDate, Money> compoundingMap = new TreeMap<>();
|
||||
final Map<LocalDate, Money> disburseDetailMap = new TreeMap<>();
|
||||
final Money outstandingBalance = principalToBeScheduled;
|
||||
final Money outstandingBalanceAsPerRest = principalToBeScheduled;
|
||||
final List<LoanRepaymentScheduleInstallment> installments = new ArrayList<>();
|
||||
final boolean partialUpdate = false;
|
||||
final Collection<RecalculationDetail> recalculationDetails = null;
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = null;
|
||||
final LocalDate scheduleTillDate = null;
|
||||
final Money unCompoundedAmount = Money.zero(currency);
|
||||
final boolean applyInterestRecalculation = false;
|
||||
return new LoanScheduleParams(periodNumber, instalmentNumber, loanTermInDays, periodStartDate, actualRepaymentDate,
|
||||
totalCumulativePrincipal, totalCumulativeInterest, totalFeeChargesCharged, totalPenaltyChargesCharged,
|
||||
totalRepaymentExpected, totalOutstandingInterestPaymentDueToGrace, reducePrincipal, principalPortionMap, latePaymentMap,
|
||||
compoundingMap, unCompoundedAmount, disburseDetailMap, principalToBeScheduled, outstandingBalance,
|
||||
outstandingBalanceAsPerRest, installments, recalculationDetails, loanRepaymentScheduleTransactionProcessor,
|
||||
scheduleTillDate, partialUpdate, currency, applyInterestRecalculation);
|
||||
}
|
||||
|
||||
public static LoanScheduleParams createLoanScheduleParams(final MonetaryCurrency currency, final Money chargesDueAtTimeOfDisbursement,
|
||||
final LocalDate periodStartDate, final Money principalToBeScheduled, final LoanScheduleParams loanScheduleParams) {
|
||||
final int loanTermInDays = 0;
|
||||
final int periodNumber = 1;
|
||||
final int instalmentNumber = 1;
|
||||
final Money totalCumulativePrincipal = Money.zero(currency);
|
||||
final Money totalCumulativeInterest = Money.zero(currency);
|
||||
final Money totalOutstandingInterestPaymentDueToGrace = Money.zero(currency);
|
||||
final LocalDate actualRepaymentDate = periodStartDate;
|
||||
final Money totalFeeChargesCharged = chargesDueAtTimeOfDisbursement;
|
||||
final Money totalPenaltyChargesCharged = Money.zero(currency);
|
||||
final Money totalRepaymentExpected = chargesDueAtTimeOfDisbursement;
|
||||
final Money reducePrincipal = Money.zero(currency);
|
||||
final Map<LocalDate, Money> principalPortionMap = new HashMap<>();
|
||||
final Map<LocalDate, Money> latePaymentMap = new HashMap<>();
|
||||
final Map<LocalDate, Money> compoundingMap = new TreeMap<>();
|
||||
final Map<LocalDate, Money> disburseDetailMap = new TreeMap<>();
|
||||
final Money outstandingBalance = principalToBeScheduled;
|
||||
final Money outstandingBalanceAsPerRest = principalToBeScheduled;
|
||||
final List<LoanRepaymentScheduleInstallment> installments = new ArrayList<>();
|
||||
final boolean partialUpdate = false;
|
||||
final Collection<RecalculationDetail> recalculationDetails = loanScheduleParams.recalculationDetails;
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = loanScheduleParams.loanRepaymentScheduleTransactionProcessor;
|
||||
final LocalDate scheduleTillDate = loanScheduleParams.scheduleTillDate;
|
||||
final boolean applyInterestRecalculation = loanScheduleParams.applyInterestRecalculation;
|
||||
final Money unCompoundedAmount = Money.zero(currency);
|
||||
return new LoanScheduleParams(periodNumber, instalmentNumber, loanTermInDays, periodStartDate, actualRepaymentDate,
|
||||
totalCumulativePrincipal, totalCumulativeInterest, totalFeeChargesCharged, totalPenaltyChargesCharged,
|
||||
totalRepaymentExpected, totalOutstandingInterestPaymentDueToGrace, reducePrincipal, principalPortionMap, latePaymentMap,
|
||||
compoundingMap, unCompoundedAmount, disburseDetailMap, principalToBeScheduled, outstandingBalance,
|
||||
outstandingBalanceAsPerRest, installments, recalculationDetails, loanRepaymentScheduleTransactionProcessor,
|
||||
scheduleTillDate, partialUpdate, currency, applyInterestRecalculation);
|
||||
}
|
||||
|
||||
public int getPeriodNumber() {
|
||||
return this.periodNumber;
|
||||
}
|
||||
|
||||
public void setPeriodNumber(int periodNumber) {
|
||||
this.periodNumber = periodNumber;
|
||||
}
|
||||
|
||||
public int getInstalmentNumber() {
|
||||
return this.instalmentNumber;
|
||||
}
|
||||
|
||||
public LocalDate getActualRepaymentDate() {
|
||||
return this.actualRepaymentDate;
|
||||
}
|
||||
|
||||
public void setActualRepaymentDate(LocalDate actualRepaymentDate) {
|
||||
this.actualRepaymentDate = actualRepaymentDate;
|
||||
}
|
||||
|
||||
public Money getTotalCumulativePrincipal() {
|
||||
return this.totalCumulativePrincipal;
|
||||
}
|
||||
|
||||
public void addTotalCumulativePrincipal(final Money totalCumulativePrincipal) {
|
||||
if (this.totalCumulativePrincipal != null) {
|
||||
this.totalCumulativePrincipal = this.totalCumulativePrincipal.plus(totalCumulativePrincipal);
|
||||
} else {
|
||||
this.totalCumulativePrincipal = totalCumulativePrincipal;
|
||||
}
|
||||
}
|
||||
|
||||
public Money getTotalCumulativeInterest() {
|
||||
return this.totalCumulativeInterest;
|
||||
}
|
||||
|
||||
public void addTotalCumulativeInterest(final Money totalCumulativeInterest) {
|
||||
if (this.totalCumulativeInterest != null) {
|
||||
this.totalCumulativeInterest = this.totalCumulativeInterest.plus(totalCumulativeInterest);
|
||||
} else {
|
||||
this.totalCumulativeInterest = totalCumulativeInterest;
|
||||
}
|
||||
}
|
||||
|
||||
public Money getTotalFeeChargesCharged() {
|
||||
return this.totalFeeChargesCharged;
|
||||
}
|
||||
|
||||
public void addTotalFeeChargesCharged(final Money totalFeeChargesCharged) {
|
||||
if (this.totalFeeChargesCharged != null) {
|
||||
this.totalFeeChargesCharged = this.totalFeeChargesCharged.plus(totalFeeChargesCharged);
|
||||
} else {
|
||||
this.totalFeeChargesCharged = totalFeeChargesCharged;
|
||||
}
|
||||
}
|
||||
|
||||
public Money getTotalPenaltyChargesCharged() {
|
||||
return this.totalPenaltyChargesCharged;
|
||||
}
|
||||
|
||||
public void addTotalPenaltyChargesCharged(final Money totalPenaltyChargesCharged) {
|
||||
if (this.totalPenaltyChargesCharged != null) {
|
||||
this.totalPenaltyChargesCharged = this.totalPenaltyChargesCharged.plus(totalPenaltyChargesCharged);
|
||||
} else {
|
||||
this.totalPenaltyChargesCharged = totalPenaltyChargesCharged;
|
||||
}
|
||||
}
|
||||
|
||||
public Money getTotalRepaymentExpected() {
|
||||
return this.totalRepaymentExpected;
|
||||
}
|
||||
|
||||
public void addTotalRepaymentExpected(final Money totalRepaymentExpected) {
|
||||
if (this.totalRepaymentExpected != null) {
|
||||
this.totalRepaymentExpected = this.totalRepaymentExpected.plus(totalRepaymentExpected);
|
||||
} else {
|
||||
this.totalRepaymentExpected = totalRepaymentExpected;
|
||||
}
|
||||
}
|
||||
|
||||
public Money getReducePrincipal() {
|
||||
return this.reducePrincipal;
|
||||
}
|
||||
|
||||
public void setReducePrincipal(Money reducePrincipal) {
|
||||
this.reducePrincipal = reducePrincipal;
|
||||
}
|
||||
|
||||
public Map<LocalDate, Money> getPrincipalPortionMap() {
|
||||
return this.principalPortionMap;
|
||||
}
|
||||
|
||||
public Map<LocalDate, Money> getLatePaymentMap() {
|
||||
return this.latePaymentMap;
|
||||
}
|
||||
|
||||
public Map<LocalDate, Money> getCompoundingMap() {
|
||||
return this.compoundingMap;
|
||||
}
|
||||
|
||||
public Map<LocalDate, Money> getDisburseDetailMap() {
|
||||
return this.disburseDetailMap;
|
||||
}
|
||||
|
||||
public Money getOutstandingBalance() {
|
||||
return this.outstandingBalance;
|
||||
}
|
||||
|
||||
public void setOutstandingBalance(Money outstandingBalance) {
|
||||
this.outstandingBalance = outstandingBalance;
|
||||
}
|
||||
|
||||
public Money getOutstandingBalanceAsPerRest() {
|
||||
return this.outstandingBalanceAsPerRest;
|
||||
}
|
||||
|
||||
public void setOutstandingBalanceAsPerRest(Money outstandingBalanceAsPerRest) {
|
||||
this.outstandingBalanceAsPerRest = outstandingBalanceAsPerRest;
|
||||
}
|
||||
|
||||
public List<LoanRepaymentScheduleInstallment> getInstallments() {
|
||||
return this.installments;
|
||||
}
|
||||
|
||||
public Collection<RecalculationDetail> getRecalculationDetails() {
|
||||
return this.recalculationDetails;
|
||||
}
|
||||
|
||||
public LoanRepaymentScheduleTransactionProcessor getLoanRepaymentScheduleTransactionProcessor() {
|
||||
return this.loanRepaymentScheduleTransactionProcessor;
|
||||
}
|
||||
|
||||
public LocalDate getScheduleTillDate() {
|
||||
return this.scheduleTillDate;
|
||||
}
|
||||
|
||||
public boolean isPartialUpdate() {
|
||||
return this.partialUpdate;
|
||||
}
|
||||
|
||||
public LocalDate getPeriodStartDate() {
|
||||
return this.periodStartDate;
|
||||
}
|
||||
|
||||
public void setPeriodStartDate(LocalDate periodStartDate) {
|
||||
this.periodStartDate = periodStartDate;
|
||||
}
|
||||
|
||||
public Money getPrincipalToBeScheduled() {
|
||||
return this.principalToBeScheduled;
|
||||
}
|
||||
|
||||
public void setPrincipalToBeScheduled(Money principalToBeScheduled) {
|
||||
this.principalToBeScheduled = principalToBeScheduled;
|
||||
}
|
||||
|
||||
public void incrementPeriodNumber() {
|
||||
this.periodNumber++;
|
||||
}
|
||||
|
||||
public void incrementInstalmentNumber() {
|
||||
this.instalmentNumber++;
|
||||
}
|
||||
|
||||
public void addReducePrincipal(Money reducePrincipal) {
|
||||
if (this.reducePrincipal != null) {
|
||||
this.reducePrincipal = this.reducePrincipal.plus(reducePrincipal);
|
||||
} else {
|
||||
this.reducePrincipal = reducePrincipal;
|
||||
}
|
||||
}
|
||||
|
||||
public void reduceReducePrincipal(Money reducePrincipal) {
|
||||
if (this.reducePrincipal != null) {
|
||||
this.reducePrincipal = this.reducePrincipal.minus(reducePrincipal);
|
||||
}
|
||||
}
|
||||
|
||||
public void addPrincipalToBeScheduled(Money principalToBeScheduled) {
|
||||
if (this.principalToBeScheduled != null) {
|
||||
this.principalToBeScheduled = this.principalToBeScheduled.plus(principalToBeScheduled);
|
||||
} else {
|
||||
this.principalToBeScheduled = principalToBeScheduled;
|
||||
}
|
||||
}
|
||||
|
||||
public void addOutstandingBalance(Money outstandingBalance) {
|
||||
if (this.outstandingBalance != null) {
|
||||
this.outstandingBalance = this.outstandingBalance.plus(outstandingBalance);
|
||||
} else {
|
||||
this.outstandingBalance = outstandingBalance;
|
||||
}
|
||||
}
|
||||
|
||||
public void reduceOutstandingBalance(Money outstandingBalance) {
|
||||
if (this.outstandingBalance != null) {
|
||||
this.outstandingBalance = this.outstandingBalance.minus(outstandingBalance);
|
||||
}
|
||||
}
|
||||
|
||||
public void addOutstandingBalanceAsPerRest(Money outstandingBalanceAsPerRest) {
|
||||
if (this.outstandingBalanceAsPerRest != null) {
|
||||
this.outstandingBalanceAsPerRest = this.outstandingBalanceAsPerRest.plus(outstandingBalanceAsPerRest);
|
||||
} else {
|
||||
this.outstandingBalanceAsPerRest = outstandingBalanceAsPerRest;
|
||||
}
|
||||
}
|
||||
|
||||
public void reduceOutstandingBalanceAsPerRest(Money outstandingBalanceAsPerRest) {
|
||||
if (this.outstandingBalanceAsPerRest != null) {
|
||||
this.outstandingBalanceAsPerRest = this.outstandingBalanceAsPerRest.minus(outstandingBalanceAsPerRest);
|
||||
}
|
||||
}
|
||||
|
||||
public int getLoanTermInDays() {
|
||||
return this.loanTermInDays;
|
||||
}
|
||||
|
||||
public void addLoanTermInDays(int loanTermInDays) {
|
||||
this.loanTermInDays += loanTermInDays;
|
||||
}
|
||||
|
||||
public Money getTotalOutstandingInterestPaymentDueToGrace() {
|
||||
return this.totalOutstandingInterestPaymentDueToGrace;
|
||||
}
|
||||
|
||||
public void setTotalOutstandingInterestPaymentDueToGrace(Money totalOutstandingInterestPaymentDueToGrace) {
|
||||
this.totalOutstandingInterestPaymentDueToGrace = totalOutstandingInterestPaymentDueToGrace;
|
||||
}
|
||||
|
||||
public Map<LocalDate, Map<LocalDate, Money>> getCompoundingDateVariations() {
|
||||
return this.compoundingDateVariations;
|
||||
}
|
||||
|
||||
public MonetaryCurrency getCurrency() {
|
||||
return this.currency;
|
||||
}
|
||||
|
||||
public boolean applyInterestRecalculation() {
|
||||
return this.applyInterestRecalculation;
|
||||
}
|
||||
|
||||
public Money getUnCompoundedAmount() {
|
||||
return this.unCompoundedAmount;
|
||||
}
|
||||
|
||||
public void setUnCompoundedAmount(Money unCompoundedAmount) {
|
||||
this.unCompoundedAmount = unCompoundedAmount;
|
||||
}
|
||||
|
||||
public void addUnCompoundedAmount(Money unCompoundedAmount) {
|
||||
if (this.unCompoundedAmount != null) {
|
||||
this.unCompoundedAmount = this.unCompoundedAmount.plus(unCompoundedAmount);
|
||||
} else {
|
||||
this.unCompoundedAmount = unCompoundedAmount;
|
||||
}
|
||||
}
|
||||
|
||||
public void minusUnCompoundedAmount(Money unCompoundedAmount) {
|
||||
if (this.unCompoundedAmount != null) {
|
||||
this.unCompoundedAmount = this.unCompoundedAmount.minus(unCompoundedAmount);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isFirstPeriod() {
|
||||
return 1 == instalmentNumber;
|
||||
}
|
||||
}
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
|
||||
|
||||
/**
|
||||
* Domain representation of a Loan Schedule Disbursement Period (not used for persistence)
|
||||
*/
|
||||
public final class LoanScheduleModelDisbursementPeriod implements LoanScheduleModelPeriod {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final Integer periodNumber;
|
||||
private final LocalDate disbursementDate;
|
||||
private final Money principalDisbursed;
|
||||
private final BigDecimal chargesDueAtTimeOfDisbursement;
|
||||
private boolean isEMIFixedSpecificToInstallment = false;
|
||||
|
||||
public static LoanScheduleModelDisbursementPeriod disbursement(final LoanApplicationTerms loanApplicationTerms,
|
||||
final BigDecimal chargesDueAtTimeOfDisbursement) {
|
||||
|
||||
return new LoanScheduleModelDisbursementPeriod(null, loanApplicationTerms.getExpectedDisbursementDate(),
|
||||
loanApplicationTerms.getPrincipal(), chargesDueAtTimeOfDisbursement);
|
||||
}
|
||||
|
||||
public static LoanScheduleModelDisbursementPeriod disbursement(final LocalDate disbursementDate, final Money principalDisbursed,
|
||||
final BigDecimal chargesDueAtTimeOfDisbursement) {
|
||||
return new LoanScheduleModelDisbursementPeriod(null, disbursementDate, principalDisbursed, chargesDueAtTimeOfDisbursement);
|
||||
}
|
||||
|
||||
private LoanScheduleModelDisbursementPeriod(final Integer periodNumber, final LocalDate disbursementDate,
|
||||
final Money principalDisbursed, final BigDecimal chargesDueAtTimeOfDisbursement) {
|
||||
this.periodNumber = periodNumber;
|
||||
this.disbursementDate = disbursementDate;
|
||||
this.principalDisbursed = principalDisbursed;
|
||||
this.chargesDueAtTimeOfDisbursement = chargesDueAtTimeOfDisbursement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoanSchedulePeriodData toData() {
|
||||
return LoanSchedulePeriodData.disbursementOnlyPeriod(this.disbursementDate, this.principalDisbursed.getAmount(),
|
||||
this.chargesDueAtTimeOfDisbursement, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRepaymentPeriod() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDownPaymentPeriod() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer periodNumber() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDate periodFromDate() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDate periodDueDate() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal principalDue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal interestDue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal feeChargesDue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal penaltyChargesDue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLoanCharges(@SuppressWarnings("unused") BigDecimal feeCharge, @SuppressWarnings("unused") BigDecimal penaltyCharge) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRecalculatedInterestComponent() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPrincipalAmount(@SuppressWarnings("unused") Money principalDue) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInterestAmount(@SuppressWarnings("unused") Money principalDue) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<LoanInterestRecalcualtionAdditionalDetails> getLoanCompoundingDetails() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEMIFixedSpecificToInstallmentTrue() {
|
||||
this.isEMIFixedSpecificToInstallment = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEMIFixedSpecificToInstallment() {
|
||||
return isEMIFixedSpecificToInstallment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal rescheduleInterestPortion() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRescheduleInterestPortion(BigDecimal rescheduleInterestPortion) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
+193
@@ -0,0 +1,193 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import lombok.Getter;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
|
||||
|
||||
/**
|
||||
* Domain representation of a Loan Schedule Repayment Period (not used for persistence)
|
||||
*/
|
||||
@Getter
|
||||
public final class LoanScheduleModelRepaymentPeriod implements LoanScheduleModelPeriod {
|
||||
|
||||
private final int periodNumber;
|
||||
private final LocalDate fromDate;
|
||||
private final LocalDate dueDate;
|
||||
private Money principalDue;
|
||||
private final Money outstandingLoanBalance;
|
||||
private Money interestDue;
|
||||
private Money feeChargesDue;
|
||||
private Money penaltyChargesDue;
|
||||
private Money totalDue;
|
||||
private final boolean recalculatedInterestComponent;
|
||||
private final Set<LoanInterestRecalcualtionAdditionalDetails> loanCompoundingDetails = new HashSet<>();
|
||||
private boolean isEMIFixedSpecificToInstallment = false;
|
||||
BigDecimal rescheduleInterestPortion;
|
||||
|
||||
public static LoanScheduleModelRepaymentPeriod repayment(final int periodNumber, final LocalDate startDate,
|
||||
final LocalDate scheduledDueDate, final Money principalDue, final Money outstandingLoanBalance, final Money interestDue,
|
||||
final Money feeChargesDue, final Money penaltyChargesDue, final Money totalDue, boolean recalculatedInterestComponent) {
|
||||
|
||||
return new LoanScheduleModelRepaymentPeriod(periodNumber, startDate, scheduledDueDate, principalDue, outstandingLoanBalance,
|
||||
interestDue, feeChargesDue, penaltyChargesDue, totalDue, recalculatedInterestComponent);
|
||||
}
|
||||
|
||||
public LoanScheduleModelRepaymentPeriod(final int periodNumber, final LocalDate fromDate, final LocalDate dueDate,
|
||||
final Money principalDue, final Money outstandingLoanBalance, final Money interestDue, final Money feeChargesDue,
|
||||
final Money penaltyChargesDue, final Money totalDue, final boolean recalculatedInterestComponent) {
|
||||
this.periodNumber = periodNumber;
|
||||
this.fromDate = fromDate;
|
||||
this.dueDate = dueDate;
|
||||
this.principalDue = principalDue;
|
||||
this.outstandingLoanBalance = outstandingLoanBalance;
|
||||
this.interestDue = interestDue;
|
||||
this.feeChargesDue = feeChargesDue;
|
||||
this.penaltyChargesDue = penaltyChargesDue;
|
||||
this.totalDue = totalDue;
|
||||
this.recalculatedInterestComponent = recalculatedInterestComponent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoanSchedulePeriodData toData() {
|
||||
return LoanSchedulePeriodData.repaymentOnlyPeriod(this.periodNumber, this.fromDate, this.dueDate, this.principalDue.getAmount(),
|
||||
this.outstandingLoanBalance.getAmount(), this.interestDue.getAmount(), this.feeChargesDue.getAmount(),
|
||||
this.penaltyChargesDue.getAmount(), this.totalDue.getAmount(), this.principalDue.plus(this.interestDue).getAmount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRepaymentPeriod() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDownPaymentPeriod() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer periodNumber() {
|
||||
return this.periodNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDate periodFromDate() {
|
||||
return this.fromDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDate periodDueDate() {
|
||||
return this.dueDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal principalDue() {
|
||||
BigDecimal value = null;
|
||||
if (this.principalDue != null) {
|
||||
value = this.principalDue.getAmount();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal interestDue() {
|
||||
BigDecimal value = null;
|
||||
if (this.interestDue != null) {
|
||||
value = this.interestDue.getAmount();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal feeChargesDue() {
|
||||
BigDecimal value = null;
|
||||
if (this.feeChargesDue != null) {
|
||||
value = this.feeChargesDue.getAmount();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal penaltyChargesDue() {
|
||||
BigDecimal value = null;
|
||||
if (this.penaltyChargesDue != null) {
|
||||
value = this.penaltyChargesDue.getAmount();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLoanCharges(BigDecimal feeCharge, BigDecimal penaltyCharge) {
|
||||
this.feeChargesDue = this.feeChargesDue.plus(feeCharge);
|
||||
this.penaltyChargesDue = this.penaltyChargesDue.plus(penaltyCharge);
|
||||
this.totalDue = this.totalDue.plus(feeCharge).plus(penaltyCharge);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPrincipalAmount(final Money principalDue) {
|
||||
this.principalDue = this.principalDue.plus(principalDue);
|
||||
this.totalDue = this.totalDue.plus(principalDue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRecalculatedInterestComponent() {
|
||||
return this.recalculatedInterestComponent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInterestAmount(Money interestDue) {
|
||||
this.interestDue = this.interestDue.plus(interestDue);
|
||||
this.totalDue = this.totalDue.plus(interestDue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<LoanInterestRecalcualtionAdditionalDetails> getLoanCompoundingDetails() {
|
||||
return this.loanCompoundingDetails;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEMIFixedSpecificToInstallment() {
|
||||
return this.isEMIFixedSpecificToInstallment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEMIFixedSpecificToInstallmentTrue() {
|
||||
this.isEMIFixedSpecificToInstallment = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRescheduleInterestPortion(BigDecimal rescheduleInterestPortion) {
|
||||
this.rescheduleInterestPortion = rescheduleInterestPortion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal rescheduleInterestPortion() {
|
||||
return this.rescheduleInterestPortion;
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
|
||||
|
||||
public record LoanTermVariationParams(boolean skipPeriod, boolean recalculateAmounts, LocalDate scheduledDueDate,
|
||||
List<LoanTermVariationsData> variationsData) {
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||
|
||||
public class RecalculationDetail {
|
||||
|
||||
private LocalDate transactionDate;
|
||||
private boolean isProcessed;
|
||||
private LoanTransaction transaction;
|
||||
|
||||
public RecalculationDetail(final LocalDate transactionDate, final LoanTransaction transaction) {
|
||||
this.transactionDate = transactionDate;
|
||||
this.transaction = transaction;
|
||||
}
|
||||
|
||||
public LocalDate getTransactionDate() {
|
||||
return this.transactionDate;
|
||||
}
|
||||
|
||||
public LoanTransaction getTransaction() {
|
||||
return this.transaction;
|
||||
}
|
||||
|
||||
public boolean isProcessed() {
|
||||
return this.isProcessed;
|
||||
}
|
||||
|
||||
public void setProcessed(boolean isProcessed) {
|
||||
this.isProcessed = isProcessed;
|
||||
}
|
||||
}
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
|
||||
public class ScheduleCurrentPeriodParams {
|
||||
|
||||
Money earlyPaidAmount;
|
||||
LoanScheduleModelPeriod lastInstallment;
|
||||
boolean skipCurrentLoop;
|
||||
Money interestForThisPeriod;
|
||||
Money principalForThisPeriod;
|
||||
Money feeChargesForInstallment;
|
||||
Money penaltyChargesForInstallment;
|
||||
// for adjusting outstandingBalances
|
||||
Money reducedBalance;
|
||||
boolean isEmiAmountChanged;
|
||||
BigDecimal interestCalculationGraceOnRepaymentPeriodFraction;
|
||||
|
||||
ScheduleCurrentPeriodParams(final MonetaryCurrency currency) {
|
||||
this(currency, BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
ScheduleCurrentPeriodParams(final MonetaryCurrency currency, BigDecimal interestCalculationGraceOnRepaymentPeriodFraction) {
|
||||
this.earlyPaidAmount = Money.zero(currency);
|
||||
this.lastInstallment = null;
|
||||
this.skipCurrentLoop = false;
|
||||
this.interestForThisPeriod = Money.zero(currency);
|
||||
this.principalForThisPeriod = Money.zero(currency);
|
||||
this.reducedBalance = Money.zero(currency);
|
||||
this.feeChargesForInstallment = Money.zero(currency);
|
||||
this.penaltyChargesForInstallment = Money.zero(currency);
|
||||
this.isEmiAmountChanged = false;
|
||||
this.interestCalculationGraceOnRepaymentPeriodFraction = interestCalculationGraceOnRepaymentPeriodFraction;
|
||||
}
|
||||
|
||||
public Money getEarlyPaidAmount() {
|
||||
return this.earlyPaidAmount;
|
||||
}
|
||||
|
||||
public void plusEarlyPaidAmount(Money earlyPaidAmount) {
|
||||
this.earlyPaidAmount = this.earlyPaidAmount.plus(earlyPaidAmount);
|
||||
}
|
||||
|
||||
public void minusEarlyPaidAmount(Money earlyPaidAmount) {
|
||||
this.earlyPaidAmount = this.earlyPaidAmount.minus(earlyPaidAmount);
|
||||
}
|
||||
|
||||
public LoanScheduleModelPeriod getLastInstallment() {
|
||||
return this.lastInstallment;
|
||||
}
|
||||
|
||||
public void setLastInstallment(LoanScheduleModelPeriod lastInstallment) {
|
||||
this.lastInstallment = lastInstallment;
|
||||
}
|
||||
|
||||
public boolean isSkipCurrentLoop() {
|
||||
return this.skipCurrentLoop;
|
||||
}
|
||||
|
||||
public void setSkipCurrentLoop(boolean skipCurrentLoop) {
|
||||
this.skipCurrentLoop = skipCurrentLoop;
|
||||
}
|
||||
|
||||
public Money getInterestForThisPeriod() {
|
||||
return this.interestForThisPeriod;
|
||||
}
|
||||
|
||||
public void setInterestForThisPeriod(Money interestForThisPeriod) {
|
||||
this.interestForThisPeriod = interestForThisPeriod;
|
||||
}
|
||||
|
||||
public void minusInterestForThisPeriod(Money interestForThisPeriod) {
|
||||
this.interestForThisPeriod = this.interestForThisPeriod.minus(interestForThisPeriod);
|
||||
}
|
||||
|
||||
public Money getPrincipalForThisPeriod() {
|
||||
return this.principalForThisPeriod;
|
||||
}
|
||||
|
||||
public void setPrincipalForThisPeriod(Money principalForThisPeriod) {
|
||||
this.principalForThisPeriod = principalForThisPeriod;
|
||||
}
|
||||
|
||||
public void plusPrincipalForThisPeriod(Money principalForThisPeriod) {
|
||||
this.principalForThisPeriod = this.principalForThisPeriod.plus(principalForThisPeriod);
|
||||
}
|
||||
|
||||
public void minusPrincipalForThisPeriod(Money principalForThisPeriod) {
|
||||
this.principalForThisPeriod = this.principalForThisPeriod.minus(principalForThisPeriod);
|
||||
}
|
||||
|
||||
public Money getReducedBalance() {
|
||||
return this.reducedBalance;
|
||||
}
|
||||
|
||||
public void setReducedBalance(Money reducedBalance) {
|
||||
this.reducedBalance = reducedBalance;
|
||||
}
|
||||
|
||||
public Money getFeeChargesForInstallment() {
|
||||
return this.feeChargesForInstallment;
|
||||
}
|
||||
|
||||
public void setFeeChargesForInstallment(Money feeChargesForInstallment) {
|
||||
this.feeChargesForInstallment = feeChargesForInstallment;
|
||||
}
|
||||
|
||||
public void minusFeeChargesForInstallment(Money feeChargesForInstallment) {
|
||||
this.feeChargesForInstallment = this.feeChargesForInstallment.minus(feeChargesForInstallment);
|
||||
}
|
||||
|
||||
public Money getPenaltyChargesForInstallment() {
|
||||
return this.penaltyChargesForInstallment;
|
||||
}
|
||||
|
||||
public void setPenaltyChargesForInstallment(Money penaltyChargesForInstallment) {
|
||||
this.penaltyChargesForInstallment = penaltyChargesForInstallment;
|
||||
}
|
||||
|
||||
public void minusPenaltyChargesForInstallment(Money penaltyChargesForInstallment) {
|
||||
this.penaltyChargesForInstallment = this.penaltyChargesForInstallment.minus(penaltyChargesForInstallment);
|
||||
}
|
||||
|
||||
public Money fetchTotalAmountForPeriod() {
|
||||
return this.principalForThisPeriod.plus(interestForThisPeriod).plus(feeChargesForInstallment).plus(penaltyChargesForInstallment);
|
||||
}
|
||||
|
||||
public boolean isEmiAmountChanged() {
|
||||
return this.isEmiAmountChanged;
|
||||
}
|
||||
|
||||
public void setEmiAmountChanged(boolean isEmiAmountChanged) {
|
||||
this.isEmiAmountChanged = isEmiAmountChanged;
|
||||
}
|
||||
|
||||
public BigDecimal getInterestCalculationGraceOnRepaymentPeriodFraction() {
|
||||
return this.interestCalculationGraceOnRepaymentPeriodFraction;
|
||||
}
|
||||
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import org.apache.fineract.organisation.workingdays.data.AdjustedDateDetailsDTO;
|
||||
import org.apache.fineract.portfolio.calendar.domain.Calendar;
|
||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
|
||||
|
||||
public interface ScheduledDateGenerator {
|
||||
|
||||
LocalDate getLastRepaymentDate(LoanApplicationTerms loanApplicationTerms, HolidayDetailDTO holidayDetailDTO);
|
||||
|
||||
LocalDate idealDisbursementDateBasedOnFirstRepaymentDate(PeriodFrequencyType repaymentPeriodFrequencyType, int repaidEvery,
|
||||
LocalDate firstRepaymentDate, Calendar loanCalendar, HolidayDetailDTO holidayDetailDTO,
|
||||
LoanApplicationTerms loanApplicationTerms);
|
||||
|
||||
LocalDate generateNextRepaymentDate(LocalDate lastRepaymentDate, LoanApplicationTerms loanApplicationTerms, boolean isFirstRepayment);
|
||||
|
||||
LocalDate generateNextRepaymentDate(LocalDate lastRepaymentDate, LoanApplicationTerms loanApplicationTerms, boolean isFirstRepayment,
|
||||
Integer periodNumber);
|
||||
|
||||
AdjustedDateDetailsDTO adjustRepaymentDate(LocalDate dueRepaymentPeriodDate, LoanApplicationTerms loanApplicationTerms,
|
||||
HolidayDetailDTO holidayDetailDTO);
|
||||
|
||||
LocalDate getRepaymentPeriodDate(PeriodFrequencyType frequency, int repaidEvery, LocalDate startDate);
|
||||
|
||||
Boolean isDateFallsInSchedule(PeriodFrequencyType frequency, int repaidEvery, LocalDate startDate, LocalDate date);
|
||||
|
||||
LocalDate generateNextScheduleDateStartingFromDisburseDate(LocalDate lastRepaymentDate, LoanApplicationTerms loanApplicationTerms,
|
||||
HolidayDetailDTO holidayDetailDTO);
|
||||
|
||||
LocalDate generateNextScheduleDateStartingFromDisburseDateOrRescheduleDate(LocalDate lastRepaymentDate,
|
||||
LoanApplicationTerms loanApplicationTerms, HolidayDetailDTO holidayDetailDTO);
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.loanschedule.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
public class MultiDisbursementOutstandingAmoutException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public MultiDisbursementOutstandingAmoutException(final String defaultUserMessage, final Object... defaultUserMessageArgs) {
|
||||
super("error.msg.loanschedule.exceeding.max.outstanding.balance", defaultUserMessage, defaultUserMessageArgs);
|
||||
}
|
||||
|
||||
}
|
||||
-122
@@ -1,122 +0,0 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanproduct.domain;
|
||||
|
||||
import com.google.common.base.Enums;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
public class AdvancedPaymentAllocationsJsonParser {
|
||||
|
||||
public final AdvancedPaymentAllocationsValidator advancedPaymentAllocationsValidator;
|
||||
|
||||
public List<LoanProductPaymentAllocationRule> assembleLoanProductPaymentAllocationRules(final JsonCommand command,
|
||||
String loanTransactionProcessingStrategyCode) {
|
||||
JsonArray paymentAllocations = command.arrayOfParameterNamed("paymentAllocation");
|
||||
List<LoanProductPaymentAllocationRule> productPaymentAllocationRules = null;
|
||||
if (paymentAllocations != null) {
|
||||
productPaymentAllocationRules = paymentAllocations.asList().stream().map(json -> {
|
||||
Map<String, JsonElement> map = json.getAsJsonObject().asMap();
|
||||
LoanProductPaymentAllocationRule loanProductPaymentAllocationRule = new LoanProductPaymentAllocationRule();
|
||||
populatePaymentAllocationRules(map, loanProductPaymentAllocationRule);
|
||||
populateFutureInstallment(map, loanProductPaymentAllocationRule);
|
||||
populateTransactionType(map, loanProductPaymentAllocationRule);
|
||||
return loanProductPaymentAllocationRule;
|
||||
}).toList();
|
||||
}
|
||||
advancedPaymentAllocationsValidator.validate(productPaymentAllocationRules, loanTransactionProcessingStrategyCode);
|
||||
return productPaymentAllocationRules;
|
||||
}
|
||||
|
||||
private void populatePaymentAllocationRules(Map<String, JsonElement> map,
|
||||
LoanProductPaymentAllocationRule loanProductPaymentAllocationRule) {
|
||||
JsonArray paymentAllocationOrder = asJsonArrayOrNull(map.get("paymentAllocationOrder"));
|
||||
if (paymentAllocationOrder != null) {
|
||||
loanProductPaymentAllocationRule.setAllocationTypes(getPaymentAllocationTypes(paymentAllocationOrder));
|
||||
}
|
||||
}
|
||||
|
||||
private void populateFutureInstallment(Map<String, JsonElement> map,
|
||||
LoanProductPaymentAllocationRule loanProductPaymentAllocationRule) {
|
||||
String futureInstallmentAllocationRule = asStringOrNull(map.get("futureInstallmentAllocationRule"));
|
||||
if (futureInstallmentAllocationRule != null) {
|
||||
loanProductPaymentAllocationRule.setFutureInstallmentAllocationRule(
|
||||
Enums.getIfPresent(FutureInstallmentAllocationRule.class, futureInstallmentAllocationRule).orNull());
|
||||
}
|
||||
}
|
||||
|
||||
private void populateTransactionType(Map<String, JsonElement> map, LoanProductPaymentAllocationRule loanProductPaymentAllocationRule) {
|
||||
String transactionType = asStringOrNull(map.get("transactionType"));
|
||||
if (transactionType != null) {
|
||||
loanProductPaymentAllocationRule
|
||||
.setTransactionType(Enums.getIfPresent(PaymentAllocationTransactionType.class, transactionType).orNull());
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<PaymentAllocationType> getPaymentAllocationTypes(JsonArray paymentAllocationOrder) {
|
||||
if (paymentAllocationOrder != null) {
|
||||
List<Pair<Integer, PaymentAllocationType>> parsedListWithOrder = paymentAllocationOrder.asList().stream().map(json -> {
|
||||
Map<String, JsonElement> map = json.getAsJsonObject().asMap();
|
||||
PaymentAllocationType paymentAllocationType = null;
|
||||
String paymentAllocationRule = asStringOrNull(map.get("paymentAllocationRule"));
|
||||
if (paymentAllocationRule != null) {
|
||||
paymentAllocationType = Enums.getIfPresent(PaymentAllocationType.class, paymentAllocationRule).orNull();
|
||||
}
|
||||
return Pair.of(asIntegerOrNull(map.get("order")), paymentAllocationType);
|
||||
}).sorted(Comparator.comparing(Pair::getLeft)).toList();
|
||||
advancedPaymentAllocationsValidator.validatePairOfOrderAndPaymentAllocationType(parsedListWithOrder);
|
||||
return parsedListWithOrder.stream().map(Pair::getRight).toList();
|
||||
} else {
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
|
||||
private Integer asIntegerOrNull(JsonElement element) {
|
||||
if (!element.isJsonNull()) {
|
||||
return element.getAsInt();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String asStringOrNull(JsonElement element) {
|
||||
if (!element.isJsonNull()) {
|
||||
return element.getAsString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private JsonArray asJsonArrayOrNull(JsonElement element) {
|
||||
if (!element.isJsonNull()) {
|
||||
return element.getAsJsonArray();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
-139
@@ -1,139 +0,0 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanproduct.domain;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.IntStream;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class AdvancedPaymentAllocationsValidator {
|
||||
|
||||
public static final String ADVANCED_PAYMENT_ALLOCATION_STRATEGY = "advanced-payment-allocation-strategy";
|
||||
|
||||
public void validate(List<LoanProductPaymentAllocationRule> rules, String code) {
|
||||
if (isAdvancedPaymentStrategy(code)) {
|
||||
if (!hasLoanProductPaymentAllocationRule(rules) || !hasAtLeastOneDefaultPaymentAllocation(rules)) {
|
||||
raiseValidationError("advanced-payment-strategy-without-default-payment-allocation",
|
||||
"Advanced-payment-allocation-strategy was selected but no DEFAULT payment allocation was provided");
|
||||
}
|
||||
|
||||
if (hasDuplicateTransactionTypes(rules)) {
|
||||
raiseValidationError("advanced-payment-strategy-with-duplicate-payment-allocation",
|
||||
"The same transaction type must be provided only once");
|
||||
}
|
||||
|
||||
for (LoanProductPaymentAllocationRule rule : rules) {
|
||||
validateAllocationRule(rule);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (hasLoanProductPaymentAllocationRule(rules)) {
|
||||
raiseValidationError("payment_allocation.must.not.be.provided.when.allocation.strategy.is.not.advanced-payment-strategy",
|
||||
"In case '" + code + "' payment strategy, payment_allocation must not be provided");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void validatePairOfOrderAndPaymentAllocationType(List<Pair<Integer, PaymentAllocationType>> rules) {
|
||||
if (rules.size() != 12) {
|
||||
raiseValidationError("advanced-payment-strategy.each_payment_allocation_order.must.contain.12.entries",
|
||||
"Each provided payment allocation must contain exactly 12 allocation rules, but " + rules.size() + " were provided");
|
||||
}
|
||||
|
||||
List<PaymentAllocationType> deduped = rules.stream().map(Pair::getRight).distinct().toList();
|
||||
if (deduped.size() != 12) {
|
||||
raiseValidationError("advanced-payment-strategy.must.not.have.duplicate.payment.allocation.rule",
|
||||
"The list of provided payment allocation rules must not contain any duplicates");
|
||||
}
|
||||
|
||||
if (!Arrays.equals(IntStream.rangeClosed(1, 12).boxed().toArray(), rules.stream().map(Pair::getLeft).toArray())) {
|
||||
raiseValidationError("advanced-payment-strategy.invalid.order", "The provided orders must be between 1 and 12");
|
||||
}
|
||||
}
|
||||
|
||||
public void checkGroupingOfAllocationRules(List<LoanProductPaymentAllocationRule> loanProductPaymentAllocationRules) {
|
||||
loanProductPaymentAllocationRules.forEach(paymentAllocationRule -> {
|
||||
AtomicInteger pastDueRuleInteger = new AtomicInteger();
|
||||
AtomicInteger dueRuleInteger = new AtomicInteger();
|
||||
AtomicInteger inAdvanceRuleInteger = new AtomicInteger();
|
||||
paymentAllocationRule.getAllocationTypes().forEach(paymentAllocationType -> {
|
||||
validateAllocationType(paymentAllocationType, pastDueRuleInteger, dueRuleInteger, inAdvanceRuleInteger);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void validateAllocationType(PaymentAllocationType paymentAllocationType, AtomicInteger pastDueRuleInteger,
|
||||
AtomicInteger dueRuleInteger, AtomicInteger inAdvanceRuleInteger) {
|
||||
switch (paymentAllocationType.getDueType()) {
|
||||
case PAST_DUE -> validateDueType(pastDueRuleInteger, dueRuleInteger, inAdvanceRuleInteger);
|
||||
case DUE -> validateDueType(dueRuleInteger, pastDueRuleInteger, inAdvanceRuleInteger);
|
||||
case IN_ADVANCE -> validateDueType(inAdvanceRuleInteger, pastDueRuleInteger, dueRuleInteger);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateDueType(AtomicInteger currentRuleInteger, AtomicInteger otherRule1Integer, AtomicInteger otherRule2Integer) {
|
||||
currentRuleInteger.incrementAndGet();
|
||||
if ((otherRule1Integer.get() > 0 && otherRule1Integer.get() < 4) || (otherRule2Integer.get() > 0 && otherRule2Integer.get() < 4)) {
|
||||
raiseValidationError("mixed.due.type.allocation.rules.are.not.supported.with.horizontal.installment.processing",
|
||||
"Horizontal repayment schedule processing is not supporting mixed due type allocation rules!");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasDuplicateTransactionTypes(List<LoanProductPaymentAllocationRule> rules) {
|
||||
return rules != null
|
||||
&& rules.stream().map(LoanProductPaymentAllocationRule::getTransactionType).distinct().toList().size() != rules.size();
|
||||
}
|
||||
|
||||
private void validateAllocationRule(LoanProductPaymentAllocationRule rule) {
|
||||
if (rule.getTransactionType() == null) {
|
||||
raiseValidationError("advanced-payment-strategy.with.not.valid.transaction.type",
|
||||
"Payment allocation was provided with a not valid transaction type");
|
||||
}
|
||||
if (rule.getFutureInstallmentAllocationRule() == null) {
|
||||
raiseValidationError("advanced-payment-strategy.with.not.valid.future.installment.allocation.rule",
|
||||
"Payment allocation was provided without a valid future installment allocation rule");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAdvancedPaymentStrategy(String code) {
|
||||
return ADVANCED_PAYMENT_ALLOCATION_STRATEGY.equals(code);
|
||||
}
|
||||
|
||||
private boolean hasAtLeastOneDefaultPaymentAllocation(List<LoanProductPaymentAllocationRule> rules) {
|
||||
return rules != null && rules.stream() //
|
||||
.filter(r -> PaymentAllocationTransactionType.DEFAULT.equals(r.getTransactionType())) //
|
||||
.toList() //
|
||||
.size() > 0;
|
||||
}
|
||||
|
||||
private boolean hasLoanProductPaymentAllocationRule(List<LoanProductPaymentAllocationRule> rules) {
|
||||
return rules != null && rules.size() > 0;
|
||||
}
|
||||
|
||||
private void raiseValidationError(String globalisationMessageCode, String msg) {
|
||||
throw new PlatformApiDataValidationException(List.of(ApiParameterError.generalError(globalisationMessageCode, msg)));
|
||||
}
|
||||
|
||||
}
|
||||
+1
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanproduct.domain;
|
||||
|
||||
// TODO FINERACT-1932-Fineract modularization: Move to fineract-progressive-loan module after refactor of Loan and LoanProduct classes
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
|
||||
-110
@@ -1,110 +0,0 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanproduct.domain;
|
||||
|
||||
import com.google.common.base.Enums;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
public class CreditAllocationsJsonParser {
|
||||
|
||||
public final CreditAllocationsValidator creditAllocationsValidator;
|
||||
|
||||
public List<LoanProductCreditAllocationRule> assembleLoanProductCreditAllocationRules(final JsonCommand command,
|
||||
String loanTransactionProcessingStrategyCode) {
|
||||
JsonArray creditAllocation = command.arrayOfParameterNamed("creditAllocation");
|
||||
List<LoanProductCreditAllocationRule> productCreditAllocationRules = null;
|
||||
if (creditAllocation != null) {
|
||||
productCreditAllocationRules = creditAllocation.asList().stream().map(json -> {
|
||||
Map<String, JsonElement> map = json.getAsJsonObject().asMap();
|
||||
LoanProductCreditAllocationRule creditAllocationRule = new LoanProductCreditAllocationRule();
|
||||
populateCreditAllocationRules(map, creditAllocationRule);
|
||||
populateTransactionType(map, creditAllocationRule);
|
||||
return creditAllocationRule;
|
||||
}).toList();
|
||||
}
|
||||
creditAllocationsValidator.validate(productCreditAllocationRules, loanTransactionProcessingStrategyCode);
|
||||
return productCreditAllocationRules;
|
||||
}
|
||||
|
||||
private void populateCreditAllocationRules(Map<String, JsonElement> map, LoanProductCreditAllocationRule creditAllocationRule) {
|
||||
JsonArray creditAllocationOrder = asJsonArrayOrNull(map.get("creditAllocationOrder"));
|
||||
if (creditAllocationOrder != null) {
|
||||
creditAllocationRule.setAllocationTypes(getAllocationTypes(creditAllocationOrder));
|
||||
}
|
||||
}
|
||||
|
||||
private void populateTransactionType(Map<String, JsonElement> map, LoanProductCreditAllocationRule creditAllocationRule) {
|
||||
String transactionType = asStringOrNull(map.get("transactionType"));
|
||||
if (transactionType != null) {
|
||||
creditAllocationRule.setTransactionType(Enums.getIfPresent(CreditAllocationTransactionType.class, transactionType).orNull());
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<AllocationType> getAllocationTypes(JsonArray allocationOrder) {
|
||||
if (allocationOrder != null) {
|
||||
List<Pair<Integer, AllocationType>> parsedListWithOrder = allocationOrder.asList().stream().map(json -> {
|
||||
Map<String, JsonElement> map = json.getAsJsonObject().asMap();
|
||||
AllocationType allocationType = null;
|
||||
String creditAllocationRule = asStringOrNull(map.get("creditAllocationRule"));
|
||||
if (creditAllocationRule != null) {
|
||||
allocationType = Enums.getIfPresent(AllocationType.class, creditAllocationRule).orNull();
|
||||
}
|
||||
return Pair.of(asIntegerOrNull(map.get("order")), allocationType);
|
||||
}).sorted(Comparator.comparing(Pair::getLeft)).toList();
|
||||
creditAllocationsValidator.validatePairOfOrderAndCreditAllocationType(parsedListWithOrder);
|
||||
return parsedListWithOrder.stream().map(Pair::getRight).toList();
|
||||
} else {
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
|
||||
private Integer asIntegerOrNull(JsonElement element) {
|
||||
if (!element.isJsonNull()) {
|
||||
return element.getAsInt();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String asStringOrNull(JsonElement element) {
|
||||
if (!element.isJsonNull()) {
|
||||
return element.getAsString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private JsonArray asJsonArrayOrNull(JsonElement element) {
|
||||
if (!element.isJsonNull()) {
|
||||
return element.getAsJsonArray();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
-96
@@ -1,96 +0,0 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanproduct.domain;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.IntStream;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class CreditAllocationsValidator {
|
||||
|
||||
public static final String ADVANCED_PAYMENT_ALLOCATION_STRATEGY = "advanced-payment-allocation-strategy";
|
||||
|
||||
public void validate(List<LoanProductCreditAllocationRule> rules, String code) {
|
||||
if (isAdvancedPaymentStrategy(code)) {
|
||||
if (hasDuplicateTransactionTypes(rules)) {
|
||||
raiseValidationError("advanced-payment-strategy-with-duplicate-credit-allocation",
|
||||
"The same transaction type must be provided only once");
|
||||
}
|
||||
|
||||
if (rules != null) {
|
||||
for (LoanProductCreditAllocationRule rule : rules) {
|
||||
validateAllocationRule(rule);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (hasLoanProductCreditAllocationRule(rules)) {
|
||||
raiseValidationError("credit_allocation.must.not.be.provided.when.allocation.strategy.is.not.advanced-payment-strategy",
|
||||
"In case '" + code + "' payment strategy, creditAllocation must not be provided");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void validatePairOfOrderAndCreditAllocationType(List<Pair<Integer, AllocationType>> rules) {
|
||||
if (rules.size() != 4) {
|
||||
raiseValidationError("advanced-payment-strategy.each_credit_allocation_order.must.contain.4.entries",
|
||||
"Each provided credit allocation must contain exactly 4 allocation rules, but " + rules.size() + " were provided");
|
||||
}
|
||||
|
||||
List<AllocationType> deduped = rules.stream().map(Pair::getRight).distinct().toList();
|
||||
if (deduped.size() != 4) {
|
||||
raiseValidationError("advanced-payment-strategy.must.not.have.duplicate.credit.allocation.rule",
|
||||
"The list of provided credit allocation rules must not contain any duplicates");
|
||||
}
|
||||
|
||||
if (!Arrays.equals(IntStream.rangeClosed(1, 4).boxed().toArray(), rules.stream().map(Pair::getLeft).toArray())) {
|
||||
raiseValidationError("advanced-payment-strategy.invalid.order", "The provided orders must be between 1 and 4");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasDuplicateTransactionTypes(List<LoanProductCreditAllocationRule> rules) {
|
||||
return rules != null
|
||||
&& rules.stream().map(LoanProductCreditAllocationRule::getTransactionType).distinct().toList().size() != rules.size();
|
||||
}
|
||||
|
||||
private void validateAllocationRule(LoanProductCreditAllocationRule rule) {
|
||||
if (rule.getTransactionType() == null) {
|
||||
raiseValidationError("advanced-payment-strategy.with.not.valid.transaction.type",
|
||||
"Credit allocation was provided with a not valid transaction type");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAdvancedPaymentStrategy(String code) {
|
||||
return ADVANCED_PAYMENT_ALLOCATION_STRATEGY.equals(code);
|
||||
}
|
||||
|
||||
private boolean hasLoanProductCreditAllocationRule(List<LoanProductCreditAllocationRule> rules) {
|
||||
return rules != null && rules.size() > 0;
|
||||
}
|
||||
|
||||
private void raiseValidationError(String globalisationMessageCode, String msg) {
|
||||
throw new PlatformApiDataValidationException(List.of(ApiParameterError.generalError(globalisationMessageCode, msg)));
|
||||
}
|
||||
|
||||
}
|
||||
+1
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanproduct.domain;
|
||||
|
||||
// TODO FINERACT-1932-Fineract modularization: Move to fineract-progressive-loan module after refactor of Loan and LoanProduct classes
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
|
||||
+4
@@ -96,9 +96,13 @@ public class LoanProduct extends AbstractPersistableCustom {
|
||||
@Column(name = "loan_transaction_strategy_name")
|
||||
private String transactionProcessingStrategyName;
|
||||
|
||||
// TODO FINERACT-1932-Fineract modularization: Move to fineract-progressive-loan module after removing association
|
||||
// from LoanProduct entity
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loanProduct", orphanRemoval = true, fetch = FetchType.EAGER)
|
||||
private List<LoanProductPaymentAllocationRule> paymentAllocationRules = new ArrayList<>();
|
||||
|
||||
// TODO FINERACT-1932-Fineract modularization: Move to fineract-progressive-loan module after removing association
|
||||
// from LoanProduct entity
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loanProduct", orphanRemoval = true, fetch = FetchType.EAGER)
|
||||
private List<LoanProductCreditAllocationRule> creditAllocationRules = new ArrayList<>();
|
||||
|
||||
|
||||
+1
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanproduct.domain;
|
||||
|
||||
// TODO FINERACT-1932-Fineract modularization: Move to fineract-progressive-loan module after refactor of Loan and LoanProduct classes
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Convert;
|
||||
import jakarta.persistence.Entity;
|
||||
|
||||
+1
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanproduct.domain;
|
||||
|
||||
// TODO FINERACT-1932-Fineract modularization: Move to fineract-progressive-loan module after refactor of Loan and LoanProduct classes
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Convert;
|
||||
import jakarta.persistence.Entity;
|
||||
|
||||
+1
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanproduct.domain;
|
||||
|
||||
// TODO FINERACT-1932-Fineract modularization: Move to fineract-progressive-loan module after refactor of Loan and LoanProduct classes
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
|
||||
+1
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanproduct.domain;
|
||||
|
||||
// TODO FINERACT-1932-Fineract modularization: Move to fineract-progressive-loan module after refactor of Loan and LoanProduct classes
|
||||
import static org.apache.fineract.portfolio.loanproduct.domain.AllocationType.FEE;
|
||||
import static org.apache.fineract.portfolio.loanproduct.domain.AllocationType.INTEREST;
|
||||
import static org.apache.fineract.portfolio.loanproduct.domain.AllocationType.PENALTY;
|
||||
|
||||
+1
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanproduct.domain;
|
||||
|
||||
// TODO FINERACT-1932-Fineract modularization: Move to fineract-progressive-loan module after refactor of Loan and LoanProduct classes
|
||||
import jakarta.persistence.AttributeConverter;
|
||||
import jakarta.persistence.Converter;
|
||||
import java.util.List;
|
||||
|
||||
Reference in New Issue
Block a user