FINERACT-2080: Extract DTO mappers from loan entity
This commit is contained in:
committed by
Adam Saghy
parent
b01dca3ecc
commit
2ba7e28108
+49
@@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
* 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.data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class AccountingBridgeDataDTO {
|
||||||
|
|
||||||
|
private Long loanId;
|
||||||
|
private Long loanProductId;
|
||||||
|
private Long officeId;
|
||||||
|
private String currencyCode;
|
||||||
|
private BigDecimal calculatedInterest;
|
||||||
|
private boolean cashBasedAccountingEnabled;
|
||||||
|
private boolean upfrontAccrualBasedAccountingEnabled;
|
||||||
|
private boolean periodicAccrualBasedAccountingEnabled;
|
||||||
|
private boolean isAccountTransfer;
|
||||||
|
private boolean isChargeOff;
|
||||||
|
private boolean isFraud;
|
||||||
|
private Long chargeOffReasonCodeValue;
|
||||||
|
private List<AccountingBridgeLoanTransactionDTO> newLoanTransactions = new ArrayList<>();
|
||||||
|
|
||||||
|
}
|
||||||
+56
@@ -0,0 +1,56 @@
|
|||||||
|
/**
|
||||||
|
* 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.data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class AccountingBridgeLoanTransactionDTO {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
private Long officeId;
|
||||||
|
private LoanTransactionEnumData type;
|
||||||
|
private boolean reversed;
|
||||||
|
private LocalDate date;
|
||||||
|
private String currencyCode;
|
||||||
|
private BigDecimal amount;
|
||||||
|
private BigDecimal netDisbursalAmount;
|
||||||
|
private BigDecimal principalPortion;
|
||||||
|
private BigDecimal interestPortion;
|
||||||
|
private BigDecimal feeChargesPortion;
|
||||||
|
private BigDecimal penaltyChargesPortion;
|
||||||
|
private BigDecimal overPaymentPortion;
|
||||||
|
private String chargeRefundChargeType;
|
||||||
|
private Long paymentTypeId;
|
||||||
|
private List<LoanChargePaidByDTO> loanChargesPaid = new ArrayList<>();
|
||||||
|
private BigDecimal principalPaid;
|
||||||
|
private BigDecimal feePaid;
|
||||||
|
private BigDecimal penaltyPaid;
|
||||||
|
private LoanChargeData loanChargeData;
|
||||||
|
private boolean loanToLoanTransfer;
|
||||||
|
|
||||||
|
}
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* 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.data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class LoanChargePaidByDTO {
|
||||||
|
|
||||||
|
private Long chargeId;
|
||||||
|
private Boolean isPenalty;
|
||||||
|
private Long loanChargeId;
|
||||||
|
private BigDecimal amount;
|
||||||
|
private Integer installmentNumber;
|
||||||
|
|
||||||
|
}
|
||||||
+30
-554
@@ -21,9 +21,6 @@ package org.apache.fineract.portfolio.loanaccount.domain;
|
|||||||
import static org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType.CUMULATIVE;
|
import static org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType.CUMULATIVE;
|
||||||
import static org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType.PROGRESSIVE;
|
import static org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType.PROGRESSIVE;
|
||||||
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.gson.JsonPrimitive;
|
|
||||||
import jakarta.persistence.CascadeType;
|
import jakarta.persistence.CascadeType;
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.Convert;
|
import jakarta.persistence.Convert;
|
||||||
@@ -43,20 +40,16 @@ import jakarta.persistence.UniqueConstraint;
|
|||||||
import jakarta.persistence.Version;
|
import jakarta.persistence.Version;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.MathContext;
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ListIterator;
|
import java.util.ListIterator;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
@@ -67,61 +60,36 @@ import lombok.Setter;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.fineract.infrastructure.codes.domain.CodeValue;
|
import org.apache.fineract.infrastructure.codes.domain.CodeValue;
|
||||||
import org.apache.fineract.infrastructure.configuration.service.TemporaryConfigurationServiceContainer;
|
import org.apache.fineract.infrastructure.configuration.service.TemporaryConfigurationServiceContainer;
|
||||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
|
||||||
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
||||||
import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
||||||
import org.apache.fineract.infrastructure.core.serialization.JsonParserHelper;
|
|
||||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
||||||
import org.apache.fineract.infrastructure.security.service.RandomPasswordGenerator;
|
import org.apache.fineract.infrastructure.security.service.RandomPasswordGenerator;
|
||||||
import org.apache.fineract.organisation.holiday.domain.Holiday;
|
import org.apache.fineract.organisation.holiday.domain.Holiday;
|
||||||
import org.apache.fineract.organisation.holiday.service.HolidayUtil;
|
import org.apache.fineract.organisation.holiday.service.HolidayUtil;
|
||||||
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
|
|
||||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||||
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
|
|
||||||
import org.apache.fineract.organisation.office.domain.Office;
|
import org.apache.fineract.organisation.office.domain.Office;
|
||||||
import org.apache.fineract.organisation.staff.domain.Staff;
|
import org.apache.fineract.organisation.staff.domain.Staff;
|
||||||
import org.apache.fineract.organisation.workingdays.domain.WorkingDays;
|
import org.apache.fineract.organisation.workingdays.domain.WorkingDays;
|
||||||
import org.apache.fineract.portfolio.accountdetails.domain.AccountType;
|
import org.apache.fineract.portfolio.accountdetails.domain.AccountType;
|
||||||
import org.apache.fineract.portfolio.calendar.data.CalendarHistoryDataWrapper;
|
|
||||||
import org.apache.fineract.portfolio.calendar.domain.Calendar;
|
|
||||||
import org.apache.fineract.portfolio.calendar.domain.CalendarHistory;
|
|
||||||
import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
|
|
||||||
import org.apache.fineract.portfolio.calendar.domain.CalendarWeekDaysType;
|
|
||||||
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
|
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
|
||||||
import org.apache.fineract.portfolio.charge.domain.Charge;
|
import org.apache.fineract.portfolio.charge.domain.Charge;
|
||||||
import org.apache.fineract.portfolio.charge.domain.ChargeCalculationType;
|
import org.apache.fineract.portfolio.charge.domain.ChargeCalculationType;
|
||||||
import org.apache.fineract.portfolio.charge.domain.ChargeTimeType;
|
import org.apache.fineract.portfolio.charge.domain.ChargeTimeType;
|
||||||
import org.apache.fineract.portfolio.client.domain.Client;
|
import org.apache.fineract.portfolio.client.domain.Client;
|
||||||
import org.apache.fineract.portfolio.collateral.domain.LoanCollateral;
|
import org.apache.fineract.portfolio.collateral.domain.LoanCollateral;
|
||||||
import org.apache.fineract.portfolio.common.domain.DayOfWeekType;
|
|
||||||
import org.apache.fineract.portfolio.common.domain.NthDayType;
|
|
||||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||||
import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO;
|
|
||||||
import org.apache.fineract.portfolio.floatingrates.data.FloatingRatePeriodData;
|
|
||||||
import org.apache.fineract.portfolio.fund.domain.Fund;
|
import org.apache.fineract.portfolio.fund.domain.Fund;
|
||||||
import org.apache.fineract.portfolio.group.domain.Group;
|
import org.apache.fineract.portfolio.group.domain.Group;
|
||||||
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
|
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.DisbursementData;
|
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
|
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
|
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
|
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator;
|
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.AmortizationMethod;
|
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.CreditAllocationTransactionType;
|
import org.apache.fineract.portfolio.loanproduct.domain.CreditAllocationTransactionType;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
|
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
|
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod;
|
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod;
|
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanSupportedInterestRefundTypes;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanSupportedInterestRefundTypes;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType;
|
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.RepaymentStartDateType;
|
|
||||||
import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
|
import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
|
||||||
import org.apache.fineract.portfolio.rate.domain.Rate;
|
import org.apache.fineract.portfolio.rate.domain.Rate;
|
||||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDatedChecks;
|
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDatedChecks;
|
||||||
@@ -186,7 +154,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
@JoinColumn(name = "product_id", nullable = false)
|
@JoinColumn(name = "product_id", nullable = false)
|
||||||
private LoanProduct loanProduct;
|
private LoanProduct loanProduct;
|
||||||
|
|
||||||
@ManyToOne(optional = true, fetch = FetchType.EAGER)
|
@ManyToOne(fetch = FetchType.EAGER)
|
||||||
@JoinColumn(name = "fund_id")
|
@JoinColumn(name = "fund_id")
|
||||||
private Fund fund;
|
private Fund fund;
|
||||||
|
|
||||||
@@ -246,7 +214,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
private LocalDate rejectedOnDate;
|
private LocalDate rejectedOnDate;
|
||||||
|
|
||||||
@Setter()
|
@Setter()
|
||||||
@ManyToOne(optional = true, fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@JoinColumn(name = "rejectedon_userid")
|
@JoinColumn(name = "rejectedon_userid")
|
||||||
private AppUser rejectedBy;
|
private AppUser rejectedBy;
|
||||||
|
|
||||||
@@ -255,7 +223,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
private LocalDate withdrawnOnDate;
|
private LocalDate withdrawnOnDate;
|
||||||
|
|
||||||
@Setter()
|
@Setter()
|
||||||
@ManyToOne(optional = true, fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@JoinColumn(name = "withdrawnon_userid")
|
@JoinColumn(name = "withdrawnon_userid")
|
||||||
private AppUser withdrawnBy;
|
private AppUser withdrawnBy;
|
||||||
|
|
||||||
@@ -264,7 +232,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
private LocalDate approvedOnDate;
|
private LocalDate approvedOnDate;
|
||||||
|
|
||||||
@Setter()
|
@Setter()
|
||||||
@ManyToOne(optional = true, fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@JoinColumn(name = "approvedon_userid")
|
@JoinColumn(name = "approvedon_userid")
|
||||||
private AppUser approvedBy;
|
private AppUser approvedBy;
|
||||||
|
|
||||||
@@ -277,7 +245,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
private LocalDate actualDisbursementDate;
|
private LocalDate actualDisbursementDate;
|
||||||
|
|
||||||
@Setter()
|
@Setter()
|
||||||
@ManyToOne(optional = true, fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@JoinColumn(name = "disbursedon_userid")
|
@JoinColumn(name = "disbursedon_userid")
|
||||||
private AppUser disbursedBy;
|
private AppUser disbursedBy;
|
||||||
|
|
||||||
@@ -286,7 +254,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
private LocalDate closedOnDate;
|
private LocalDate closedOnDate;
|
||||||
|
|
||||||
@Setter()
|
@Setter()
|
||||||
@ManyToOne(optional = true, fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@JoinColumn(name = "closedon_userid")
|
@JoinColumn(name = "closedon_userid")
|
||||||
private AppUser closedBy;
|
private AppUser closedBy;
|
||||||
|
|
||||||
@@ -298,7 +266,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
@Column(name = "rescheduledon_date")
|
@Column(name = "rescheduledon_date")
|
||||||
private LocalDate rescheduledOnDate;
|
private LocalDate rescheduledOnDate;
|
||||||
|
|
||||||
@ManyToOne(optional = true, fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@JoinColumn(name = "rescheduledon_userid")
|
@JoinColumn(name = "rescheduledon_userid")
|
||||||
private AppUser rescheduledByUser;
|
private AppUser rescheduledByUser;
|
||||||
|
|
||||||
@@ -396,7 +364,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
@Column(name = "total_recovered_derived", scale = 6, precision = 19)
|
@Column(name = "total_recovered_derived", scale = 6, precision = 19)
|
||||||
private BigDecimal totalRecovered;
|
private BigDecimal totalRecovered;
|
||||||
|
|
||||||
@OneToOne(cascade = CascadeType.ALL, mappedBy = "loan", optional = true, orphanRemoval = true, fetch = FetchType.LAZY)
|
@OneToOne(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true, fetch = FetchType.LAZY)
|
||||||
private LoanInterestRecalculationDetails loanInterestRecalculationDetails;
|
private LoanInterestRecalculationDetails loanInterestRecalculationDetails;
|
||||||
|
|
||||||
@Column(name = "is_npa", nullable = false)
|
@Column(name = "is_npa", nullable = false)
|
||||||
@@ -439,7 +407,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
@Column(name = "is_fraud", nullable = false)
|
@Column(name = "is_fraud", nullable = false)
|
||||||
private boolean fraud = false;
|
private boolean fraud = false;
|
||||||
|
|
||||||
@OneToOne(cascade = CascadeType.ALL, mappedBy = "loan", optional = true, orphanRemoval = true, fetch = FetchType.LAZY)
|
@OneToOne(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true, fetch = FetchType.LAZY)
|
||||||
private LoanTopupDetails loanTopupDetails;
|
private LoanTopupDetails loanTopupDetails;
|
||||||
|
|
||||||
@OneToMany(fetch = FetchType.LAZY)
|
@OneToMany(fetch = FetchType.LAZY)
|
||||||
@@ -709,7 +677,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
* newly created transaction is also added to the Loan on which this method is called.
|
* newly created transaction is also added to the Loan on which this method is called.
|
||||||
*
|
*
|
||||||
* If "suppliedTransactionDate" is not passed Id, the transaction date is set to the loans due date if the due date
|
* If "suppliedTransactionDate" is not passed Id, the transaction date is set to the loans due date if the due date
|
||||||
* is lesser than todays date. If not, the transaction date is set to todays date
|
* is lesser than today's date. If not, the transaction date is set to today's date
|
||||||
*/
|
*/
|
||||||
public LoanTransaction handleChargeAppliedTransaction(final LoanCharge loanCharge, final LocalDate suppliedTransactionDate) {
|
public LoanTransaction handleChargeAppliedTransaction(final LoanCharge loanCharge, final LocalDate suppliedTransactionDate) {
|
||||||
if (isProgressiveSchedule()) {
|
if (isProgressiveSchedule()) {
|
||||||
@@ -782,9 +750,9 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
if (transaction.isGreaterThan(chargeAmount)) {
|
if (transaction.isGreaterThan(chargeAmount)) {
|
||||||
final Money principalPortion = Money.zero(currency);
|
final Money principalPortion = Money.zero(currency);
|
||||||
final Money interestPortion = Money.zero(currency);
|
final Money interestPortion = Money.zero(currency);
|
||||||
final Money penaltychargesPortion = Money.zero(currency);
|
final Money penaltyChargesPortion = Money.zero(currency);
|
||||||
|
|
||||||
transaction.updateComponentsAndTotal(principalPortion, interestPortion, chargeAmount, penaltychargesPortion);
|
transaction.updateComponentsAndTotal(principalPortion, interestPortion, chargeAmount, penaltyChargesPortion);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
transactionToRemove = transaction;
|
transactionToRemove = transaction;
|
||||||
@@ -874,12 +842,6 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
return this.summary.getTotalWrittenOff();
|
return this.summary.getTotalWrittenOff();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param calculationType
|
|
||||||
* @param percentage
|
|
||||||
* @param installment
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private Money calculateInstallmentChargeAmount(final ChargeCalculationType calculationType, final BigDecimal percentage,
|
private Money calculateInstallmentChargeAmount(final ChargeCalculationType calculationType, final BigDecimal percentage,
|
||||||
final LoanRepaymentScheduleInstallment installment) {
|
final LoanRepaymentScheduleInstallment installment) {
|
||||||
Money percentOf = switch (calculationType) {
|
Money percentOf = switch (calculationType) {
|
||||||
@@ -1113,64 +1075,6 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method returns date format and locale if present in the JsonCommand
|
|
||||||
public Map<String, String> getDateFormatAndLocale(final JsonCommand jsonCommand) {
|
|
||||||
Map<String, String> returnObject = new HashMap<>();
|
|
||||||
JsonElement jsonElement = jsonCommand.parsedJson();
|
|
||||||
if (jsonElement.isJsonObject()) {
|
|
||||||
JsonObject topLevel = jsonElement.getAsJsonObject();
|
|
||||||
if (topLevel.has(LoanApiConstants.dateFormatParameterName)
|
|
||||||
&& topLevel.get(LoanApiConstants.dateFormatParameterName).isJsonPrimitive()) {
|
|
||||||
final JsonPrimitive primitive = topLevel.get(LoanApiConstants.dateFormatParameterName).getAsJsonPrimitive();
|
|
||||||
returnObject.put(LoanApiConstants.dateFormatParameterName, primitive.getAsString());
|
|
||||||
}
|
|
||||||
if (topLevel.has(LoanApiConstants.localeParameterName)
|
|
||||||
&& topLevel.get(LoanApiConstants.localeParameterName).isJsonPrimitive()) {
|
|
||||||
final JsonPrimitive primitive = topLevel.get(LoanApiConstants.localeParameterName).getAsJsonPrimitive();
|
|
||||||
String localeString = primitive.getAsString();
|
|
||||||
returnObject.put(LoanApiConstants.localeParameterName, localeString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return returnObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, Object> parseDisbursementDetails(final JsonObject jsonObject, String dateFormat, Locale locale) {
|
|
||||||
Map<String, Object> returnObject = new HashMap<>();
|
|
||||||
if (jsonObject.get(LoanApiConstants.expectedDisbursementDateParameterName) != null
|
|
||||||
&& jsonObject.get(LoanApiConstants.expectedDisbursementDateParameterName).isJsonPrimitive()) {
|
|
||||||
final JsonPrimitive primitive = jsonObject.get(LoanApiConstants.expectedDisbursementDateParameterName).getAsJsonPrimitive();
|
|
||||||
final String valueAsString = primitive.getAsString();
|
|
||||||
if (StringUtils.isNotBlank(valueAsString)) {
|
|
||||||
LocalDate date = JsonParserHelper.convertFrom(valueAsString, LoanApiConstants.expectedDisbursementDateParameterName,
|
|
||||||
dateFormat, locale);
|
|
||||||
if (date != null) {
|
|
||||||
returnObject.put(LoanApiConstants.expectedDisbursementDateParameterName, date);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (jsonObject.get(LoanApiConstants.disbursementPrincipalParameterName).isJsonPrimitive()
|
|
||||||
&& StringUtils.isNotBlank(jsonObject.get(LoanApiConstants.disbursementPrincipalParameterName).getAsString())) {
|
|
||||||
BigDecimal principal = jsonObject.getAsJsonPrimitive(LoanApiConstants.disbursementPrincipalParameterName).getAsBigDecimal();
|
|
||||||
returnObject.put(LoanApiConstants.disbursementPrincipalParameterName, principal);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (jsonObject.has(LoanApiConstants.disbursementIdParameterName)
|
|
||||||
&& jsonObject.get(LoanApiConstants.disbursementIdParameterName).isJsonPrimitive()
|
|
||||||
&& StringUtils.isNotBlank(jsonObject.get(LoanApiConstants.disbursementIdParameterName).getAsString())) {
|
|
||||||
Long id = jsonObject.getAsJsonPrimitive(LoanApiConstants.disbursementIdParameterName).getAsLong();
|
|
||||||
returnObject.put(LoanApiConstants.disbursementIdParameterName, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (jsonObject.has(LoanApiConstants.loanChargeIdParameterName)
|
|
||||||
&& jsonObject.get(LoanApiConstants.loanChargeIdParameterName).isJsonPrimitive()
|
|
||||||
&& StringUtils.isNotBlank(jsonObject.get(LoanApiConstants.loanChargeIdParameterName).getAsString())) {
|
|
||||||
returnObject.put(LoanApiConstants.loanChargeIdParameterName,
|
|
||||||
jsonObject.getAsJsonPrimitive(LoanApiConstants.loanChargeIdParameterName).getAsString());
|
|
||||||
}
|
|
||||||
return returnObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Long> fetchLoanTrancheChargeIds() {
|
public List<Long> fetchLoanTrancheChargeIds() {
|
||||||
return getCharges().stream()//
|
return getCharges().stream()//
|
||||||
.filter(charge -> charge.isTrancheDisbursementCharge() && charge.isActive()) //
|
.filter(charge -> charge.isTrancheDisbursementCharge() && charge.isActive()) //
|
||||||
@@ -1344,56 +1248,6 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoanScheduleModel regenerateScheduleModel(final ScheduleGeneratorDTO scheduleGeneratorDTO) {
|
|
||||||
final MathContext mc = MoneyHelper.getMathContext();
|
|
||||||
|
|
||||||
final LoanApplicationTerms loanApplicationTerms = constructLoanApplicationTerms(scheduleGeneratorDTO);
|
|
||||||
LoanScheduleGenerator loanScheduleGenerator;
|
|
||||||
if (loanApplicationTerms.isEqualAmortization()) {
|
|
||||||
if (loanApplicationTerms.getInterestMethod().isDecliningBalance()) {
|
|
||||||
final LoanScheduleGenerator decliningLoanScheduleGenerator = scheduleGeneratorDTO.getLoanScheduleFactory()
|
|
||||||
.create(loanApplicationTerms.getLoanScheduleType(), InterestMethod.DECLINING_BALANCE);
|
|
||||||
Set<LoanCharge> loanCharges = getActiveCharges();
|
|
||||||
LoanScheduleModel loanSchedule = decliningLoanScheduleGenerator.generate(mc, loanApplicationTerms, loanCharges,
|
|
||||||
scheduleGeneratorDTO.getHolidayDetailDTO());
|
|
||||||
|
|
||||||
loanApplicationTerms
|
|
||||||
.updateTotalInterestDue(Money.of(loanApplicationTerms.getCurrency(), loanSchedule.getTotalInterestCharged()));
|
|
||||||
|
|
||||||
}
|
|
||||||
loanScheduleGenerator = scheduleGeneratorDTO.getLoanScheduleFactory().create(loanApplicationTerms.getLoanScheduleType(),
|
|
||||||
InterestMethod.FLAT);
|
|
||||||
} else {
|
|
||||||
loanScheduleGenerator = scheduleGeneratorDTO.getLoanScheduleFactory().create(loanApplicationTerms.getLoanScheduleType(),
|
|
||||||
loanApplicationTerms.getInterestMethod());
|
|
||||||
}
|
|
||||||
|
|
||||||
return loanScheduleGenerator.generate(mc, loanApplicationTerms, getActiveCharges(), scheduleGeneratorDTO.getHolidayDetailDTO());
|
|
||||||
}
|
|
||||||
|
|
||||||
private BigDecimal constructFloatingInterestRates(final BigDecimal annualNominalInterestRate, final FloatingRateDTO floatingRateDTO,
|
|
||||||
final List<LoanTermVariationsData> loanTermVariations) {
|
|
||||||
final LocalDate dateValue = null;
|
|
||||||
final boolean isSpecificToInstallment = false;
|
|
||||||
BigDecimal interestRate = annualNominalInterestRate;
|
|
||||||
if (loanProduct.isLinkedToFloatingInterestRate()) {
|
|
||||||
floatingRateDTO.resetInterestRateDiff();
|
|
||||||
Collection<FloatingRatePeriodData> applicableRates = loanProduct.fetchInterestRates(floatingRateDTO);
|
|
||||||
LocalDate interestRateStartDate = DateUtils.getBusinessLocalDate();
|
|
||||||
for (FloatingRatePeriodData periodData : applicableRates) {
|
|
||||||
LoanTermVariationsData loanTermVariation = new LoanTermVariationsData(
|
|
||||||
LoanEnumerations.loanVariationType(LoanTermVariationType.INTEREST_RATE), periodData.getFromDateAsLocalDate(),
|
|
||||||
periodData.getInterestRate(), dateValue, isSpecificToInstallment);
|
|
||||||
if (!DateUtils.isBefore(interestRateStartDate, periodData.getFromDateAsLocalDate())) {
|
|
||||||
interestRateStartDate = periodData.getFromDateAsLocalDate();
|
|
||||||
interestRate = periodData.getInterestRate();
|
|
||||||
}
|
|
||||||
loanTermVariations.add(loanTermVariation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return interestRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAutoRepaymentForDownPaymentEnabled() {
|
public boolean isAutoRepaymentForDownPaymentEnabled() {
|
||||||
return this.loanRepaymentScheduleDetail.isEnableDownPayment()
|
return this.loanRepaymentScheduleDetail.isEnableDownPayment()
|
||||||
&& this.loanRepaymentScheduleDetail.isEnableAutoRepaymentForDownPayment();
|
&& this.loanRepaymentScheduleDetail.isEnableAutoRepaymentForDownPayment();
|
||||||
@@ -1664,7 +1518,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if total paid in transactions doesnt match repayment schedule then there's an overpayment.
|
// if total paid in transactions doesn't match repayment schedule then there's an overpayment.
|
||||||
return totalPaidInRepayments.minus(cumulativeTotalPaidOnInstallments);
|
return totalPaidInRepayments.minus(cumulativeTotalPaidOnInstallments);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1945,7 +1799,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
return this.client != null ? this.client.getOffice() : this.group.getOffice();
|
return this.client != null ? this.client.getOffice() : this.group.getOffice();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Boolean isCashBasedAccountingEnabledOnLoanProduct() {
|
public Boolean isCashBasedAccountingEnabledOnLoanProduct() {
|
||||||
return this.loanProduct.isCashBasedAccountingEnabled();
|
return this.loanProduct.isCashBasedAccountingEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1970,165 +1824,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
return this.loanProduct.getId();
|
return this.loanProduct.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Map<String, Object>> deriveAccountingBridgeDataForChargeOff(final String currencyCode,
|
public Long fetchChargeOffReasonId() {
|
||||||
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds, boolean isAccountTransfer) {
|
|
||||||
|
|
||||||
final List<Map<String, Object>> accountingBridgeData = new ArrayList<>();
|
|
||||||
final List<Map<String, Object>> newLoanTransactionsBeforeChargeOff = new ArrayList<>();
|
|
||||||
final List<Map<String, Object>> newLoanTransactionsAfterChargeOff = new ArrayList<>();
|
|
||||||
// get map before charge-off
|
|
||||||
final Map<String, Object> accountingBridgeDataBeforeChargeOff = buildAccountingMapForChargeOffDateCriteria(currencyCode,
|
|
||||||
isAccountTransfer, true);
|
|
||||||
// get map after charge-off
|
|
||||||
final Map<String, Object> accountingBridgeDataAfterChargeOff = buildAccountingMapForChargeOffDateCriteria(currencyCode,
|
|
||||||
isAccountTransfer, false);
|
|
||||||
|
|
||||||
// split the transactions according charge-off date
|
|
||||||
classifyTransactionsBasedOnChargeOffDate(newLoanTransactionsBeforeChargeOff, newLoanTransactionsAfterChargeOff,
|
|
||||||
existingTransactionIds, existingReversedTransactionIds, currencyCode);
|
|
||||||
|
|
||||||
accountingBridgeDataBeforeChargeOff.put("newLoanTransactions", newLoanTransactionsBeforeChargeOff);
|
|
||||||
accountingBridgeData.add(accountingBridgeDataBeforeChargeOff);
|
|
||||||
|
|
||||||
accountingBridgeDataAfterChargeOff.put("newLoanTransactions", newLoanTransactionsAfterChargeOff);
|
|
||||||
accountingBridgeData.add(accountingBridgeDataAfterChargeOff);
|
|
||||||
|
|
||||||
return accountingBridgeData;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void classifyTransactionsBasedOnChargeOffDate(List<Map<String, Object>> newLoanTransactionsBeforeChargeOff,
|
|
||||||
List<Map<String, Object>> newLoanTransactionsAfterChargeOff, List<Long> existingTransactionIds,
|
|
||||||
List<Long> existingReversedTransactionIds, String currencyCode) {
|
|
||||||
// Before
|
|
||||||
filterTransactionsByChargeOffDate(newLoanTransactionsBeforeChargeOff, currencyCode, existingTransactionIds,
|
|
||||||
existingReversedTransactionIds, transaction -> DateUtils.isBefore(transaction.getTransactionDate(), getChargedOffOnDate()));
|
|
||||||
// On
|
|
||||||
filterTransactionsByChargeOffDate(newLoanTransactionsBeforeChargeOff, newLoanTransactionsAfterChargeOff, currencyCode,
|
|
||||||
existingTransactionIds, existingReversedTransactionIds,
|
|
||||||
transaction -> DateUtils.isEqual(transaction.getTransactionDate(), getChargedOffOnDate()));
|
|
||||||
// After
|
|
||||||
filterTransactionsByChargeOffDate(newLoanTransactionsAfterChargeOff, currencyCode, existingTransactionIds,
|
|
||||||
existingReversedTransactionIds, transaction -> DateUtils.isAfter(transaction.getTransactionDate(), getChargedOffOnDate()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, Object> getAccountingBridgeDataGenericAttributes(final String currencyCode, boolean isAccountTransfer) {
|
|
||||||
final Map<String, Object> accountingBridgeDataGenericAttributes = new LinkedHashMap<>();
|
|
||||||
accountingBridgeDataGenericAttributes.put("loanId", getId());
|
|
||||||
accountingBridgeDataGenericAttributes.put("loanProductId", productId());
|
|
||||||
accountingBridgeDataGenericAttributes.put("officeId", getOfficeId());
|
|
||||||
accountingBridgeDataGenericAttributes.put("currencyCode", currencyCode);
|
|
||||||
accountingBridgeDataGenericAttributes.put("calculatedInterest", this.summary.getTotalInterestCharged());
|
|
||||||
accountingBridgeDataGenericAttributes.put("cashBasedAccountingEnabled", isCashBasedAccountingEnabledOnLoanProduct());
|
|
||||||
accountingBridgeDataGenericAttributes.put("upfrontAccrualBasedAccountingEnabled", isUpfrontAccrualAccountingEnabledOnLoanProduct());
|
|
||||||
accountingBridgeDataGenericAttributes.put("periodicAccrualBasedAccountingEnabled",
|
|
||||||
isPeriodicAccrualAccountingEnabledOnLoanProduct());
|
|
||||||
accountingBridgeDataGenericAttributes.put("isAccountTransfer", isAccountTransfer);
|
|
||||||
return accountingBridgeDataGenericAttributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, Object> buildAccountingMapForChargeOffDateCriteria(final String currencyCode, boolean isAccountTransfer,
|
|
||||||
boolean isBeforeChargeOffDate) {
|
|
||||||
final Map<String, Object> accountingBridgeDataChargeOff = new LinkedHashMap<>(
|
|
||||||
getAccountingBridgeDataGenericAttributes(currencyCode, isAccountTransfer));
|
|
||||||
accountingBridgeDataChargeOff.put("isChargeOff", !isBeforeChargeOffDate && isChargedOff());
|
|
||||||
accountingBridgeDataChargeOff.put("isFraud", isFraud());
|
|
||||||
accountingBridgeDataChargeOff.put("chargeOffReasonCodeValue", fetchChargeOffReasonId());
|
|
||||||
return accountingBridgeDataChargeOff;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void filterTransactionsByChargeOffDate(List<Map<String, Object>> filteredTransactions, final String currencyCode,
|
|
||||||
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
|
|
||||||
Predicate<LoanTransaction> chargeOffDateCriteria) {
|
|
||||||
filteredTransactions.addAll(this.loanTransactions.stream() //
|
|
||||||
.filter(chargeOffDateCriteria) //
|
|
||||||
.filter(transaction -> {
|
|
||||||
boolean isExistingTransaction = existingTransactionIds.contains(transaction.getId());
|
|
||||||
boolean isExistingReversedTransaction = existingReversedTransactionIds.contains(transaction.getId());
|
|
||||||
|
|
||||||
if (transaction.isReversed() && isExistingTransaction && !isExistingReversedTransaction) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return !isExistingTransaction;
|
|
||||||
}
|
|
||||||
}) //
|
|
||||||
.map(transaction -> transaction.toMapData(currencyCode)).toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void filterTransactionsByChargeOffDate(List<Map<String, Object>> newLoanTransactionsBeforeChargeOff,
|
|
||||||
List<Map<String, Object>> newLoanTransactionsAfterChargeOff, String currencyCode, List<Long> existingTransactionIds,
|
|
||||||
List<Long> existingReversedTransactionIds, Predicate<LoanTransaction> chargeOffDateCriteria) {
|
|
||||||
|
|
||||||
LoanTransaction chargeOffTransaction = this.loanTransactions.stream() //
|
|
||||||
.filter(LoanTransaction::isChargeOff) //
|
|
||||||
.filter(LoanTransaction::isNotReversed) //
|
|
||||||
.findFirst().get();
|
|
||||||
|
|
||||||
LoanTransaction originalChargeOffTransaction = getOriginalTransactionIfReverseReplayed(chargeOffTransaction);
|
|
||||||
|
|
||||||
this.loanTransactions.stream().filter(chargeOffDateCriteria).forEach(transaction -> {
|
|
||||||
boolean isExistingTransaction = existingTransactionIds.contains(transaction.getId());
|
|
||||||
boolean isExistingReversedTransaction = existingReversedTransactionIds.contains(transaction.getId());
|
|
||||||
List<Map<String, Object>> targetList = null;
|
|
||||||
if ((transaction.isReversed() && isExistingTransaction && !isExistingReversedTransaction)) {
|
|
||||||
// reversed transactions
|
|
||||||
LoanTransaction originalTransaction = getOriginalTransactionIfReverseReplayed(transaction);
|
|
||||||
targetList = originalTransaction.happenedBefore(originalChargeOffTransaction) ? newLoanTransactionsBeforeChargeOff
|
|
||||||
: newLoanTransactionsAfterChargeOff;
|
|
||||||
|
|
||||||
} else if (!isExistingTransaction) {
|
|
||||||
// new and replayed transactions
|
|
||||||
targetList = transaction.happenedBefore(chargeOffTransaction) ? newLoanTransactionsBeforeChargeOff
|
|
||||||
: newLoanTransactionsAfterChargeOff;
|
|
||||||
}
|
|
||||||
if (targetList != null) {
|
|
||||||
targetList.add(transaction.toMapData(currencyCode));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private LoanTransaction getOriginalTransactionIfReverseReplayed(LoanTransaction loanTransaction) {
|
|
||||||
if (!loanTransaction.getLoanTransactionRelations().isEmpty()) {
|
|
||||||
return loanTransaction.getLoanTransactionRelations().stream()
|
|
||||||
.filter(tr -> LoanTransactionRelationTypeEnum.REPLAYED.equals(tr.getRelationType())).map(tr -> tr.getToTransaction())
|
|
||||||
.collect(Collectors.toList()).stream().sorted(Comparator.comparingLong(LoanTransaction::getId)).findFirst()
|
|
||||||
.orElse(loanTransaction);
|
|
||||||
}
|
|
||||||
return loanTransaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, Object> deriveAccountingBridgeData(final String currencyCode, final List<Long> existingTransactionIds,
|
|
||||||
final List<Long> existingReversedTransactionIds, boolean isAccountTransfer) {
|
|
||||||
|
|
||||||
final Map<String, Object> accountingBridgeData = new LinkedHashMap<>();
|
|
||||||
accountingBridgeData.put("loanId", getId());
|
|
||||||
accountingBridgeData.put("loanProductId", productId());
|
|
||||||
accountingBridgeData.put("officeId", getOfficeId());
|
|
||||||
accountingBridgeData.put("currencyCode", currencyCode);
|
|
||||||
accountingBridgeData.put("calculatedInterest", this.summary.getTotalInterestCharged());
|
|
||||||
accountingBridgeData.put("cashBasedAccountingEnabled", isCashBasedAccountingEnabledOnLoanProduct());
|
|
||||||
accountingBridgeData.put("upfrontAccrualBasedAccountingEnabled", isUpfrontAccrualAccountingEnabledOnLoanProduct());
|
|
||||||
accountingBridgeData.put("periodicAccrualBasedAccountingEnabled", isPeriodicAccrualAccountingEnabledOnLoanProduct());
|
|
||||||
accountingBridgeData.put("isAccountTransfer", isAccountTransfer);
|
|
||||||
accountingBridgeData.put("isChargeOff", isChargedOff());
|
|
||||||
accountingBridgeData.put("chargeOffReasonCodeValue", fetchChargeOffReasonId());
|
|
||||||
|
|
||||||
accountingBridgeData.put("isFraud", isFraud());
|
|
||||||
|
|
||||||
final List<Map<String, Object>> newLoanTransactions = new ArrayList<>();
|
|
||||||
for (final LoanTransaction transaction : this.loanTransactions) {
|
|
||||||
if (transaction.isReversed() && existingTransactionIds.contains(transaction.getId())
|
|
||||||
&& !existingReversedTransactionIds.contains(transaction.getId())) {
|
|
||||||
newLoanTransactions.add(transaction.toMapData(currencyCode));
|
|
||||||
} else if (!existingTransactionIds.contains(transaction.getId())) {
|
|
||||||
newLoanTransactions.add(transaction.toMapData(currencyCode));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
accountingBridgeData.put("newLoanTransactions", newLoanTransactions);
|
|
||||||
return accountingBridgeData;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Long fetchChargeOffReasonId() {
|
|
||||||
return isChargedOff() && getChargeOffReason() != null ? getChargeOffReason().getId() : null;
|
return isChargedOff() && getChargeOffReason() != null ? getChargeOffReason().getId() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2223,25 +1919,23 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
final Integer loanRepaymentInterval = this.loanRepaymentScheduleDetail.getRepayEvery();
|
final Integer loanRepaymentInterval = this.loanRepaymentScheduleDetail.getRepayEvery();
|
||||||
final String frequency = CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType);
|
final String frequency = CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType);
|
||||||
|
|
||||||
LocalDate newRepaymentDate = null;
|
LocalDate newRepaymentDate;
|
||||||
LocalDate seedDate = meetingStartDate;
|
|
||||||
LocalDate latestRepaymentDate = null;
|
LocalDate latestRepaymentDate = null;
|
||||||
List<LoanRepaymentScheduleInstallment> installments = getRepaymentScheduleInstallments();
|
List<LoanRepaymentScheduleInstallment> installments = getRepaymentScheduleInstallments();
|
||||||
for (final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : installments) {
|
for (final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : installments) {
|
||||||
LocalDate oldDueDate = loanRepaymentScheduleInstallment.getDueDate();
|
LocalDate oldDueDate = loanRepaymentScheduleInstallment.getDueDate();
|
||||||
|
|
||||||
// FIXME: AA this won't update repayment dates before current date.
|
// FIXME: AA this won't update repayment dates before current date.
|
||||||
|
if (DateUtils.isAfter(oldDueDate, meetingStartDate) && DateUtils.isDateInTheFuture(oldDueDate)) {
|
||||||
if (DateUtils.isAfter(oldDueDate, seedDate) && DateUtils.isDateInTheFuture(oldDueDate)) {
|
newRepaymentDate = CalendarUtils.getNewRepaymentMeetingDate(recuringRule, meetingStartDate, oldDueDate,
|
||||||
newRepaymentDate = CalendarUtils.getNewRepaymentMeetingDate(recuringRule, seedDate, oldDueDate, loanRepaymentInterval,
|
loanRepaymentInterval, frequency, workingDays, isSkipRepaymentonfirstdayofmonth, numberofDays);
|
||||||
frequency, workingDays, isSkipRepaymentonfirstdayofmonth, numberofDays);
|
|
||||||
|
|
||||||
final LocalDate maxDateLimitForNewRepayment = getMaxDateLimitForNewRepayment(repaymentPeriodFrequencyType,
|
final LocalDate maxDateLimitForNewRepayment = getMaxDateLimitForNewRepayment(repaymentPeriodFrequencyType,
|
||||||
loanRepaymentInterval, tmpFromDate);
|
loanRepaymentInterval, tmpFromDate);
|
||||||
|
|
||||||
if (DateUtils.isAfter(newRepaymentDate, maxDateLimitForNewRepayment)) {
|
if (DateUtils.isAfter(newRepaymentDate, maxDateLimitForNewRepayment)) {
|
||||||
newRepaymentDate = CalendarUtils.getNextRepaymentMeetingDate(recuringRule, seedDate, tmpFromDate, loanRepaymentInterval,
|
newRepaymentDate = CalendarUtils.getNextRepaymentMeetingDate(recuringRule, meetingStartDate, tmpFromDate,
|
||||||
frequency, workingDays, isSkipRepaymentonfirstdayofmonth, numberofDays);
|
loanRepaymentInterval, frequency, workingDays, isSkipRepaymentonfirstdayofmonth, numberofDays);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isHolidayEnabled) {
|
if (isHolidayEnabled) {
|
||||||
@@ -2292,10 +1986,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Integer getLoanProductLoanCounter() {
|
public Integer getLoanProductLoanCounter() {
|
||||||
if (this.loanProductCounter == null) {
|
return Objects.requireNonNullElse(this.loanProductCounter, 0);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return this.loanProductCounter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateClientLoanCounter(final Integer newLoanCounter) {
|
public void updateClientLoanCounter(final Integer newLoanCounter) {
|
||||||
@@ -2510,76 +2201,6 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
return (this.actualMaturityDate != null) ? (referenceDate.compareTo(this.actualMaturityDate) >= 0) : false;
|
return (this.actualMaturityDate != null) ? (referenceDate.compareTo(this.actualMaturityDate) >= 0) : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoanApplicationTerms constructLoanApplicationTerms(final ScheduleGeneratorDTO scheduleGeneratorDTO) {
|
|
||||||
final Integer loanTermFrequency = this.termFrequency;
|
|
||||||
NthDayType nthDayType = null;
|
|
||||||
DayOfWeekType dayOfWeekType = null;
|
|
||||||
final List<DisbursementData> disbursementData = new ArrayList<>();
|
|
||||||
for (LoanDisbursementDetails disbursementDetails : getDisbursementDetails()) {
|
|
||||||
disbursementData.add(disbursementDetails.toData());
|
|
||||||
}
|
|
||||||
|
|
||||||
Calendar calendar = scheduleGeneratorDTO.getCalendar();
|
|
||||||
if (calendar != null) {
|
|
||||||
nthDayType = CalendarUtils.getRepeatsOnNthDayOfMonth(calendar.getRecurrence());
|
|
||||||
dayOfWeekType = DayOfWeekType.fromInt(CalendarUtils.getRepeatsOnDay(calendar.getRecurrence()).getValue());
|
|
||||||
}
|
|
||||||
HolidayDetailDTO holidayDetailDTO = scheduleGeneratorDTO.getHolidayDetailDTO();
|
|
||||||
CalendarInstance restCalendarInstance = null;
|
|
||||||
CalendarInstance compoundingCalendarInstance = null;
|
|
||||||
RecalculationFrequencyType recalculationFrequencyType = null;
|
|
||||||
InterestRecalculationCompoundingMethod compoundingMethod = null;
|
|
||||||
RecalculationFrequencyType compoundingFrequencyType = null;
|
|
||||||
LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
|
||||||
CalendarHistoryDataWrapper calendarHistoryDataWrapper;
|
|
||||||
RepaymentStartDateType repaymentStartDateType = this.getLoanProduct().getRepaymentStartDateType();
|
|
||||||
boolean allowCompoundingOnEod = false;
|
|
||||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
|
||||||
restCalendarInstance = scheduleGeneratorDTO.getCalendarInstanceForInterestRecalculation();
|
|
||||||
compoundingCalendarInstance = scheduleGeneratorDTO.getCompoundingCalendarInstance();
|
|
||||||
recalculationFrequencyType = this.loanInterestRecalculationDetails.getRestFrequencyType();
|
|
||||||
compoundingMethod = this.loanInterestRecalculationDetails.getInterestRecalculationCompoundingMethod();
|
|
||||||
compoundingFrequencyType = this.loanInterestRecalculationDetails.getCompoundingFrequencyType();
|
|
||||||
rescheduleStrategyMethod = this.loanInterestRecalculationDetails.getRescheduleStrategyMethod();
|
|
||||||
allowCompoundingOnEod = this.loanInterestRecalculationDetails.allowCompoundingOnEod();
|
|
||||||
}
|
|
||||||
calendar = scheduleGeneratorDTO.getCalendar();
|
|
||||||
calendarHistoryDataWrapper = scheduleGeneratorDTO.getCalendarHistoryDataWrapper();
|
|
||||||
|
|
||||||
BigDecimal annualNominalInterestRate = this.loanRepaymentScheduleDetail.getAnnualNominalInterestRate();
|
|
||||||
FloatingRateDTO floatingRateDTO = scheduleGeneratorDTO.getFloatingRateDTO();
|
|
||||||
List<LoanTermVariationsData> loanTermVariations = new ArrayList<>();
|
|
||||||
annualNominalInterestRate = constructLoanTermVariations(floatingRateDTO, annualNominalInterestRate, loanTermVariations);
|
|
||||||
LocalDate interestChargedFromDate = getInterestChargedFromDate();
|
|
||||||
if (interestChargedFromDate == null && scheduleGeneratorDTO.isInterestChargedFromDateAsDisbursementDateEnabled()) {
|
|
||||||
interestChargedFromDate = getDisbursementDate();
|
|
||||||
}
|
|
||||||
|
|
||||||
return LoanApplicationTerms.assembleFrom(scheduleGeneratorDTO.getCurrency(), loanTermFrequency, this.termPeriodFrequencyType,
|
|
||||||
nthDayType, dayOfWeekType, getDisbursementDate(), getExpectedFirstRepaymentOnDate(),
|
|
||||||
scheduleGeneratorDTO.getCalculatedRepaymentsStartingFromDate(), getInArrearsTolerance(), this.loanRepaymentScheduleDetail,
|
|
||||||
this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount, disbursementData, this.maxOutstandingLoanBalance,
|
|
||||||
interestChargedFromDate, this.loanProduct.getPrincipalThresholdForLastInstallment(),
|
|
||||||
this.loanProduct.getInstallmentAmountInMultiplesOf(), recalculationFrequencyType, restCalendarInstance, compoundingMethod,
|
|
||||||
compoundingCalendarInstance, compoundingFrequencyType, this.loanProduct.preCloseInterestCalculationStrategy(),
|
|
||||||
rescheduleStrategyMethod, calendar, getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations,
|
|
||||||
calendarHistoryDataWrapper, scheduleGeneratorDTO.getNumberOfdays(), scheduleGeneratorDTO.isSkipRepaymentOnFirstDayofMonth(),
|
|
||||||
holidayDetailDTO, allowCompoundingOnEod, scheduleGeneratorDTO.isFirstRepaymentDateAllowedOnHoliday(),
|
|
||||||
scheduleGeneratorDTO.isInterestToBeRecoveredFirstWhenGreaterThanEMI(), this.fixedPrincipalPercentagePerInstallment,
|
|
||||||
scheduleGeneratorDTO.isPrincipalCompoundingDisabledForOverdueLoans(), repaymentStartDateType, getSubmittedOnDate());
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigDecimal constructLoanTermVariations(FloatingRateDTO floatingRateDTO, BigDecimal annualNominalInterestRate,
|
|
||||||
List<LoanTermVariationsData> loanTermVariations) {
|
|
||||||
for (LoanTermVariations variationTerms : this.loanTermVariations) {
|
|
||||||
if (variationTerms.isActive()) {
|
|
||||||
loanTermVariations.add(variationTerms.toData());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
annualNominalInterestRate = constructFloatingInterestRates(annualNominalInterestRate, floatingRateDTO, loanTermVariations);
|
|
||||||
return annualNominalInterestRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LocalDate fetchInterestRecalculateFromDate() {
|
public LocalDate fetchInterestRecalculateFromDate() {
|
||||||
LocalDate recalculatedOn;
|
LocalDate recalculatedOn;
|
||||||
if (this.interestRecalculatedOn == null) {
|
if (this.interestRecalculatedOn == null) {
|
||||||
@@ -2602,7 +2223,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
Money transactionOutstanding = loanTransaction.getPrincipalPortion(getCurrency());
|
Money transactionOutstanding = loanTransaction.getPrincipalPortion(getCurrency());
|
||||||
if (loanTransaction.isOverPaid()) {
|
if (loanTransaction.isOverPaid()) {
|
||||||
// in case of advanced payment strategy and creditAllocations the full amount is recognized first
|
// in case of advanced payment strategy and creditAllocations the full amount is recognized first
|
||||||
if (this.getCreditAllocationRules() != null && this.getCreditAllocationRules().size() > 0) {
|
if (this.getCreditAllocationRules() != null && !this.getCreditAllocationRules().isEmpty()) {
|
||||||
Money payedPrincipal = loanTransaction.getLoanTransactionToRepaymentScheduleMappings().stream() //
|
Money payedPrincipal = loanTransaction.getLoanTransactionToRepaymentScheduleMappings().stream() //
|
||||||
.map(mapping -> mapping.getPrincipalPortion(getCurrency())) //
|
.map(mapping -> mapping.getPrincipalPortion(getCurrency())) //
|
||||||
.reduce(Money.zero(getCurrency()), Money::plus);
|
.reduce(Money.zero(getCurrency()), Money::plus);
|
||||||
@@ -2690,137 +2311,6 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
return getRepaymentScheduleInstallments().stream().filter(predicate).toList();
|
return getRepaymentScheduleInstallments().stream().filter(predicate).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return loan disbursement data
|
|
||||||
**/
|
|
||||||
public List<DisbursementData> getDisbursementData() {
|
|
||||||
Iterator<LoanDisbursementDetails> iterator = this.getDisbursementDetails().iterator();
|
|
||||||
List<DisbursementData> disbursementData = new ArrayList<>();
|
|
||||||
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
LoanDisbursementDetails loanDisbursementDetails = iterator.next();
|
|
||||||
|
|
||||||
LocalDate expectedDisbursementDate = null;
|
|
||||||
LocalDate actualDisbursementDate = null;
|
|
||||||
|
|
||||||
if (loanDisbursementDetails.expectedDisbursementDate() != null) {
|
|
||||||
expectedDisbursementDate = loanDisbursementDetails.expectedDisbursementDate();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (loanDisbursementDetails.actualDisbursementDate() != null) {
|
|
||||||
actualDisbursementDate = loanDisbursementDetails.actualDisbursementDate();
|
|
||||||
}
|
|
||||||
BigDecimal waivedChargeAmount = null;
|
|
||||||
disbursementData.add(new DisbursementData(loanDisbursementDetails.getId(), expectedDisbursementDate, actualDisbursementDate,
|
|
||||||
loanDisbursementDetails.principal(), this.netDisbursalAmount, null, null, waivedChargeAmount));
|
|
||||||
}
|
|
||||||
|
|
||||||
return disbursementData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return application terms of the Loan object
|
|
||||||
**/
|
|
||||||
@SuppressWarnings({ "unused" })
|
|
||||||
public LoanApplicationTerms getLoanApplicationTerms(final ApplicationCurrency applicationCurrency,
|
|
||||||
final CalendarInstance restCalendarInstance, CalendarInstance compoundingCalendarInstance, final Calendar loanCalendar,
|
|
||||||
final FloatingRateDTO floatingRateDTO, final boolean isSkipRepaymentonmonthFirst, final Integer numberofdays,
|
|
||||||
final HolidayDetailDTO holidayDetailDTO) {
|
|
||||||
LoanProduct loanProduct = loanProduct();
|
|
||||||
final MonetaryCurrency currency = this.loanRepaymentScheduleDetail.getCurrency();
|
|
||||||
|
|
||||||
final Integer loanTermFrequency = getTermFrequency();
|
|
||||||
final PeriodFrequencyType loanTermPeriodFrequencyType = this.loanRepaymentScheduleDetail.getInterestPeriodFrequencyType();
|
|
||||||
NthDayType nthDayType = null;
|
|
||||||
DayOfWeekType dayOfWeekType = null;
|
|
||||||
if (loanCalendar != null) {
|
|
||||||
nthDayType = CalendarUtils.getRepeatsOnNthDayOfMonth(loanCalendar.getRecurrence());
|
|
||||||
CalendarWeekDaysType getRepeatsOnDay = CalendarUtils.getRepeatsOnDay(loanCalendar.getRecurrence());
|
|
||||||
Integer getRepeatsOnDayValue = null;
|
|
||||||
if (getRepeatsOnDay != null) {
|
|
||||||
getRepeatsOnDayValue = getRepeatsOnDay.getValue();
|
|
||||||
}
|
|
||||||
if (getRepeatsOnDayValue != null) {
|
|
||||||
dayOfWeekType = DayOfWeekType.fromInt(getRepeatsOnDayValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final Integer numberOfRepayments = this.loanRepaymentScheduleDetail.getNumberOfRepayments();
|
|
||||||
final Integer repaymentEvery = this.loanRepaymentScheduleDetail.getRepayEvery();
|
|
||||||
final PeriodFrequencyType repaymentPeriodFrequencyType = this.loanRepaymentScheduleDetail.getRepaymentPeriodFrequencyType();
|
|
||||||
|
|
||||||
final AmortizationMethod amortizationMethod = this.loanRepaymentScheduleDetail.getAmortizationMethod();
|
|
||||||
|
|
||||||
final InterestMethod interestMethod = this.loanRepaymentScheduleDetail.getInterestMethod();
|
|
||||||
final InterestCalculationPeriodMethod interestCalculationPeriodMethod = this.loanRepaymentScheduleDetail
|
|
||||||
.getInterestCalculationPeriodMethod();
|
|
||||||
|
|
||||||
final BigDecimal interestRatePerPeriod = this.loanRepaymentScheduleDetail.getNominalInterestRatePerPeriod();
|
|
||||||
final PeriodFrequencyType interestRatePeriodFrequencyType = this.loanRepaymentScheduleDetail.getInterestPeriodFrequencyType();
|
|
||||||
|
|
||||||
BigDecimal annualNominalInterestRate = this.loanRepaymentScheduleDetail.getAnnualNominalInterestRate();
|
|
||||||
final Money principalMoney = this.loanRepaymentScheduleDetail.getPrincipal();
|
|
||||||
|
|
||||||
final LocalDate expectedDisbursementDate = getExpectedDisbursedOnLocalDate();
|
|
||||||
final LocalDate repaymentsStartingFromDate = getExpectedFirstRepaymentOnDate();
|
|
||||||
LocalDate calculatedRepaymentsStartingFromDate = repaymentsStartingFromDate;
|
|
||||||
|
|
||||||
// TODO get calender linked to loan if any exist. As of 17-07-2014,
|
|
||||||
// could not find a link in the database.
|
|
||||||
// skip for now and set the Calender object to null
|
|
||||||
// Calendar loanCalendar = null;
|
|
||||||
// The calendar instance might be null if the loan is not connected
|
|
||||||
// To a calendar object
|
|
||||||
// if (loanCalendarInstance != null) {
|
|
||||||
// loanCalendar = loanCalendarInstance.getCalendar();
|
|
||||||
// }
|
|
||||||
|
|
||||||
final Integer graceOnPrincipalPayment = this.loanRepaymentScheduleDetail.getGraceOnPrincipalPayment();
|
|
||||||
final Integer graceOnInterestPayment = this.loanRepaymentScheduleDetail.getGraceOnInterestPayment();
|
|
||||||
final Integer graceOnInterestCharged = this.loanRepaymentScheduleDetail.getGraceOnInterestCharged();
|
|
||||||
final LocalDate interestChargedFromDate = getInterestChargedFromDate();
|
|
||||||
final Integer graceOnArrearsAgeing = this.loanRepaymentScheduleDetail.getGraceOnArrearsAgeing();
|
|
||||||
|
|
||||||
final Money inArrearsToleranceMoney = this.loanRepaymentScheduleDetail.getInArrearsTolerance();
|
|
||||||
final BigDecimal emiAmount = getFixedEmiAmount();
|
|
||||||
final BigDecimal maxOutstandingBalance = getMaxOutstandingLoanBalance();
|
|
||||||
|
|
||||||
final List<DisbursementData> disbursementData = getDisbursementData();
|
|
||||||
|
|
||||||
CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
|
|
||||||
if (loanCalendar != null) {
|
|
||||||
Set<CalendarHistory> calendarHistory = loanCalendar.getCalendarHistory();
|
|
||||||
calendarHistoryDataWrapper = new CalendarHistoryDataWrapper(calendarHistory);
|
|
||||||
}
|
|
||||||
|
|
||||||
RecalculationFrequencyType recalculationFrequencyType = null;
|
|
||||||
InterestRecalculationCompoundingMethod compoundingMethod = null;
|
|
||||||
RecalculationFrequencyType compoundingFrequencyType = null;
|
|
||||||
LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
|
||||||
RepaymentStartDateType repaymentStartDateType = loanProduct.getRepaymentStartDateType();
|
|
||||||
boolean allowCompoundingOnEod = false;
|
|
||||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
|
||||||
recalculationFrequencyType = this.loanInterestRecalculationDetails.getRestFrequencyType();
|
|
||||||
compoundingMethod = this.loanInterestRecalculationDetails.getInterestRecalculationCompoundingMethod();
|
|
||||||
compoundingFrequencyType = this.loanInterestRecalculationDetails.getCompoundingFrequencyType();
|
|
||||||
rescheduleStrategyMethod = this.loanInterestRecalculationDetails.getRescheduleStrategyMethod();
|
|
||||||
allowCompoundingOnEod = this.loanInterestRecalculationDetails.allowCompoundingOnEod();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<LoanTermVariationsData> loanTermVariations = new ArrayList<>();
|
|
||||||
annualNominalInterestRate = constructFloatingInterestRates(annualNominalInterestRate, floatingRateDTO, loanTermVariations);
|
|
||||||
|
|
||||||
return LoanApplicationTerms.assembleFrom(applicationCurrency.toData(), loanTermFrequency, loanTermPeriodFrequencyType, nthDayType,
|
|
||||||
dayOfWeekType, expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate,
|
|
||||||
inArrearsToleranceMoney, this.loanRepaymentScheduleDetail, loanProduct.isMultiDisburseLoan(), emiAmount, disbursementData,
|
|
||||||
maxOutstandingBalance, interestChargedFromDate, this.loanProduct.getPrincipalThresholdForLastInstallment(),
|
|
||||||
this.loanProduct.getInstallmentAmountInMultiplesOf(), recalculationFrequencyType, restCalendarInstance, compoundingMethod,
|
|
||||||
compoundingCalendarInstance, compoundingFrequencyType, this.loanProduct.preCloseInterestCalculationStrategy(),
|
|
||||||
rescheduleStrategyMethod, loanCalendar, getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations,
|
|
||||||
calendarHistoryDataWrapper, numberofdays, isSkipRepaymentonmonthFirst, holidayDetailDTO, allowCompoundingOnEod, false,
|
|
||||||
false, this.fixedPrincipalPercentagePerInstallment, false, repaymentStartDateType, getSubmittedOnDate());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateRescheduledByUser(AppUser rescheduledByUser) {
|
public void updateRescheduledByUser(AppUser rescheduledByUser) {
|
||||||
this.rescheduledByUser = rescheduledByUser;
|
this.rescheduledByUser = rescheduledByUser;
|
||||||
}
|
}
|
||||||
@@ -2993,7 +2483,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public LoanRepaymentScheduleInstallment fetchLoanForeclosureDetail(final LocalDate closureDate) {
|
public LoanRepaymentScheduleInstallment fetchLoanForeclosureDetail(final LocalDate closureDate) {
|
||||||
Money[] receivables = retriveIncomeOutstandingTillDate(closureDate);
|
Money[] receivables = retrieveIncomeOutstandingTillDate(closureDate);
|
||||||
Money totalPrincipal = Money.of(getCurrency(), this.getSummary().getTotalPrincipalOutstanding());
|
Money totalPrincipal = Money.of(getCurrency(), this.getSummary().getTotalPrincipalOutstanding());
|
||||||
totalPrincipal = totalPrincipal.minus(receivables[3]);
|
totalPrincipal = totalPrincipal.minus(receivables[3]);
|
||||||
final Set<LoanInterestRecalcualtionAdditionalDetails> compoundingDetails = null;
|
final Set<LoanInterestRecalcualtionAdditionalDetails> compoundingDetails = null;
|
||||||
@@ -3002,7 +2492,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
receivables[0].getAmount(), receivables[1].getAmount(), receivables[2].getAmount(), false, compoundingDetails);
|
receivables[0].getAmount(), receivables[1].getAmount(), receivables[2].getAmount(), false, compoundingDetails);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money[] retriveIncomeOutstandingTillDate(final LocalDate paymentDate) {
|
private Money[] retrieveIncomeOutstandingTillDate(final LocalDate paymentDate) {
|
||||||
Money[] balances = new Money[4];
|
Money[] balances = new Money[4];
|
||||||
final MonetaryCurrency currency = getCurrency();
|
final MonetaryCurrency currency = getCurrency();
|
||||||
Money interest = Money.zero(currency);
|
Money interest = Money.zero(currency);
|
||||||
@@ -3058,13 +2548,12 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
Money penaltyAccoutedForCurrentPeriod = Money.zero(getCurrency());
|
Money penaltyAccoutedForCurrentPeriod = Money.zero(getCurrency());
|
||||||
Money feeForCurrentPeriod = Money.zero(getCurrency());
|
Money feeForCurrentPeriod = Money.zero(getCurrency());
|
||||||
Money feeAccountedForCurrentPeriod = Money.zero(getCurrency());
|
Money feeAccountedForCurrentPeriod = Money.zero(getCurrency());
|
||||||
Money interestForCurrentPeriod = Money.zero(getCurrency());
|
|
||||||
Money interestAccountedForCurrentPeriod = Money.zero(getCurrency());
|
|
||||||
int totalPeriodDays = DateUtils.getExactDifferenceInDays(installment.getFromDate(), installment.getDueDate());
|
int totalPeriodDays = DateUtils.getExactDifferenceInDays(installment.getFromDate(), installment.getDueDate());
|
||||||
int tillDays = DateUtils.getExactDifferenceInDays(installment.getFromDate(), paymentDate);
|
int tillDays = DateUtils.getExactDifferenceInDays(installment.getFromDate(), paymentDate);
|
||||||
interestForCurrentPeriod = Money.of(getCurrency(), BigDecimal
|
Money interestForCurrentPeriod = Money.of(getCurrency(), BigDecimal
|
||||||
.valueOf(calculateInterestForDays(totalPeriodDays, installment.getInterestCharged(getCurrency()).getAmount(), tillDays)));
|
.valueOf(calculateInterestForDays(totalPeriodDays, installment.getInterestCharged(getCurrency()).getAmount(), tillDays)));
|
||||||
interestAccountedForCurrentPeriod = installment.getInterestWaived(getCurrency()).plus(installment.getInterestPaid(getCurrency()));
|
Money interestAccountedForCurrentPeriod = installment.getInterestWaived(getCurrency())
|
||||||
|
.plus(installment.getInterestPaid(getCurrency()));
|
||||||
for (LoanCharge loanCharge : this.charges) {
|
for (LoanCharge loanCharge : this.charges) {
|
||||||
if (loanCharge.isActive() && !loanCharge.isDueAtDisbursement()) {
|
if (loanCharge.isActive() && !loanCharge.isDueAtDisbursement()) {
|
||||||
boolean isDue = loanCharge.isDueInPeriod(installment.getFromDate(), paymentDate, isFirstNormalInstallment);
|
boolean isDue = loanCharge.isDueInPeriod(installment.getFromDate(), paymentDate, isFirstNormalInstallment);
|
||||||
@@ -3101,7 +2590,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
return balances;
|
return balances;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money[] retriveIncomeForOverlappingPeriod(final LocalDate paymentDate) {
|
public Money[] retrieveIncomeForOverlappingPeriod(final LocalDate paymentDate) {
|
||||||
Money[] balances = new Money[3];
|
Money[] balances = new Money[3];
|
||||||
final MonetaryCurrency currency = getCurrency();
|
final MonetaryCurrency currency = getCurrency();
|
||||||
balances[0] = balances[1] = balances[2] = Money.zero(currency);
|
balances[0] = balances[1] = balances[2] = Money.zero(currency);
|
||||||
@@ -3165,19 +2654,6 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
this.fraud = value;
|
this.fraud = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BigDecimal getFirstDisbursalAmount() {
|
|
||||||
BigDecimal firstDisbursalAmount;
|
|
||||||
|
|
||||||
if (this.isMultiDisburmentLoan()) {
|
|
||||||
List<DisbursementData> disbursementData = getDisbursementData();
|
|
||||||
Collections.sort(disbursementData);
|
|
||||||
firstDisbursalAmount = disbursementData.get(disbursementData.size() - 1).getPrincipal();
|
|
||||||
} else {
|
|
||||||
firstDisbursalAmount = this.getLoanRepaymentScheduleDetail().getPrincipal().getAmount();
|
|
||||||
}
|
|
||||||
return firstDisbursalAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTopupLoanDetails(LoanTopupDetails topupLoanDetails) {
|
public void setTopupLoanDetails(LoanTopupDetails topupLoanDetails) {
|
||||||
this.loanTopupDetails = topupLoanDetails;
|
this.loanTopupDetails = topupLoanDetails;
|
||||||
}
|
}
|
||||||
|
|||||||
+251
@@ -0,0 +1,251 @@
|
|||||||
|
/**
|
||||||
|
* 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.mapper;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.data.AccountingBridgeDataDTO;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.data.AccountingBridgeLoanTransactionDTO;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.data.LoanChargePaidByDTO;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanChargePaidBy;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelation;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelationTypeEnum;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class LoanAccountingBridgeMapper {
|
||||||
|
|
||||||
|
public List<AccountingBridgeDataDTO> deriveAccountingBridgeDataForChargeOff(final String currencyCode,
|
||||||
|
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds, final boolean isAccountTransfer,
|
||||||
|
final Loan loan) {
|
||||||
|
final List<AccountingBridgeLoanTransactionDTO> newLoanTransactionsBeforeChargeOff = new ArrayList<>();
|
||||||
|
final List<AccountingBridgeLoanTransactionDTO> newLoanTransactionsAfterChargeOff = new ArrayList<>();
|
||||||
|
|
||||||
|
// split the transactions according charge-off date
|
||||||
|
classifyTransactionsBasedOnChargeOffDate(newLoanTransactionsBeforeChargeOff, newLoanTransactionsAfterChargeOff,
|
||||||
|
existingTransactionIds, existingReversedTransactionIds, currencyCode, loan);
|
||||||
|
|
||||||
|
AccountingBridgeDataDTO beforeChargeOff = new AccountingBridgeDataDTO(loan.getId(), loan.productId(), loan.getOfficeId(),
|
||||||
|
currencyCode, loan.getSummary().getTotalInterestCharged(), loan.isCashBasedAccountingEnabledOnLoanProduct(),
|
||||||
|
loan.isUpfrontAccrualAccountingEnabledOnLoanProduct(), loan.isPeriodicAccrualAccountingEnabledOnLoanProduct(),
|
||||||
|
isAccountTransfer, false, loan.isFraud(), loan.fetchChargeOffReasonId(), newLoanTransactionsBeforeChargeOff);
|
||||||
|
|
||||||
|
AccountingBridgeDataDTO afterChargeOff = new AccountingBridgeDataDTO(loan.getId(), loan.productId(), loan.getOfficeId(),
|
||||||
|
currencyCode, loan.getSummary().getTotalInterestCharged(), loan.isCashBasedAccountingEnabledOnLoanProduct(),
|
||||||
|
loan.isUpfrontAccrualAccountingEnabledOnLoanProduct(), loan.isPeriodicAccrualAccountingEnabledOnLoanProduct(),
|
||||||
|
isAccountTransfer, true, loan.isFraud(), loan.fetchChargeOffReasonId(), newLoanTransactionsAfterChargeOff);
|
||||||
|
|
||||||
|
List<AccountingBridgeDataDTO> result = new ArrayList<>();
|
||||||
|
result.add(beforeChargeOff);
|
||||||
|
result.add(afterChargeOff);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccountingBridgeDataDTO deriveAccountingBridgeData(final String currencyCode, final List<Long> existingTransactionIds,
|
||||||
|
final List<Long> existingReversedTransactionIds, final boolean isAccountTransfer, final Loan loan) {
|
||||||
|
final List<AccountingBridgeLoanTransactionDTO> newLoanTransactions = new ArrayList<>();
|
||||||
|
for (final LoanTransaction transaction : loan.getLoanTransactions()) {
|
||||||
|
if (transaction.isReversed() && existingTransactionIds.contains(transaction.getId())
|
||||||
|
&& !existingReversedTransactionIds.contains(transaction.getId())) {
|
||||||
|
newLoanTransactions.add(mapToLoanTransactionData(transaction, currencyCode));
|
||||||
|
} else if (!existingTransactionIds.contains(transaction.getId())) {
|
||||||
|
newLoanTransactions.add(mapToLoanTransactionData(transaction, currencyCode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AccountingBridgeDataDTO(loan.getId(), loan.productId(), loan.getOfficeId(), currencyCode,
|
||||||
|
loan.getSummary().getTotalInterestCharged(), loan.isCashBasedAccountingEnabledOnLoanProduct(),
|
||||||
|
loan.isUpfrontAccrualAccountingEnabledOnLoanProduct(), loan.isPeriodicAccrualAccountingEnabledOnLoanProduct(),
|
||||||
|
isAccountTransfer, loan.isChargedOff(), loan.isFraud(), loan.fetchChargeOffReasonId(), newLoanTransactions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccountingBridgeLoanTransactionDTO mapToLoanTransactionData(final LoanTransaction transaction, final String currencyCode) {
|
||||||
|
final AccountingBridgeLoanTransactionDTO transactionDTO = new AccountingBridgeLoanTransactionDTO();
|
||||||
|
|
||||||
|
transactionDTO.setId(transaction.getId());
|
||||||
|
transactionDTO.setOfficeId(transaction.getOffice().getId());
|
||||||
|
transactionDTO.setType(LoanEnumerations.transactionType(transaction.getTypeOf()));
|
||||||
|
transactionDTO.setReversed(transaction.isReversed());
|
||||||
|
transactionDTO.setDate(transaction.getTransactionDate());
|
||||||
|
transactionDTO.setCurrencyCode(currencyCode);
|
||||||
|
transactionDTO.setAmount(transaction.getAmount());
|
||||||
|
transactionDTO.setNetDisbursalAmount(transaction.getLoan().getNetDisbursalAmount());
|
||||||
|
|
||||||
|
if (transactionDTO.getType().isChargeback() && (transaction.getLoan().getCreditAllocationRules() == null
|
||||||
|
|| transaction.getLoan().getCreditAllocationRules().isEmpty())) {
|
||||||
|
transactionDTO.setPrincipalPortion(transaction.getAmount());
|
||||||
|
} else {
|
||||||
|
transactionDTO.setPrincipalPortion(transaction.getPrincipalPortion());
|
||||||
|
}
|
||||||
|
|
||||||
|
transactionDTO.setInterestPortion(transaction.getInterestPortion());
|
||||||
|
transactionDTO.setFeeChargesPortion(transaction.getFeeChargesPortion());
|
||||||
|
transactionDTO.setPenaltyChargesPortion(transaction.getPenaltyChargesPortion());
|
||||||
|
transactionDTO.setOverPaymentPortion(transaction.getOverPaymentPortion());
|
||||||
|
|
||||||
|
if (transactionDTO.getType().isChargeRefund()) {
|
||||||
|
transactionDTO.setChargeRefundChargeType(transaction.getChargeRefundChargeType());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transaction.getPaymentDetail() != null) {
|
||||||
|
transactionDTO.setPaymentTypeId(transaction.getPaymentDetail().getPaymentType().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!transaction.getLoanChargesPaid().isEmpty()) {
|
||||||
|
List<LoanChargePaidByDTO> loanChargesPaidData = new ArrayList<>();
|
||||||
|
for (final LoanChargePaidBy chargePaidBy : transaction.getLoanChargesPaid()) {
|
||||||
|
final LoanChargePaidByDTO loanChargePaidData = new LoanChargePaidByDTO();
|
||||||
|
loanChargePaidData.setChargeId(chargePaidBy.getLoanCharge().getCharge().getId());
|
||||||
|
loanChargePaidData.setIsPenalty(chargePaidBy.getLoanCharge().isPenaltyCharge());
|
||||||
|
loanChargePaidData.setLoanChargeId(chargePaidBy.getLoanCharge().getId());
|
||||||
|
loanChargePaidData.setAmount(chargePaidBy.getAmount());
|
||||||
|
loanChargePaidData.setInstallmentNumber(chargePaidBy.getInstallmentNumber());
|
||||||
|
|
||||||
|
loanChargesPaidData.add(loanChargePaidData);
|
||||||
|
}
|
||||||
|
transactionDTO.setLoanChargesPaid(loanChargesPaidData);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transactionDTO.getType().isChargeback() && transaction.getOverPaymentPortion() != null
|
||||||
|
&& transaction.getOverPaymentPortion().compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
BigDecimal principalPaid = transaction.getOverPaymentPortion();
|
||||||
|
BigDecimal feePaid = BigDecimal.ZERO;
|
||||||
|
BigDecimal penaltyPaid = BigDecimal.ZERO;
|
||||||
|
if (!transaction.getLoanTransactionToRepaymentScheduleMappings().isEmpty()) {
|
||||||
|
principalPaid = transaction.getLoanTransactionToRepaymentScheduleMappings().stream()
|
||||||
|
.map(mapping -> Optional.ofNullable(mapping.getPrincipalPortion()).orElse(BigDecimal.ZERO))
|
||||||
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||||
|
feePaid = transaction.getLoanTransactionToRepaymentScheduleMappings().stream()
|
||||||
|
.map(mapping -> Optional.ofNullable(mapping.getFeeChargesPortion()).orElse(BigDecimal.ZERO))
|
||||||
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||||
|
penaltyPaid = transaction.getLoanTransactionToRepaymentScheduleMappings().stream()
|
||||||
|
.map(mapping -> Optional.ofNullable(mapping.getPenaltyChargesPortion()).orElse(BigDecimal.ZERO))
|
||||||
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||||
|
}
|
||||||
|
transactionDTO.setPrincipalPaid(principalPaid);
|
||||||
|
transactionDTO.setFeePaid(feePaid);
|
||||||
|
transactionDTO.setPenaltyPaid(penaltyPaid);
|
||||||
|
}
|
||||||
|
|
||||||
|
LoanTransactionRelation loanTransactionRelation = transaction.getLoanTransactionRelations().stream()
|
||||||
|
.filter(e -> LoanTransactionRelationTypeEnum.CHARGE_ADJUSTMENT.equals(e.getRelationType())).findAny().orElse(null);
|
||||||
|
if (loanTransactionRelation != null) {
|
||||||
|
LoanCharge loanCharge = loanTransactionRelation.getToCharge();
|
||||||
|
transactionDTO.setLoanChargeData(loanCharge.toData());
|
||||||
|
}
|
||||||
|
|
||||||
|
transactionDTO.setLoanToLoanTransfer(false);
|
||||||
|
|
||||||
|
return transactionDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void classifyTransactionsBasedOnChargeOffDate(final List<AccountingBridgeLoanTransactionDTO> newLoanTransactionsBeforeChargeOff,
|
||||||
|
final List<AccountingBridgeLoanTransactionDTO> newLoanTransactionsAfterChargeOff, final List<Long> existingTransactionIds,
|
||||||
|
final List<Long> existingReversedTransactionIds, final String currencyCode, final Loan loan) {
|
||||||
|
// Before
|
||||||
|
filterTransactionsByChargeOffDate(newLoanTransactionsBeforeChargeOff, currencyCode, existingTransactionIds,
|
||||||
|
existingReversedTransactionIds,
|
||||||
|
transaction -> DateUtils.isBefore(transaction.getTransactionDate(), loan.getChargedOffOnDate()), loan);
|
||||||
|
// On
|
||||||
|
filterTransactionsByChargeOffDate(newLoanTransactionsBeforeChargeOff, newLoanTransactionsAfterChargeOff, currencyCode,
|
||||||
|
existingTransactionIds, existingReversedTransactionIds,
|
||||||
|
transaction -> DateUtils.isEqual(transaction.getTransactionDate(), loan.getChargedOffOnDate()), loan);
|
||||||
|
// After
|
||||||
|
filterTransactionsByChargeOffDate(newLoanTransactionsAfterChargeOff, currencyCode, existingTransactionIds,
|
||||||
|
existingReversedTransactionIds,
|
||||||
|
transaction -> DateUtils.isAfter(transaction.getTransactionDate(), loan.getChargedOffOnDate()), loan);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void filterTransactionsByChargeOffDate(final List<AccountingBridgeLoanTransactionDTO> filteredTransactions,
|
||||||
|
final String currencyCode, final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
|
||||||
|
final Predicate<LoanTransaction> chargeOffDateCriteria, final Loan loan) {
|
||||||
|
filteredTransactions.addAll(loan.getLoanTransactions().stream() //
|
||||||
|
.filter(chargeOffDateCriteria) //
|
||||||
|
.filter(transaction -> {
|
||||||
|
boolean isExistingTransaction = existingTransactionIds.contains(transaction.getId());
|
||||||
|
boolean isExistingReversedTransaction = existingReversedTransactionIds.contains(transaction.getId());
|
||||||
|
|
||||||
|
if (transaction.isReversed() && isExistingTransaction && !isExistingReversedTransaction) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return !isExistingTransaction;
|
||||||
|
}
|
||||||
|
}) //
|
||||||
|
.map(transaction -> mapToLoanTransactionData(transaction, currencyCode)).toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void filterTransactionsByChargeOffDate(final List<AccountingBridgeLoanTransactionDTO> newLoanTransactionsBeforeChargeOff,
|
||||||
|
final List<AccountingBridgeLoanTransactionDTO> newLoanTransactionsAfterChargeOff, final String currencyCode,
|
||||||
|
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
|
||||||
|
final Predicate<LoanTransaction> chargeOffDateCriteria, final Loan loan) {
|
||||||
|
final Optional<LoanTransaction> chargeOffTransactionOptional = loan.getLoanTransactions().stream() //
|
||||||
|
.filter(LoanTransaction::isChargeOff) //
|
||||||
|
.filter(LoanTransaction::isNotReversed) //
|
||||||
|
.findFirst();
|
||||||
|
|
||||||
|
if (chargeOffTransactionOptional.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final LoanTransaction chargeOffTransaction = chargeOffTransactionOptional.get();
|
||||||
|
final LoanTransaction originalChargeOffTransaction = getOriginalTransactionIfReverseReplayed(chargeOffTransaction);
|
||||||
|
|
||||||
|
loan.getLoanTransactions().stream().filter(chargeOffDateCriteria).forEach(transaction -> {
|
||||||
|
boolean isExistingTransaction = existingTransactionIds.contains(transaction.getId());
|
||||||
|
boolean isExistingReversedTransaction = existingReversedTransactionIds.contains(transaction.getId());
|
||||||
|
List<AccountingBridgeLoanTransactionDTO> targetList = null;
|
||||||
|
if ((transaction.isReversed() && isExistingTransaction && !isExistingReversedTransaction)) {
|
||||||
|
// reversed transactions
|
||||||
|
LoanTransaction originalTransaction = getOriginalTransactionIfReverseReplayed(transaction);
|
||||||
|
targetList = originalTransaction.happenedBefore(originalChargeOffTransaction) ? newLoanTransactionsBeforeChargeOff
|
||||||
|
: newLoanTransactionsAfterChargeOff;
|
||||||
|
|
||||||
|
} else if (!isExistingTransaction) {
|
||||||
|
// new and replayed transactions
|
||||||
|
targetList = transaction.happenedBefore(chargeOffTransaction) ? newLoanTransactionsBeforeChargeOff
|
||||||
|
: newLoanTransactionsAfterChargeOff;
|
||||||
|
}
|
||||||
|
if (targetList != null) {
|
||||||
|
targetList.add(mapToLoanTransactionData(transaction, currencyCode));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoanTransaction getOriginalTransactionIfReverseReplayed(final LoanTransaction loanTransaction) {
|
||||||
|
if (!loanTransaction.getLoanTransactionRelations().isEmpty()) {
|
||||||
|
return loanTransaction.getLoanTransactionRelations().stream()
|
||||||
|
.filter(tr -> LoanTransactionRelationTypeEnum.REPLAYED.equals(tr.getRelationType()))
|
||||||
|
.map(LoanTransactionRelation::getToTransaction).toList().stream().min(Comparator.comparingLong(LoanTransaction::getId))
|
||||||
|
.orElse(loanTransaction);
|
||||||
|
}
|
||||||
|
return loanTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+102
@@ -0,0 +1,102 @@
|
|||||||
|
/**
|
||||||
|
* 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.mapper;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.MathContext;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||||
|
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.data.DisbursementData;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class LoanMapper {
|
||||||
|
|
||||||
|
private final LoanTermVariationsMapper loanTermVariationsMapper;
|
||||||
|
|
||||||
|
public LoanScheduleModel regenerateScheduleModel(final ScheduleGeneratorDTO scheduleGeneratorDTO, final Loan loan) {
|
||||||
|
final MathContext mc = MoneyHelper.getMathContext();
|
||||||
|
|
||||||
|
final LoanApplicationTerms loanApplicationTerms = loanTermVariationsMapper.constructLoanApplicationTerms(scheduleGeneratorDTO,
|
||||||
|
loan);
|
||||||
|
LoanScheduleGenerator loanScheduleGenerator;
|
||||||
|
if (loanApplicationTerms.isEqualAmortization()) {
|
||||||
|
if (loanApplicationTerms.getInterestMethod().isDecliningBalance()) {
|
||||||
|
final LoanScheduleGenerator decliningLoanScheduleGenerator = scheduleGeneratorDTO.getLoanScheduleFactory()
|
||||||
|
.create(loanApplicationTerms.getLoanScheduleType(), InterestMethod.DECLINING_BALANCE);
|
||||||
|
Set<LoanCharge> loanCharges = loan.getActiveCharges();
|
||||||
|
LoanScheduleModel loanSchedule = decliningLoanScheduleGenerator.generate(mc, loanApplicationTerms, loanCharges,
|
||||||
|
scheduleGeneratorDTO.getHolidayDetailDTO());
|
||||||
|
|
||||||
|
loanApplicationTerms
|
||||||
|
.updateTotalInterestDue(Money.of(loanApplicationTerms.getCurrency(), loanSchedule.getTotalInterestCharged()));
|
||||||
|
|
||||||
|
}
|
||||||
|
loanScheduleGenerator = scheduleGeneratorDTO.getLoanScheduleFactory().create(loanApplicationTerms.getLoanScheduleType(),
|
||||||
|
InterestMethod.FLAT);
|
||||||
|
} else {
|
||||||
|
loanScheduleGenerator = scheduleGeneratorDTO.getLoanScheduleFactory().create(loanApplicationTerms.getLoanScheduleType(),
|
||||||
|
loanApplicationTerms.getInterestMethod());
|
||||||
|
}
|
||||||
|
|
||||||
|
return loanScheduleGenerator.generate(mc, loanApplicationTerms, loan.getActiveCharges(),
|
||||||
|
scheduleGeneratorDTO.getHolidayDetailDTO());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DisbursementData> getDisbursementData(final Loan loan) {
|
||||||
|
Iterator<LoanDisbursementDetails> iterator = loan.getDisbursementDetails().iterator();
|
||||||
|
List<DisbursementData> disbursementData = new ArrayList<>();
|
||||||
|
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
LoanDisbursementDetails loanDisbursementDetails = iterator.next();
|
||||||
|
|
||||||
|
LocalDate expectedDisbursementDate = null;
|
||||||
|
LocalDate actualDisbursementDate = null;
|
||||||
|
|
||||||
|
if (loanDisbursementDetails.expectedDisbursementDate() != null) {
|
||||||
|
expectedDisbursementDate = loanDisbursementDetails.expectedDisbursementDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loanDisbursementDetails.actualDisbursementDate() != null) {
|
||||||
|
actualDisbursementDate = loanDisbursementDetails.actualDisbursementDate();
|
||||||
|
}
|
||||||
|
BigDecimal waivedChargeAmount = null;
|
||||||
|
disbursementData.add(new DisbursementData(loanDisbursementDetails.getId(), expectedDisbursementDate, actualDisbursementDate,
|
||||||
|
loanDisbursementDetails.principal(), loan.getNetDisbursalAmount(), null, null, waivedChargeAmount));
|
||||||
|
}
|
||||||
|
|
||||||
|
return disbursementData;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+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.mapper;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
import org.apache.fineract.portfolio.calendar.data.CalendarHistoryDataWrapper;
|
||||||
|
import org.apache.fineract.portfolio.calendar.domain.Calendar;
|
||||||
|
import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
|
||||||
|
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
|
||||||
|
import org.apache.fineract.portfolio.common.domain.DayOfWeekType;
|
||||||
|
import org.apache.fineract.portfolio.common.domain.NthDayType;
|
||||||
|
import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO;
|
||||||
|
import org.apache.fineract.portfolio.floatingrates.data.FloatingRatePeriodData;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.data.DisbursementData;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariationType;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariations;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.domain.RepaymentStartDateType;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class LoanTermVariationsMapper {
|
||||||
|
|
||||||
|
public BigDecimal constructLoanTermVariations(final FloatingRateDTO floatingRateDTO, final BigDecimal annualNominalInterestRate,
|
||||||
|
final List<LoanTermVariationsData> loanTermVariations, final Loan loan) {
|
||||||
|
for (LoanTermVariations variationTerms : loan.getLoanTermVariations()) {
|
||||||
|
if (variationTerms.isActive()) {
|
||||||
|
loanTermVariations.add(variationTerms.toData());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return constructFloatingInterestRates(annualNominalInterestRate, floatingRateDTO, loanTermVariations, loan);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoanApplicationTerms constructLoanApplicationTerms(final ScheduleGeneratorDTO scheduleGeneratorDTO, final Loan loan) {
|
||||||
|
final Integer loanTermFrequency = loan.getTermFrequency();
|
||||||
|
NthDayType nthDayType = null;
|
||||||
|
DayOfWeekType dayOfWeekType = null;
|
||||||
|
final List<DisbursementData> disbursementData = new ArrayList<>();
|
||||||
|
for (LoanDisbursementDetails disbursementDetails : loan.getDisbursementDetails()) {
|
||||||
|
disbursementData.add(disbursementDetails.toData());
|
||||||
|
}
|
||||||
|
|
||||||
|
Calendar calendar = scheduleGeneratorDTO.getCalendar();
|
||||||
|
if (calendar != null) {
|
||||||
|
nthDayType = CalendarUtils.getRepeatsOnNthDayOfMonth(calendar.getRecurrence());
|
||||||
|
dayOfWeekType = DayOfWeekType.fromInt(CalendarUtils.getRepeatsOnDay(calendar.getRecurrence()).getValue());
|
||||||
|
}
|
||||||
|
HolidayDetailDTO holidayDetailDTO = scheduleGeneratorDTO.getHolidayDetailDTO();
|
||||||
|
CalendarInstance restCalendarInstance = null;
|
||||||
|
CalendarInstance compoundingCalendarInstance = null;
|
||||||
|
RecalculationFrequencyType recalculationFrequencyType = null;
|
||||||
|
InterestRecalculationCompoundingMethod compoundingMethod = null;
|
||||||
|
RecalculationFrequencyType compoundingFrequencyType = null;
|
||||||
|
LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
||||||
|
CalendarHistoryDataWrapper calendarHistoryDataWrapper;
|
||||||
|
RepaymentStartDateType repaymentStartDateType = loan.getLoanProduct().getRepaymentStartDateType();
|
||||||
|
boolean allowCompoundingOnEod = false;
|
||||||
|
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
|
restCalendarInstance = scheduleGeneratorDTO.getCalendarInstanceForInterestRecalculation();
|
||||||
|
compoundingCalendarInstance = scheduleGeneratorDTO.getCompoundingCalendarInstance();
|
||||||
|
recalculationFrequencyType = loan.getLoanInterestRecalculationDetails().getRestFrequencyType();
|
||||||
|
compoundingMethod = loan.getLoanInterestRecalculationDetails().getInterestRecalculationCompoundingMethod();
|
||||||
|
compoundingFrequencyType = loan.getLoanInterestRecalculationDetails().getCompoundingFrequencyType();
|
||||||
|
rescheduleStrategyMethod = loan.getLoanInterestRecalculationDetails().getRescheduleStrategyMethod();
|
||||||
|
allowCompoundingOnEod = loan.getLoanInterestRecalculationDetails().allowCompoundingOnEod();
|
||||||
|
}
|
||||||
|
calendar = scheduleGeneratorDTO.getCalendar();
|
||||||
|
calendarHistoryDataWrapper = scheduleGeneratorDTO.getCalendarHistoryDataWrapper();
|
||||||
|
|
||||||
|
BigDecimal annualNominalInterestRate = loan.getLoanRepaymentScheduleDetail().getAnnualNominalInterestRate();
|
||||||
|
FloatingRateDTO floatingRateDTO = scheduleGeneratorDTO.getFloatingRateDTO();
|
||||||
|
List<LoanTermVariationsData> loanTermVariations = new ArrayList<>();
|
||||||
|
annualNominalInterestRate = constructLoanTermVariations(floatingRateDTO, annualNominalInterestRate, loanTermVariations, loan);
|
||||||
|
LocalDate interestChargedFromDate = loan.getInterestChargedFromDate();
|
||||||
|
if (interestChargedFromDate == null && scheduleGeneratorDTO.isInterestChargedFromDateAsDisbursementDateEnabled()) {
|
||||||
|
interestChargedFromDate = loan.getDisbursementDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
return LoanApplicationTerms.assembleFrom(scheduleGeneratorDTO.getCurrency(), loanTermFrequency, loan.getTermPeriodFrequencyType(),
|
||||||
|
nthDayType, dayOfWeekType, loan.getDisbursementDate(), loan.getExpectedFirstRepaymentOnDate(),
|
||||||
|
scheduleGeneratorDTO.getCalculatedRepaymentsStartingFromDate(), loan.getInArrearsTolerance(),
|
||||||
|
loan.getLoanRepaymentScheduleDetail(), loan.getLoanProduct().isMultiDisburseLoan(), loan.getFixedEmiAmount(),
|
||||||
|
disbursementData, loan.getMaxOutstandingLoanBalance(), interestChargedFromDate,
|
||||||
|
loan.getLoanProduct().getPrincipalThresholdForLastInstallment(), loan.getLoanProduct().getInstallmentAmountInMultiplesOf(),
|
||||||
|
recalculationFrequencyType, restCalendarInstance, compoundingMethod, compoundingCalendarInstance, compoundingFrequencyType,
|
||||||
|
loan.getLoanProduct().preCloseInterestCalculationStrategy(), rescheduleStrategyMethod, calendar,
|
||||||
|
loan.getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations, calendarHistoryDataWrapper,
|
||||||
|
scheduleGeneratorDTO.getNumberOfdays(), scheduleGeneratorDTO.isSkipRepaymentOnFirstDayofMonth(), holidayDetailDTO,
|
||||||
|
allowCompoundingOnEod, scheduleGeneratorDTO.isFirstRepaymentDateAllowedOnHoliday(),
|
||||||
|
scheduleGeneratorDTO.isInterestToBeRecoveredFirstWhenGreaterThanEMI(), loan.getFixedPrincipalPercentagePerInstallment(),
|
||||||
|
scheduleGeneratorDTO.isPrincipalCompoundingDisabledForOverdueLoans(), repaymentStartDateType, loan.getSubmittedOnDate());
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal constructFloatingInterestRates(final BigDecimal annualNominalInterestRate, final FloatingRateDTO floatingRateDTO,
|
||||||
|
final List<LoanTermVariationsData> loanTermVariations, final Loan loan) {
|
||||||
|
final LocalDate dateValue = null;
|
||||||
|
final boolean isSpecificToInstallment = false;
|
||||||
|
BigDecimal interestRate = annualNominalInterestRate;
|
||||||
|
if (loan.getLoanProduct().isLinkedToFloatingInterestRate()) {
|
||||||
|
floatingRateDTO.resetInterestRateDiff();
|
||||||
|
Collection<FloatingRatePeriodData> applicableRates = loan.getLoanProduct().fetchInterestRates(floatingRateDTO);
|
||||||
|
LocalDate interestRateStartDate = DateUtils.getBusinessLocalDate();
|
||||||
|
for (FloatingRatePeriodData periodData : applicableRates) {
|
||||||
|
LoanTermVariationsData loanTermVariation = new LoanTermVariationsData(
|
||||||
|
LoanEnumerations.loanVariationType(LoanTermVariationType.INTEREST_RATE), periodData.getFromDateAsLocalDate(),
|
||||||
|
periodData.getInterestRate(), dateValue, isSpecificToInstallment);
|
||||||
|
if (!DateUtils.isBefore(interestRateStartDate, periodData.getFromDateAsLocalDate())) {
|
||||||
|
interestRateStartDate = periodData.getFromDateAsLocalDate();
|
||||||
|
interestRate = periodData.getInterestRate();
|
||||||
|
}
|
||||||
|
loanTermVariations.add(loanTermVariation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return interestRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+3
-1
@@ -29,6 +29,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
|||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleDTO;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleDTO;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.mapper.LoanMapper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.service.schedule.LoanScheduleComponent;
|
import org.apache.fineract.portfolio.loanaccount.service.schedule.LoanScheduleComponent;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@@ -36,6 +37,7 @@ public class LoanScheduleService {
|
|||||||
|
|
||||||
private final LoanChargeService loanChargeService;
|
private final LoanChargeService loanChargeService;
|
||||||
private final ReprocessLoanTransactionsService reprocessLoanTransactionsService;
|
private final ReprocessLoanTransactionsService reprocessLoanTransactionsService;
|
||||||
|
private final LoanMapper loanMapper;
|
||||||
private final LoanTransactionProcessingService loadTransactionProcessingService;
|
private final LoanTransactionProcessingService loadTransactionProcessingService;
|
||||||
private final LoanScheduleComponent loanSchedule;
|
private final LoanScheduleComponent loanSchedule;
|
||||||
|
|
||||||
@@ -43,7 +45,7 @@ public class LoanScheduleService {
|
|||||||
* Ability to regenerate the repayment schedule based on the loans current details/state.
|
* Ability to regenerate the repayment schedule based on the loans current details/state.
|
||||||
*/
|
*/
|
||||||
public void regenerateRepaymentSchedule(final Loan loan, final ScheduleGeneratorDTO scheduleGeneratorDTO) {
|
public void regenerateRepaymentSchedule(final Loan loan, final ScheduleGeneratorDTO scheduleGeneratorDTO) {
|
||||||
final LoanScheduleModel loanScheduleModel = loan.regenerateScheduleModel(scheduleGeneratorDTO);
|
final LoanScheduleModel loanScheduleModel = loanMapper.regenerateScheduleModel(scheduleGeneratorDTO, loan);
|
||||||
if (loanScheduleModel == null) {
|
if (loanScheduleModel == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -41,6 +41,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.Tra
|
|||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleDTO;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleDTO;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.mapper.LoanTermVariationsMapper;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
|
import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@@ -49,6 +50,7 @@ import org.springframework.stereotype.Service;
|
|||||||
public class LoanTransactionProcessingService {
|
public class LoanTransactionProcessingService {
|
||||||
|
|
||||||
private final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessorFactory;
|
private final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessorFactory;
|
||||||
|
private final LoanTermVariationsMapper loanMapper;
|
||||||
|
|
||||||
public ChangedTransactionDetail processLatestTransaction(String transactionProcessingStrategyCode, LoanTransaction loanTransaction,
|
public ChangedTransactionDetail processLatestTransaction(String transactionProcessingStrategyCode, LoanTransaction loanTransaction,
|
||||||
TransactionCtx ctx) {
|
TransactionCtx ctx) {
|
||||||
@@ -103,7 +105,7 @@ public class LoanTransactionProcessingService {
|
|||||||
|
|
||||||
final MathContext mc = MoneyHelper.getMathContext();
|
final MathContext mc = MoneyHelper.getMathContext();
|
||||||
|
|
||||||
final LoanApplicationTerms loanApplicationTerms = loan.constructLoanApplicationTerms(generatorDTO);
|
final LoanApplicationTerms loanApplicationTerms = loanMapper.constructLoanApplicationTerms(generatorDTO, loan);
|
||||||
|
|
||||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = getTransactionProcessor(
|
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = getTransactionProcessor(
|
||||||
loan.getTransactionProcessingStrategyCode());
|
loan.getTransactionProcessingStrategyCode());
|
||||||
@@ -119,7 +121,7 @@ public class LoanTransactionProcessingService {
|
|||||||
final MathContext mc = MoneyHelper.getMathContext();
|
final MathContext mc = MoneyHelper.getMathContext();
|
||||||
|
|
||||||
final InterestMethod interestMethod = loan.getLoanRepaymentScheduleDetail().getInterestMethod();
|
final InterestMethod interestMethod = loan.getLoanRepaymentScheduleDetail().getInterestMethod();
|
||||||
final LoanApplicationTerms loanApplicationTerms = loan.constructLoanApplicationTerms(scheduleGeneratorDTO);
|
final LoanApplicationTerms loanApplicationTerms = loanMapper.constructLoanApplicationTerms(scheduleGeneratorDTO, loan);
|
||||||
|
|
||||||
final LoanScheduleGenerator loanScheduleGenerator = scheduleGeneratorDTO.getLoanScheduleFactory()
|
final LoanScheduleGenerator loanScheduleGenerator = scheduleGeneratorDTO.getLoanScheduleFactory()
|
||||||
.create(loanApplicationTerms.getLoanScheduleType(), interestMethod);
|
.create(loanApplicationTerms.getLoanScheduleType(), interestMethod);
|
||||||
|
|||||||
+56
-59
@@ -29,8 +29,8 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.fineract.accounting.closure.domain.GLClosure;
|
import org.apache.fineract.accounting.closure.domain.GLClosure;
|
||||||
import org.apache.fineract.accounting.closure.domain.GLClosureRepository;
|
import org.apache.fineract.accounting.closure.domain.GLClosureRepository;
|
||||||
|
import org.apache.fineract.accounting.common.AccountingConstants;
|
||||||
import org.apache.fineract.accounting.common.AccountingConstants.AccrualAccountsForLoan;
|
import org.apache.fineract.accounting.common.AccountingConstants.AccrualAccountsForLoan;
|
||||||
import org.apache.fineract.accounting.common.AccountingConstants.AccrualAccountsForSavings;
|
|
||||||
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForLoan;
|
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForLoan;
|
||||||
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForSavings;
|
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForSavings;
|
||||||
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForShares;
|
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForShares;
|
||||||
@@ -68,12 +68,11 @@ import org.apache.fineract.portfolio.PortfolioProductType;
|
|||||||
import org.apache.fineract.portfolio.account.PortfolioAccountType;
|
import org.apache.fineract.portfolio.account.PortfolioAccountType;
|
||||||
import org.apache.fineract.portfolio.account.service.AccountTransfersReadPlatformService;
|
import org.apache.fineract.portfolio.account.service.AccountTransfersReadPlatformService;
|
||||||
import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
|
import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
|
||||||
import org.apache.fineract.portfolio.client.domain.ClientTransactionRepository;
|
import org.apache.fineract.portfolio.loanaccount.data.AccountingBridgeLoanTransactionDTO;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.data.LoanChargePaidByDTO;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionEnumData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionEnumData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
|
||||||
import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionEnumData;
|
import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionEnumData;
|
||||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransactionRepository;
|
|
||||||
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountTransactionEnumData;
|
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountTransactionEnumData;
|
||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
|
|
||||||
@@ -92,55 +91,53 @@ public class AccountingProcessorHelper {
|
|||||||
private final GLClosureRepository closureRepository;
|
private final GLClosureRepository closureRepository;
|
||||||
private final GLAccountRepository glAccountRepository;
|
private final GLAccountRepository glAccountRepository;
|
||||||
private final OfficeRepository officeRepository;
|
private final OfficeRepository officeRepository;
|
||||||
private final LoanTransactionRepository loanTransactionRepository;
|
|
||||||
private final ClientTransactionRepository clientTransactionRepository;
|
|
||||||
private final SavingsAccountTransactionRepository savingsAccountTransactionRepository;
|
|
||||||
private final AccountTransfersReadPlatformService accountTransfersReadPlatformService;
|
private final AccountTransfersReadPlatformService accountTransfersReadPlatformService;
|
||||||
private final ChargeRepositoryWrapper chargeRepositoryWrapper;
|
private final ChargeRepositoryWrapper chargeRepositoryWrapper;
|
||||||
private final BusinessEventNotifierService businessEventNotifierService;
|
private final BusinessEventNotifierService businessEventNotifierService;
|
||||||
|
|
||||||
public LoanDTO populateLoanDtoFromMap(final Map<String, Object> accountingBridgeData, final boolean cashBasedAccountingEnabled,
|
public LoanDTO populateLoanDtoFromDTO(
|
||||||
final boolean upfrontAccrualBasedAccountingEnabled, final boolean periodicAccrualBasedAccountingEnabled) {
|
final org.apache.fineract.portfolio.loanaccount.data.AccountingBridgeDataDTO accountingBridgeData) {
|
||||||
final Long loanId = (Long) accountingBridgeData.get("loanId");
|
final Long loanId = accountingBridgeData.getLoanId();
|
||||||
final Long loanProductId = (Long) accountingBridgeData.get("loanProductId");
|
final Long loanProductId = accountingBridgeData.getLoanProductId();
|
||||||
final Long officeId = (Long) accountingBridgeData.get("officeId");
|
final Long officeId = accountingBridgeData.getOfficeId();
|
||||||
final String currencyCode = (String) accountingBridgeData.get("currencyCode");
|
final String currencyCode = accountingBridgeData.getCurrencyCode();
|
||||||
final List<LoanTransactionDTO> newLoanTransactions = new ArrayList<>();
|
final List<LoanTransactionDTO> newLoanTransactions = new ArrayList<>();
|
||||||
boolean isAccountTransfer = (Boolean) accountingBridgeData.get("isAccountTransfer");
|
boolean isAccountTransfer = accountingBridgeData.isAccountTransfer();
|
||||||
boolean isLoanMarkedAsChargeOff = (Boolean) accountingBridgeData.get("isChargeOff");
|
boolean isLoanMarkedAsChargeOff = accountingBridgeData.isChargeOff();
|
||||||
boolean isLoanMarkedAsFraud = (Boolean) accountingBridgeData.get("isFraud");
|
boolean isLoanMarkedAsFraud = accountingBridgeData.isFraud();
|
||||||
final Long chargeOffReasonCodeValue = (Long) accountingBridgeData.get("chargeOffReasonCodeValue");
|
final Long chargeOffReasonCodeValue = accountingBridgeData.getChargeOffReasonCodeValue();
|
||||||
|
final boolean cashBasedAccountingEnabled = accountingBridgeData.isCashBasedAccountingEnabled();
|
||||||
|
final boolean upfrontAccrualBasedAccountingEnabled = accountingBridgeData.isUpfrontAccrualBasedAccountingEnabled();
|
||||||
|
final boolean periodicAccrualBasedAccountingEnabled = accountingBridgeData.isPeriodicAccrualBasedAccountingEnabled();
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
final List<AccountingBridgeLoanTransactionDTO> loanTransactionDTOs = accountingBridgeData.getNewLoanTransactions();
|
||||||
final List<Map<String, Object>> newTransactionsMap = (List<Map<String, Object>>) accountingBridgeData.get("newLoanTransactions");
|
|
||||||
|
|
||||||
for (final Map<String, Object> map : newTransactionsMap) {
|
for (final AccountingBridgeLoanTransactionDTO loanTxnDto : loanTransactionDTOs) {
|
||||||
final Long transactionOfficeId = (Long) map.get("officeId");
|
final Long transactionOfficeId = loanTxnDto.getOfficeId();
|
||||||
final String transactionId = ((Long) map.get("id")).toString();
|
final String transactionId = loanTxnDto.getId().toString();
|
||||||
final LocalDate transactionDate = ((LocalDate) map.get("date"));
|
final LocalDate transactionDate = loanTxnDto.getDate();
|
||||||
final LoanTransactionEnumData transactionType = (LoanTransactionEnumData) map.get("type");
|
final LoanTransactionEnumData transactionType = loanTxnDto.getType();
|
||||||
final BigDecimal amount = (BigDecimal) map.get("amount");
|
final BigDecimal amount = loanTxnDto.getAmount();
|
||||||
final BigDecimal principal = (BigDecimal) map.get("principalPortion");
|
final BigDecimal principal = loanTxnDto.getPrincipalPortion();
|
||||||
final BigDecimal interest = (BigDecimal) map.get("interestPortion");
|
final BigDecimal interest = loanTxnDto.getInterestPortion();
|
||||||
final BigDecimal fees = (BigDecimal) map.get("feeChargesPortion");
|
final BigDecimal fees = loanTxnDto.getFeeChargesPortion();
|
||||||
final BigDecimal penalties = (BigDecimal) map.get("penaltyChargesPortion");
|
final BigDecimal penalties = loanTxnDto.getPenaltyChargesPortion();
|
||||||
final BigDecimal overPayments = (BigDecimal) map.get("overPaymentPortion");
|
final BigDecimal overPayments = loanTxnDto.getOverPaymentPortion();
|
||||||
final boolean reversed = (Boolean) map.get("reversed");
|
final boolean reversed = loanTxnDto.isReversed();
|
||||||
final Long paymentTypeId = (Long) map.get("paymentTypeId");
|
final Long paymentTypeId = loanTxnDto.getPaymentTypeId();
|
||||||
final String chargeRefundChargeType = (String) map.get("chargeRefundChargeType");
|
final String chargeRefundChargeType = loanTxnDto.getChargeRefundChargeType();
|
||||||
final LoanChargeData loanChargeData = (LoanChargeData) map.get("loanChargeData");
|
final LoanChargeData loanChargeData = loanTxnDto.getLoanChargeData();
|
||||||
|
|
||||||
final List<ChargePaymentDTO> feePaymentDetails = new ArrayList<>();
|
final List<ChargePaymentDTO> feePaymentDetails = new ArrayList<>();
|
||||||
final List<ChargePaymentDTO> penaltyPaymentDetails = new ArrayList<>();
|
final List<ChargePaymentDTO> penaltyPaymentDetails = new ArrayList<>();
|
||||||
// extract charge payment details (if exists)
|
// extract charge payment details (if exists)
|
||||||
if (map.containsKey("loanChargesPaid")) {
|
if (loanTxnDto.getLoanChargesPaid() != null) {
|
||||||
@SuppressWarnings("unchecked")
|
List<LoanChargePaidByDTO> loanChargesPaidData = loanTxnDto.getLoanChargesPaid();
|
||||||
final List<Map<String, Object>> loanChargesPaidData = (List<Map<String, Object>>) map.get("loanChargesPaid");
|
for (final LoanChargePaidByDTO loanChargePaid : loanChargesPaidData) {
|
||||||
for (final Map<String, Object> loanChargePaid : loanChargesPaidData) {
|
final Long chargeId = loanChargePaid.getChargeId();
|
||||||
final Long chargeId = (Long) loanChargePaid.get("chargeId");
|
final Long loanChargeId = loanChargePaid.getLoanChargeId();
|
||||||
final Long loanChargeId = (Long) loanChargePaid.get("loanChargeId");
|
final boolean isPenalty = loanChargePaid.getIsPenalty();
|
||||||
final boolean isPenalty = (Boolean) loanChargePaid.get("isPenalty");
|
final BigDecimal chargeAmountPaid = loanChargePaid.getAmount();
|
||||||
final BigDecimal chargeAmountPaid = (BigDecimal) loanChargePaid.get("amount");
|
|
||||||
final ChargePaymentDTO chargePaymentDTO = new ChargePaymentDTO(chargeId, chargeAmountPaid, loanChargeId);
|
final ChargePaymentDTO chargePaymentDTO = new ChargePaymentDTO(chargeId, chargeAmountPaid, loanChargeId);
|
||||||
if (isPenalty) {
|
if (isPenalty) {
|
||||||
penaltyPaymentDetails.add(chargePaymentDTO);
|
penaltyPaymentDetails.add(chargePaymentDTO);
|
||||||
@@ -150,23 +147,23 @@ public class AccountingProcessorHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isAccountTransfer) {
|
boolean localIsAccountTransfer = isAccountTransfer;
|
||||||
isAccountTransfer = this.accountTransfersReadPlatformService.isAccountTransfer(Long.parseLong(transactionId),
|
if (!localIsAccountTransfer) {
|
||||||
|
localIsAccountTransfer = this.accountTransfersReadPlatformService.isAccountTransfer(Long.parseLong(transactionId),
|
||||||
PortfolioAccountType.LOAN);
|
PortfolioAccountType.LOAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
BigDecimal principalPaid = (BigDecimal) map.get("principalPaid");
|
BigDecimal principalPaid = loanTxnDto.getPrincipalPaid();
|
||||||
BigDecimal feePaid = (BigDecimal) map.get("feePaid");
|
BigDecimal feePaid = loanTxnDto.getFeePaid();
|
||||||
BigDecimal penaltyPaid = (BigDecimal) map.get("penaltyPaid");
|
BigDecimal penaltyPaid = loanTxnDto.getPenaltyPaid();
|
||||||
|
|
||||||
final LoanTransactionDTO transaction = new LoanTransactionDTO(transactionOfficeId, paymentTypeId, transactionId,
|
final LoanTransactionDTO transaction = new LoanTransactionDTO(transactionOfficeId, paymentTypeId, transactionId,
|
||||||
transactionDate, transactionType, amount, principal, interest, fees, penalties, overPayments, reversed,
|
transactionDate, transactionType, amount, principal, interest, fees, penalties, overPayments, reversed,
|
||||||
penaltyPaymentDetails, feePaymentDetails, isAccountTransfer, chargeRefundChargeType, loanChargeData, principalPaid,
|
penaltyPaymentDetails, feePaymentDetails, localIsAccountTransfer, chargeRefundChargeType, loanChargeData, principalPaid,
|
||||||
feePaid, penaltyPaid);
|
feePaid, penaltyPaid);
|
||||||
Boolean isLoanToLoanTransfer = (Boolean) accountingBridgeData.get("isLoanToLoanTransfer");
|
|
||||||
transaction.setLoanToLoanTransfer(isLoanToLoanTransfer != null && isLoanToLoanTransfer);
|
|
||||||
newLoanTransactions.add(transaction);
|
|
||||||
|
|
||||||
|
transaction.setLoanToLoanTransfer(loanTxnDto.isLoanToLoanTransfer());
|
||||||
|
newLoanTransactions.add(transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new LoanDTO(loanId, loanProductId, officeId, currencyCode, cashBasedAccountingEnabled, upfrontAccrualBasedAccountingEnabled,
|
return new LoanDTO(loanId, loanProductId, officeId, currencyCode, cashBasedAccountingEnabled, upfrontAccrualBasedAccountingEnabled,
|
||||||
@@ -559,10 +556,10 @@ public class AccountingProcessorHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void createAccrualBasedJournalEntriesAndReversalsForSavingsTax(final Office office, final String currencyCode,
|
public void createAccrualBasedJournalEntriesAndReversalsForSavingsTax(final Office office, final String currencyCode,
|
||||||
final AccrualAccountsForSavings accountTypeToBeDebited, final AccrualAccountsForSavings accountTypeToBeCredited,
|
final AccountingConstants.AccrualAccountsForSavings accountTypeToBeDebited,
|
||||||
final Long savingsProductId, final Long paymentTypeId, final Long savingsId, final String transactionId,
|
final AccountingConstants.AccrualAccountsForSavings accountTypeToBeCredited, final Long savingsProductId,
|
||||||
final LocalDate transactionDate, final BigDecimal amount, final Boolean isReversal, final List<TaxPaymentDTO> taxDetails) {
|
final Long paymentTypeId, final Long savingsId, final String transactionId, final LocalDate transactionDate,
|
||||||
|
final BigDecimal amount, final Boolean isReversal, final List<TaxPaymentDTO> taxDetails) {
|
||||||
for (TaxPaymentDTO taxPaymentDTO : taxDetails) {
|
for (TaxPaymentDTO taxPaymentDTO : taxDetails) {
|
||||||
if (taxPaymentDTO.getAmount() != null) {
|
if (taxPaymentDTO.getAmount() != null) {
|
||||||
if (taxPaymentDTO.getCreditAccountId() == null) {
|
if (taxPaymentDTO.getCreditAccountId() == null) {
|
||||||
@@ -769,10 +766,10 @@ public class AccountingProcessorHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(final Office office, final String currencyCode,
|
public void createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(final Office office, final String currencyCode,
|
||||||
final AccrualAccountsForSavings accountTypeToBeDebited, AccrualAccountsForSavings accountTypeToBeCredited,
|
final AccountingConstants.AccrualAccountsForSavings accountTypeToBeDebited,
|
||||||
final Long savingsProductId, final Long paymentTypeId, final Long loanId, final String transactionId,
|
final AccountingConstants.AccrualAccountsForSavings accountTypeToBeCredited, final Long savingsProductId,
|
||||||
final LocalDate transactionDate, final BigDecimal totalAmount, final Boolean isReversal,
|
final Long paymentTypeId, final Long loanId, final String transactionId, final LocalDate transactionDate,
|
||||||
final List<ChargePaymentDTO> chargePaymentDTOs) {
|
final BigDecimal totalAmount, final Boolean isReversal, final List<ChargePaymentDTO> chargePaymentDTOs) {
|
||||||
// TODO Vishwas: Remove this validation, as and when appropriate Junit
|
// TODO Vishwas: Remove this validation, as and when appropriate Junit
|
||||||
// tests are written for accounting
|
// tests are written for accounting
|
||||||
/**
|
/**
|
||||||
|
|||||||
+2
-1
@@ -24,6 +24,7 @@ import java.util.Map;
|
|||||||
import org.apache.fineract.accounting.provisioning.domain.ProvisioningEntry;
|
import org.apache.fineract.accounting.provisioning.domain.ProvisioningEntry;
|
||||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.data.AccountingBridgeDataDTO;
|
||||||
|
|
||||||
public interface JournalEntryWritePlatformService {
|
public interface JournalEntryWritePlatformService {
|
||||||
|
|
||||||
@@ -31,7 +32,7 @@ public interface JournalEntryWritePlatformService {
|
|||||||
|
|
||||||
CommandProcessingResult revertJournalEntry(JsonCommand command);
|
CommandProcessingResult revertJournalEntry(JsonCommand command);
|
||||||
|
|
||||||
void createJournalEntriesForLoan(Map<String, Object> accountingBridgeData);
|
void createJournalEntriesForLoan(AccountingBridgeDataDTO accountingBridgeData);
|
||||||
|
|
||||||
void createJournalEntriesForSavings(Map<String, Object> accountingBridgeData);
|
void createJournalEntriesForSavings(Map<String, Object> accountingBridgeData);
|
||||||
|
|
||||||
|
|||||||
+6
-7
@@ -75,6 +75,7 @@ import org.apache.fineract.organisation.monetary.domain.OrganisationCurrencyRepo
|
|||||||
import org.apache.fineract.organisation.office.domain.Office;
|
import org.apache.fineract.organisation.office.domain.Office;
|
||||||
import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper;
|
import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper;
|
||||||
import org.apache.fineract.portfolio.PortfolioProductType;
|
import org.apache.fineract.portfolio.PortfolioProductType;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.data.AccountingBridgeDataDTO;
|
||||||
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
|
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
|
||||||
import org.apache.fineract.portfolio.paymentdetail.service.PaymentDetailWritePlatformService;
|
import org.apache.fineract.portfolio.paymentdetail.service.PaymentDetailWritePlatformService;
|
||||||
import org.apache.fineract.useradministration.domain.AppUser;
|
import org.apache.fineract.useradministration.domain.AppUser;
|
||||||
@@ -480,15 +481,13 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
|||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@Override
|
@Override
|
||||||
public void createJournalEntriesForLoan(final Map<String, Object> accountingBridgeData) {
|
public void createJournalEntriesForLoan(final AccountingBridgeDataDTO accountingBridgeData) {
|
||||||
|
final boolean cashBasedAccountingEnabled = accountingBridgeData.isCashBasedAccountingEnabled();
|
||||||
final boolean cashBasedAccountingEnabled = (Boolean) accountingBridgeData.get("cashBasedAccountingEnabled");
|
final boolean upfrontAccrualBasedAccountingEnabled = accountingBridgeData.isUpfrontAccrualBasedAccountingEnabled();
|
||||||
final boolean upfrontAccrualBasedAccountingEnabled = (Boolean) accountingBridgeData.get("upfrontAccrualBasedAccountingEnabled");
|
final boolean periodicAccrualBasedAccountingEnabled = accountingBridgeData.isPeriodicAccrualBasedAccountingEnabled();
|
||||||
final boolean periodicAccrualBasedAccountingEnabled = (Boolean) accountingBridgeData.get("periodicAccrualBasedAccountingEnabled");
|
|
||||||
|
|
||||||
if (cashBasedAccountingEnabled || upfrontAccrualBasedAccountingEnabled || periodicAccrualBasedAccountingEnabled) {
|
if (cashBasedAccountingEnabled || upfrontAccrualBasedAccountingEnabled || periodicAccrualBasedAccountingEnabled) {
|
||||||
final LoanDTO loanDTO = this.helper.populateLoanDtoFromMap(accountingBridgeData, cashBasedAccountingEnabled,
|
final LoanDTO loanDTO = this.helper.populateLoanDtoFromDTO(accountingBridgeData);
|
||||||
upfrontAccrualBasedAccountingEnabled, periodicAccrualBasedAccountingEnabled);
|
|
||||||
final AccountingProcessorForLoan accountingProcessorForLoan = this.accountingProcessorForLoanFactory
|
final AccountingProcessorForLoan accountingProcessorForLoan = this.accountingProcessorForLoanFactory
|
||||||
.determineProcessor(loanDTO);
|
.determineProcessor(loanDTO);
|
||||||
accountingProcessorForLoan.createJournalEntriesForLoan(loanDTO);
|
accountingProcessorForLoan.createJournalEntriesForLoan(loanDTO);
|
||||||
|
|||||||
+2
-8
@@ -46,10 +46,7 @@ import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper;
|
|||||||
import org.apache.fineract.organisation.office.service.OfficeReadPlatformService;
|
import org.apache.fineract.organisation.office.service.OfficeReadPlatformService;
|
||||||
import org.apache.fineract.portfolio.account.service.AccountTransfersReadPlatformService;
|
import org.apache.fineract.portfolio.account.service.AccountTransfersReadPlatformService;
|
||||||
import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
|
import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
|
||||||
import org.apache.fineract.portfolio.client.domain.ClientTransactionRepository;
|
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
|
||||||
import org.apache.fineract.portfolio.paymentdetail.service.PaymentDetailWritePlatformService;
|
import org.apache.fineract.portfolio.paymentdetail.service.PaymentDetailWritePlatformService;
|
||||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransactionRepository;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
@@ -63,14 +60,11 @@ public class AccountingJournalEntryConfiguration {
|
|||||||
public AccountingProcessorHelper accountingProcessorHelper(JournalEntryRepository glJournalEntryRepository,
|
public AccountingProcessorHelper accountingProcessorHelper(JournalEntryRepository glJournalEntryRepository,
|
||||||
ProductToGLAccountMappingRepository accountMappingRepository,
|
ProductToGLAccountMappingRepository accountMappingRepository,
|
||||||
FinancialActivityAccountRepositoryWrapper financialActivityAccountRepository, GLClosureRepository closureRepository,
|
FinancialActivityAccountRepositoryWrapper financialActivityAccountRepository, GLClosureRepository closureRepository,
|
||||||
GLAccountRepository glAccountRepository, OfficeRepository officeRepository, LoanTransactionRepository loanTransactionRepository,
|
GLAccountRepository glAccountRepository, OfficeRepository officeRepository,
|
||||||
ClientTransactionRepository clientTransactionRepository,
|
|
||||||
SavingsAccountTransactionRepository savingsAccountTransactionRepository,
|
|
||||||
AccountTransfersReadPlatformService accountTransfersReadPlatformService, ChargeRepositoryWrapper chargeRepositoryWrapper,
|
AccountTransfersReadPlatformService accountTransfersReadPlatformService, ChargeRepositoryWrapper chargeRepositoryWrapper,
|
||||||
BusinessEventNotifierService businessEventNotifierService) {
|
BusinessEventNotifierService businessEventNotifierService) {
|
||||||
return new AccountingProcessorHelper(glJournalEntryRepository, accountMappingRepository, financialActivityAccountRepository,
|
return new AccountingProcessorHelper(glJournalEntryRepository, accountMappingRepository, financialActivityAccountRepository,
|
||||||
closureRepository, glAccountRepository, officeRepository, loanTransactionRepository, clientTransactionRepository,
|
closureRepository, glAccountRepository, officeRepository, accountTransfersReadPlatformService, chargeRepositoryWrapper,
|
||||||
savingsAccountTransactionRepository, accountTransfersReadPlatformService, chargeRepositoryWrapper,
|
|
||||||
businessEventNotifierService);
|
businessEventNotifierService);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+22
-12
@@ -87,6 +87,7 @@ import org.apache.fineract.portfolio.delinquency.service.DelinquencyWritePlatfor
|
|||||||
import org.apache.fineract.portfolio.delinquency.validator.LoanDelinquencyActionData;
|
import org.apache.fineract.portfolio.delinquency.validator.LoanDelinquencyActionData;
|
||||||
import org.apache.fineract.portfolio.group.domain.Group;
|
import org.apache.fineract.portfolio.group.domain.Group;
|
||||||
import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
|
import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.data.AccountingBridgeDataDTO;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
|
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanRefundRequestData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanRefundRequestData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData;
|
||||||
@@ -94,6 +95,7 @@ import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
|
|||||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.MoneyHolder;
|
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.MoneyHolder;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.TransactionCtx;
|
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.TransactionCtx;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.mapper.LoanAccountingBridgeMapper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator;
|
import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator;
|
||||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanDownPaymentTransactionValidator;
|
import org.apache.fineract.portfolio.loanaccount.serialization.LoanDownPaymentTransactionValidator;
|
||||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanForeclosureValidator;
|
import org.apache.fineract.portfolio.loanaccount.serialization.LoanForeclosureValidator;
|
||||||
@@ -157,6 +159,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
|||||||
private final LoanRefundService loanRefundService;
|
private final LoanRefundService loanRefundService;
|
||||||
private final LoanAccountService loanAccountService;
|
private final LoanAccountService loanAccountService;
|
||||||
private final ReprocessLoanTransactionsService reprocessLoanTransactionsService;
|
private final ReprocessLoanTransactionsService reprocessLoanTransactionsService;
|
||||||
|
private final LoanAccountingBridgeMapper loanAccountingBridgeMapper;
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@Override
|
@Override
|
||||||
@@ -449,19 +452,26 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
|||||||
|
|
||||||
final MonetaryCurrency currency = loanAccount.getCurrency();
|
final MonetaryCurrency currency = loanAccount.getCurrency();
|
||||||
|
|
||||||
List<Map<String, Object>> accountingBridgeData = new ArrayList<>();
|
|
||||||
if (loanAccount.isChargedOff()) {
|
if (loanAccount.isChargedOff()) {
|
||||||
accountingBridgeData = loanAccount.deriveAccountingBridgeDataForChargeOff(currency.getCode(), existingTransactionIds,
|
final List<AccountingBridgeDataDTO> accountingBridgeDataList = loanAccountingBridgeMapper
|
||||||
existingReversedTransactionIds, isAccountTransfer);
|
.deriveAccountingBridgeDataForChargeOff(currency.getCode(), existingTransactionIds, existingReversedTransactionIds,
|
||||||
} else {
|
isAccountTransfer, loanAccount);
|
||||||
accountingBridgeData.add(loanAccount.deriveAccountingBridgeData(currency.getCode(), existingTransactionIds,
|
if (isLoanToLoanTransfer) {
|
||||||
existingReversedTransactionIds, isAccountTransfer));
|
accountingBridgeDataList.forEach(dto -> dto.getNewLoanTransactions().forEach(tx -> tx.setLoanToLoanTransfer(true)));
|
||||||
}
|
}
|
||||||
for (Map<String, Object> accountingData : accountingBridgeData) {
|
|
||||||
accountingData.put("isLoanToLoanTransfer", isLoanToLoanTransfer);
|
|
||||||
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingData);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
for (AccountingBridgeDataDTO accountingBridgeData : accountingBridgeDataList) {
|
||||||
|
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final AccountingBridgeDataDTO accountingBridgeData = loanAccountingBridgeMapper.deriveAccountingBridgeData(currency.getCode(),
|
||||||
|
existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, loanAccount);
|
||||||
|
if (isLoanToLoanTransfer) {
|
||||||
|
accountingBridgeData.getNewLoanTransactions().forEach(tx -> tx.setLoanToLoanTransfer(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkClientOrGroupActive(final Loan loan) {
|
private void checkClientOrGroupActive(final Loan loan) {
|
||||||
@@ -985,7 +995,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
|||||||
final List<LoanRepaymentScheduleInstallment> newInstallments = new ArrayList<>(loan.getRepaymentScheduleInstallments());
|
final List<LoanRepaymentScheduleInstallment> newInstallments = new ArrayList<>(loan.getRepaymentScheduleInstallments());
|
||||||
final MonetaryCurrency currency = loan.getCurrency();
|
final MonetaryCurrency currency = loan.getCurrency();
|
||||||
Money totalPrincipal = Money.zero(currency);
|
Money totalPrincipal = Money.zero(currency);
|
||||||
final Money[] balances = loan.retriveIncomeForOverlappingPeriod(transactionDate);
|
final Money[] balances = loan.retrieveIncomeForOverlappingPeriod(transactionDate);
|
||||||
boolean isInterestComponent = true;
|
boolean isInterestComponent = true;
|
||||||
for (final LoanRepaymentScheduleInstallment installment : loan.getRepaymentScheduleInstallments()) {
|
for (final LoanRepaymentScheduleInstallment installment : loan.getRepaymentScheduleInstallments()) {
|
||||||
if (!DateUtils.isAfter(transactionDate, installment.getDueDate())) {
|
if (!DateUtils.isAfter(transactionDate, installment.getDueDate())) {
|
||||||
|
|||||||
+6
-2
@@ -42,6 +42,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
|
|||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.DefaultScheduledDateGenerator;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.DefaultScheduledDateGenerator;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.mapper.LoanTermVariationsMapper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
|
import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
|
||||||
import org.springframework.batch.core.StepContribution;
|
import org.springframework.batch.core.StepContribution;
|
||||||
import org.springframework.batch.core.scope.context.ChunkContext;
|
import org.springframework.batch.core.scope.context.ChunkContext;
|
||||||
@@ -59,6 +60,7 @@ public class ApplyHolidaysToLoansTasklet implements Tasklet {
|
|||||||
private final LoanRepositoryWrapper loanRepositoryWrapper;
|
private final LoanRepositoryWrapper loanRepositoryWrapper;
|
||||||
private final LoanUtilService loanUtilService;
|
private final LoanUtilService loanUtilService;
|
||||||
private final BusinessEventNotifierService businessEventNotifierService;
|
private final BusinessEventNotifierService businessEventNotifierService;
|
||||||
|
private final LoanTermVariationsMapper loanTermVariationsMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
|
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
|
||||||
@@ -120,7 +122,8 @@ public class ApplyHolidaysToLoansTasklet implements Tasklet {
|
|||||||
private void adjustRepaymentSchedules(Loan loan, Holiday holiday, LocalDate adjustedRescheduleToDate) {
|
private void adjustRepaymentSchedules(Loan loan, Holiday holiday, LocalDate adjustedRescheduleToDate) {
|
||||||
final DefaultScheduledDateGenerator scheduledDateGenerator = new DefaultScheduledDateGenerator();
|
final DefaultScheduledDateGenerator scheduledDateGenerator = new DefaultScheduledDateGenerator();
|
||||||
ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, holiday.getFromDate());
|
ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, holiday.getFromDate());
|
||||||
final LoanApplicationTerms loanApplicationTerms = loan.constructLoanApplicationTerms(scheduleGeneratorDTO);
|
final LoanApplicationTerms loanApplicationTerms = loanTermVariationsMapper.constructLoanApplicationTerms(scheduleGeneratorDTO,
|
||||||
|
loan);
|
||||||
|
|
||||||
// first repayment's from date is same as disbursement date.
|
// first repayment's from date is same as disbursement date.
|
||||||
LocalDate tmpFromDate = loan.getDisbursementDate();
|
LocalDate tmpFromDate = loan.getDisbursementDate();
|
||||||
@@ -152,7 +155,8 @@ public class ApplyHolidaysToLoansTasklet implements Tasklet {
|
|||||||
private void adjustAllRepaymentSchedules(Loan loan, Holiday holiday, LocalDate adjustedRescheduleToDate) {
|
private void adjustAllRepaymentSchedules(Loan loan, Holiday holiday, LocalDate adjustedRescheduleToDate) {
|
||||||
final DefaultScheduledDateGenerator scheduledDateGenerator = new DefaultScheduledDateGenerator();
|
final DefaultScheduledDateGenerator scheduledDateGenerator = new DefaultScheduledDateGenerator();
|
||||||
ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, holiday.getFromDate());
|
ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, holiday.getFromDate());
|
||||||
final LoanApplicationTerms loanApplicationTerms = loan.constructLoanApplicationTerms(scheduleGeneratorDTO);
|
final LoanApplicationTerms loanApplicationTerms = loanTermVariationsMapper.constructLoanApplicationTerms(scheduleGeneratorDTO,
|
||||||
|
loan);
|
||||||
|
|
||||||
// first repayment's from date is same as disbursement date.
|
// first repayment's from date is same as disbursement date.
|
||||||
LocalDate tmpFromDate = loan.getDisbursementDate();
|
LocalDate tmpFromDate = loan.getDisbursementDate();
|
||||||
|
|||||||
+3
-1
@@ -44,6 +44,7 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleD
|
|||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.mapper.LoanTermVariationsMapper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanApplicationValidator;
|
import org.apache.fineract.portfolio.loanaccount.serialization.LoanApplicationValidator;
|
||||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanScheduleValidator;
|
import org.apache.fineract.portfolio.loanaccount.serialization.LoanScheduleValidator;
|
||||||
import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
|
import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
|
||||||
@@ -63,6 +64,7 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
|
|||||||
private final LoanUtilService loanUtilService;
|
private final LoanUtilService loanUtilService;
|
||||||
private final LoanRepositoryWrapper loanRepository;
|
private final LoanRepositoryWrapper loanRepository;
|
||||||
private final LoanLifecycleStateMachine defaultLoanLifecycleStateMachine;
|
private final LoanLifecycleStateMachine defaultLoanLifecycleStateMachine;
|
||||||
|
private final LoanTermVariationsMapper loanTermVariationsMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LoanScheduleModel calculateLoanSchedule(final JsonQuery query, Boolean validateParams) {
|
public LoanScheduleModel calculateLoanSchedule(final JsonQuery query, Boolean validateParams) {
|
||||||
@@ -204,7 +206,7 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
|
|||||||
private LoanApplicationTerms constructLoanApplicationTerms(final Loan loan) {
|
private LoanApplicationTerms constructLoanApplicationTerms(final Loan loan) {
|
||||||
final LocalDate recalculateFrom = null;
|
final LocalDate recalculateFrom = null;
|
||||||
ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom);
|
ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom);
|
||||||
return loan.constructLoanApplicationTerms(scheduleGeneratorDTO);
|
return loanTermVariationsMapper.constructLoanApplicationTerms(scheduleGeneratorDTO, loan);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Loan fetchLoan(final Long accountId) {
|
private Loan fetchLoan(final Long accountId) {
|
||||||
|
|||||||
+7
-14
@@ -23,6 +23,7 @@ import java.time.LocalDate;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
|
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
|
||||||
@@ -38,32 +39,23 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplica
|
|||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.mapper.LoanTermVariationsMapper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
|
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
|
||||||
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequestRepositoryWrapper;
|
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequestRepositoryWrapper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.exception.LoanRescheduleRequestNotFoundException;
|
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.exception.LoanRescheduleRequestNotFoundException;
|
||||||
import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
|
import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class LoanReschedulePreviewPlatformServiceImpl implements LoanReschedulePreviewPlatformService {
|
public class LoanReschedulePreviewPlatformServiceImpl implements LoanReschedulePreviewPlatformService {
|
||||||
|
|
||||||
|
private static final DefaultScheduledDateGenerator DEFAULT_SCHEDULED_DATE_GENERATOR = new DefaultScheduledDateGenerator();
|
||||||
private final LoanRescheduleRequestRepositoryWrapper loanRescheduleRequestRepository;
|
private final LoanRescheduleRequestRepositoryWrapper loanRescheduleRequestRepository;
|
||||||
private final LoanUtilService loanUtilService;
|
private final LoanUtilService loanUtilService;
|
||||||
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
|
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
|
||||||
private final LoanScheduleGeneratorFactory loanScheduleFactory;
|
private final LoanScheduleGeneratorFactory loanScheduleFactory;
|
||||||
private static final DefaultScheduledDateGenerator DEFAULT_SCHEDULED_DATE_GENERATOR = new DefaultScheduledDateGenerator();
|
private final LoanTermVariationsMapper loanTermVariationsMapper;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public LoanReschedulePreviewPlatformServiceImpl(final LoanRescheduleRequestRepositoryWrapper loanRescheduleRequestRepository,
|
|
||||||
final LoanUtilService loanUtilService,
|
|
||||||
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
|
|
||||||
final LoanScheduleGeneratorFactory loanScheduleFactory) {
|
|
||||||
this.loanRescheduleRequestRepository = loanRescheduleRequestRepository;
|
|
||||||
this.loanUtilService = loanUtilService;
|
|
||||||
this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
|
|
||||||
this.loanScheduleFactory = loanScheduleFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LoanScheduleModel previewLoanReschedule(Long requestId) {
|
public LoanScheduleModel previewLoanReschedule(Long requestId) {
|
||||||
@@ -80,7 +72,8 @@ public class LoanReschedulePreviewPlatformServiceImpl implements LoanRescheduleP
|
|||||||
loanRescheduleRequest.getRescheduleFromDate());
|
loanRescheduleRequest.getRescheduleFromDate());
|
||||||
LocalDate rescheduleFromDate = null;
|
LocalDate rescheduleFromDate = null;
|
||||||
List<LoanTermVariationsData> removeLoanTermVariationsData = new ArrayList<>();
|
List<LoanTermVariationsData> removeLoanTermVariationsData = new ArrayList<>();
|
||||||
final LoanApplicationTerms loanApplicationTerms = loan.constructLoanApplicationTerms(scheduleGeneratorDTO);
|
final LoanApplicationTerms loanApplicationTerms = loanTermVariationsMapper.constructLoanApplicationTerms(scheduleGeneratorDTO,
|
||||||
|
loan);
|
||||||
LoanTermVariations dueDateVariationInCurrentRequest = loanRescheduleRequest.getDueDateTermVariationIfExists();
|
LoanTermVariations dueDateVariationInCurrentRequest = loanRescheduleRequest.getDueDateTermVariationIfExists();
|
||||||
if (dueDateVariationInCurrentRequest != null) {
|
if (dueDateVariationInCurrentRequest != null) {
|
||||||
for (LoanTermVariationsData loanTermVariation : loanApplicationTerms.getLoanTermVariations().getDueDateVariation()) {
|
for (LoanTermVariationsData loanTermVariation : loanApplicationTerms.getLoanTermVariations().getDueDateVariation()) {
|
||||||
|
|||||||
+11
-4
@@ -47,6 +47,7 @@ import org.apache.fineract.infrastructure.event.business.service.BusinessEventNo
|
|||||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||||
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
|
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.data.AccountingBridgeDataDTO;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
|
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
@@ -68,6 +69,8 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanRepayme
|
|||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleHistoryWritePlatformService;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleHistoryWritePlatformService;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.mapper.LoanAccountingBridgeMapper;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.mapper.LoanTermVariationsMapper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.RescheduleLoansApiConstants;
|
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.RescheduleLoansApiConstants;
|
||||||
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.data.LoanRescheduleRequestDataValidator;
|
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.data.LoanRescheduleRequestDataValidator;
|
||||||
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
|
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
|
||||||
@@ -116,6 +119,8 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
|||||||
private final LoanAccrualsProcessingService loanAccrualsProcessingService;
|
private final LoanAccrualsProcessingService loanAccrualsProcessingService;
|
||||||
private final LoanChargeService loanChargeService;
|
private final LoanChargeService loanChargeService;
|
||||||
private final ReprocessLoanTransactionsService reprocessLoanTransactionsService;
|
private final ReprocessLoanTransactionsService reprocessLoanTransactionsService;
|
||||||
|
private final LoanTermVariationsMapper loanTermVariationsMapper;
|
||||||
|
private final LoanAccountingBridgeMapper loanAccountingBridgeMapper;
|
||||||
private final LoanScheduleComponent loanSchedule;
|
private final LoanScheduleComponent loanSchedule;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -363,7 +368,8 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
|||||||
Collection<LoanRepaymentScheduleHistory> loanRepaymentScheduleHistoryList = this.loanScheduleHistoryWritePlatformService
|
Collection<LoanRepaymentScheduleHistory> loanRepaymentScheduleHistoryList = this.loanScheduleHistoryWritePlatformService
|
||||||
.createLoanScheduleArchive(loan.getRepaymentScheduleInstallments(), loan, loanRescheduleRequest);
|
.createLoanScheduleArchive(loan.getRepaymentScheduleInstallments(), loan, loanRescheduleRequest);
|
||||||
|
|
||||||
final LoanApplicationTerms loanApplicationTerms = loan.constructLoanApplicationTerms(scheduleGeneratorDTO);
|
final LoanApplicationTerms loanApplicationTerms = loanTermVariationsMapper.constructLoanApplicationTerms(scheduleGeneratorDTO,
|
||||||
|
loan);
|
||||||
|
|
||||||
LocalDate rescheduleFromDate = null;
|
LocalDate rescheduleFromDate = null;
|
||||||
List<LoanTermVariations> activeLoanTermVariations = loan.getActiveLoanTermVariations();
|
List<LoanTermVariations> activeLoanTermVariations = loan.getActiveLoanTermVariations();
|
||||||
@@ -403,7 +409,8 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
|||||||
}
|
}
|
||||||
BigDecimal annualNominalInterestRate = null;
|
BigDecimal annualNominalInterestRate = null;
|
||||||
List<LoanTermVariationsData> loanTermVariations = new ArrayList<>();
|
List<LoanTermVariationsData> loanTermVariations = new ArrayList<>();
|
||||||
loan.constructLoanTermVariations(scheduleGeneratorDTO.getFloatingRateDTO(), annualNominalInterestRate, loanTermVariations);
|
loanTermVariationsMapper.constructLoanTermVariations(scheduleGeneratorDTO.getFloatingRateDTO(), annualNominalInterestRate,
|
||||||
|
loanTermVariations, loan);
|
||||||
loanApplicationTerms.getLoanTermVariations().setExceptionData(loanTermVariations);
|
loanApplicationTerms.getLoanTermVariations().setExceptionData(loanTermVariations);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -495,8 +502,8 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
|||||||
private void postJournalEntries(Loan loan, List<Long> existingTransactionIds, List<Long> existingReversedTransactionIds) {
|
private void postJournalEntries(Loan loan, List<Long> existingTransactionIds, List<Long> existingReversedTransactionIds) {
|
||||||
final MonetaryCurrency currency = loan.getCurrency();
|
final MonetaryCurrency currency = loan.getCurrency();
|
||||||
boolean isAccountTransfer = false;
|
boolean isAccountTransfer = false;
|
||||||
final Map<String, Object> accountingBridgeData = loan.deriveAccountingBridgeData(currency.getCode(), existingTransactionIds,
|
final AccountingBridgeDataDTO accountingBridgeData = loanAccountingBridgeMapper.deriveAccountingBridgeData(currency.getCode(),
|
||||||
existingReversedTransactionIds, isAccountTransfer);
|
existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, loan);
|
||||||
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+27
-9
@@ -28,6 +28,7 @@ import java.time.LocalDate;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -90,6 +91,7 @@ import org.apache.fineract.portfolio.group.domain.GroupRepositoryWrapper;
|
|||||||
import org.apache.fineract.portfolio.group.exception.ClientNotInGroupException;
|
import org.apache.fineract.portfolio.group.exception.ClientNotInGroupException;
|
||||||
import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
|
import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
|
||||||
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
|
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.data.DisbursementData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCollateralManagement;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanCollateralManagement;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanEvent;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanEvent;
|
||||||
@@ -109,6 +111,7 @@ import org.apache.fineract.portfolio.loanaccount.exception.MultiDisbursementData
|
|||||||
import org.apache.fineract.portfolio.loanaccount.exception.MultiDisbursementDataRequiredException;
|
import org.apache.fineract.portfolio.loanaccount.exception.MultiDisbursementDataRequiredException;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.mapper.LoanMapper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
|
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
|
||||||
import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
|
import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
|
||||||
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
|
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
|
||||||
@@ -200,6 +203,7 @@ public final class LoanApplicationValidator {
|
|||||||
private final CalendarInstanceRepository calendarInstanceRepository;
|
private final CalendarInstanceRepository calendarInstanceRepository;
|
||||||
private final LoanUtilService loanUtilService;
|
private final LoanUtilService loanUtilService;
|
||||||
private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService;
|
private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService;
|
||||||
|
private final LoanMapper loanMapper;
|
||||||
|
|
||||||
public void validateForCreate(final Loan loan) {
|
public void validateForCreate(final Loan loan) {
|
||||||
final LocalDate expectedFirstRepaymentOnDate = loan.getExpectedFirstRepaymentOnDate();
|
final LocalDate expectedFirstRepaymentOnDate = loan.getExpectedFirstRepaymentOnDate();
|
||||||
@@ -1404,12 +1408,11 @@ public final class LoanApplicationValidator {
|
|||||||
BigDecimal loanOutstanding = this.loanReadPlatformService
|
BigDecimal loanOutstanding = this.loanReadPlatformService
|
||||||
.retrieveLoanPrePaymentTemplate(LoanTransactionType.REPAYMENT, loanIdToClose, expectedDisbursementDate)
|
.retrieveLoanPrePaymentTemplate(LoanTransactionType.REPAYMENT, loanIdToClose, expectedDisbursementDate)
|
||||||
.getAmount();
|
.getAmount();
|
||||||
final BigDecimal firstDisbursalAmount = loan.getFirstDisbursalAmount();
|
final BigDecimal firstDisbursalAmount = getFirstDisbursalAmount(loan);
|
||||||
if (loanOutstanding.compareTo(firstDisbursalAmount) > 0) {
|
if (loanOutstanding.compareTo(firstDisbursalAmount) > 0) {
|
||||||
throw new GeneralPlatformDomainRuleException("error.msg.loan.amount.less.than.outstanding.of.loan.to.be.closed",
|
throw new GeneralPlatformDomainRuleException("error.msg.loan.amount.less.than.outstanding.of.loan.to.be.closed",
|
||||||
"Topup loan amount should be greater than outstanding amount of loan to be closed.");
|
"Topup loan amount should be greater than outstanding amount of loan to be closed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1953,7 +1956,7 @@ public final class LoanApplicationValidator {
|
|||||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, SUPPORTED_PARAMETERS);
|
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, SUPPORTED_PARAMETERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validateTopupLoan(Loan loan, LocalDate expectedDisbursementDate) {
|
public BigDecimal validateTopupLoan(final Loan loan, final LocalDate disbursementDate) {
|
||||||
final Long loanIdToClose = loan.getTopupLoanDetails().getLoanIdToClose();
|
final Long loanIdToClose = loan.getTopupLoanDetails().getLoanIdToClose();
|
||||||
final Loan loanToClose = loanRepositoryWrapper.findNonClosedLoanThatBelongsToClient(loanIdToClose, loan.getClientId());
|
final Loan loanToClose = loanRepositoryWrapper.findNonClosedLoanThatBelongsToClient(loanIdToClose, loan.getClientId());
|
||||||
if (loanToClose == null) {
|
if (loanToClose == null) {
|
||||||
@@ -1969,16 +1972,15 @@ public final class LoanApplicationValidator {
|
|||||||
+ " should be after last transaction date of loan to be closed " + lastUserTransactionOnLoanToClose);
|
+ " should be after last transaction date of loan to be closed " + lastUserTransactionOnLoanToClose);
|
||||||
}
|
}
|
||||||
|
|
||||||
BigDecimal loanOutstanding = loanReadPlatformService
|
final BigDecimal loanOutstanding = loanReadPlatformService
|
||||||
.retrieveLoanPrePaymentTemplate(LoanTransactionType.REPAYMENT, loanIdToClose, expectedDisbursementDate).getAmount();
|
.retrieveLoanPrePaymentTemplate(LoanTransactionType.REPAYMENT, loanIdToClose, disbursementDate).getAmount();
|
||||||
final BigDecimal firstDisbursalAmount = loan.getFirstDisbursalAmount();
|
final BigDecimal firstDisbursalAmount = getFirstDisbursalAmount(loan);
|
||||||
if (loanOutstanding.compareTo(firstDisbursalAmount) > 0) {
|
if (loanOutstanding.compareTo(firstDisbursalAmount) > 0) {
|
||||||
throw new GeneralPlatformDomainRuleException("error.msg.loan.amount.less.than.outstanding.of.loan.to.be.closed",
|
throw new GeneralPlatformDomainRuleException("error.msg.loan.amount.less.than.outstanding.of.loan.to.be.closed",
|
||||||
"Topup loan amount should be greater than outstanding amount of loan to be closed.");
|
"Topup loan amount should be greater than outstanding amount of loan to be closed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
BigDecimal netDisbursalAmount = loan.getApprovedPrincipal().subtract(loanOutstanding);
|
return loanOutstanding;
|
||||||
loan.adjustNetDisbursalAmount(netDisbursalAmount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validateApproval(JsonCommand command, Long loanId) {
|
public void validateApproval(JsonCommand command, Long loanId) {
|
||||||
@@ -2074,7 +2076,9 @@ public final class LoanApplicationValidator {
|
|||||||
StatusEnum.APPROVE.getValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId());
|
StatusEnum.APPROVE.getValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId());
|
||||||
|
|
||||||
if (loan.isTopup() && loan.getClientId() != null) {
|
if (loan.isTopup() && loan.getClientId() != null) {
|
||||||
validateTopupLoan(loan, expectedDisbursementDate);
|
final BigDecimal loanOutstanding = validateTopupLoan(loan, expectedDisbursementDate);
|
||||||
|
final BigDecimal netDisbursalAmountAdjusted = loan.getApprovedPrincipal().subtract(loanOutstanding);
|
||||||
|
loan.adjustNetDisbursalAmount(netDisbursalAmountAdjusted);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!loan.getStatus().isSubmittedAndPendingApproval()) {
|
if (!loan.getStatus().isSubmittedAndPendingApproval()) {
|
||||||
@@ -2202,4 +2206,18 @@ public final class LoanApplicationValidator {
|
|||||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
|
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
|
||||||
dataValidationErrors);
|
dataValidationErrors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BigDecimal getFirstDisbursalAmount(final Loan loan) {
|
||||||
|
BigDecimal firstDisbursalAmount;
|
||||||
|
|
||||||
|
if (loan.isMultiDisburmentLoan()) {
|
||||||
|
List<DisbursementData> disbursementData = loanMapper.getDisbursementData(loan);
|
||||||
|
Collections.sort(disbursementData);
|
||||||
|
firstDisbursalAmount = disbursementData.get(disbursementData.size() - 1).getPrincipal();
|
||||||
|
} else {
|
||||||
|
firstDisbursalAmount = loan.getLoanRepaymentScheduleDetail().getPrincipal().getAmount();
|
||||||
|
}
|
||||||
|
return firstDisbursalAmount;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-24
@@ -32,7 +32,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -60,6 +59,8 @@ import org.apache.fineract.infrastructure.event.business.service.BusinessEventNo
|
|||||||
import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException;
|
import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException;
|
||||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.data.AccountingBridgeDataDTO;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.data.AccountingBridgeLoanTransactionDTO;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.AccrualBalances;
|
import org.apache.fineract.portfolio.loanaccount.data.AccrualBalances;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.AccrualChargeData;
|
import org.apache.fineract.portfolio.loanaccount.data.AccrualChargeData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.AccrualPeriodData;
|
import org.apache.fineract.portfolio.loanaccount.data.AccrualPeriodData;
|
||||||
@@ -79,6 +80,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionToRepayme
|
|||||||
import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException;
|
import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.mapper.LoanAccountingBridgeMapper;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod;
|
import org.apache.fineract.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
@@ -109,6 +111,7 @@ public class LoanAccrualsProcessingServiceImpl implements LoanAccrualsProcessing
|
|||||||
@Qualifier(TaskExecutorConstant.CONFIGURABLE_TASK_EXECUTOR_BEAN_NAME)
|
@Qualifier(TaskExecutorConstant.CONFIGURABLE_TASK_EXECUTOR_BEAN_NAME)
|
||||||
private final ThreadPoolTaskExecutor taskExecutor;
|
private final ThreadPoolTaskExecutor taskExecutor;
|
||||||
private final TransactionTemplate transactionTemplate;
|
private final TransactionTemplate transactionTemplate;
|
||||||
|
private final LoanAccountingBridgeMapper loanAccountingBridgeMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* method adds accrual for batch job "Add Periodic Accrual Transactions" and add accruals api for Loan
|
* method adds accrual for batch job "Add Periodic Accrual Transactions" and add accruals api for Loan
|
||||||
@@ -413,7 +416,7 @@ public class LoanAccrualsProcessingServiceImpl implements LoanAccrualsProcessing
|
|||||||
if (!isFinal || progressiveAccrual) {
|
if (!isFinal || progressiveAccrual) {
|
||||||
loan.setAccruedTill(isFinal ? accrualDate : tillDate);
|
loan.setAccruedTill(isFinal ? accrualDate : tillDate);
|
||||||
}
|
}
|
||||||
ArrayList<Map<String, Object>> newTransactionMapping = new ArrayList<>();
|
List<AccountingBridgeLoanTransactionDTO> newTransactionDTOs = new ArrayList<>();
|
||||||
for (LoanTransaction accrualTransaction : accrualTransactions) {
|
for (LoanTransaction accrualTransaction : accrualTransactions) {
|
||||||
accrualTransaction = loanTransactionRepository.saveAndFlush(accrualTransaction);
|
accrualTransaction = loanTransactionRepository.saveAndFlush(accrualTransaction);
|
||||||
if (addJournal) {
|
if (addJournal) {
|
||||||
@@ -421,11 +424,17 @@ public class LoanAccrualsProcessingServiceImpl implements LoanAccrualsProcessing
|
|||||||
? new LoanAccrualTransactionCreatedBusinessEvent(accrualTransaction)
|
? new LoanAccrualTransactionCreatedBusinessEvent(accrualTransaction)
|
||||||
: new LoanAccrualAdjustmentTransactionBusinessEvent(accrualTransaction);
|
: new LoanAccrualAdjustmentTransactionBusinessEvent(accrualTransaction);
|
||||||
businessEventNotifierService.notifyPostBusinessEvent(businessEvent);
|
businessEventNotifierService.notifyPostBusinessEvent(businessEvent);
|
||||||
newTransactionMapping.add(accrualTransaction.toMapData(currency.getCode()));
|
AccountingBridgeLoanTransactionDTO transactionDTO = loanAccountingBridgeMapper.mapToLoanTransactionData(accrualTransaction,
|
||||||
|
currency.getCode());
|
||||||
|
newTransactionDTOs.add(transactionDTO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (addJournal) {
|
if (addJournal) {
|
||||||
Map<String, Object> accountingBridgeData = deriveAccountingBridgeData(loan, newTransactionMapping);
|
AccountingBridgeDataDTO accountingBridgeData = new AccountingBridgeDataDTO(loan.getId(), loan.getLoanProduct().getId(),
|
||||||
|
loan.getOfficeId(), loan.getCurrencyCode(), loan.getSummary().getTotalInterestCharged(),
|
||||||
|
loan.isNoneOrCashOrUpfrontAccrualAccountingEnabledOnLoanProduct(),
|
||||||
|
loan.isUpfrontAccrualAccountingEnabledOnLoanProduct(), loan.isPeriodicAccrualAccountingEnabledOnLoanProduct(), false,
|
||||||
|
false, false, null, newTransactionDTOs);
|
||||||
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1110,30 +1119,12 @@ public class LoanAccrualsProcessingServiceImpl implements LoanAccrualsProcessing
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Utility
|
|
||||||
|
|
||||||
private Map<String, Object> deriveAccountingBridgeData(@NotNull Loan loan, List<Map<String, Object>> newLoanTransactions) {
|
|
||||||
final Map<String, Object> accountingBridgeData = new LinkedHashMap<>();
|
|
||||||
accountingBridgeData.put("loanId", loan.getId());
|
|
||||||
accountingBridgeData.put("loanProductId", loan.getLoanProduct().getId());
|
|
||||||
accountingBridgeData.put("officeId", loan.getOfficeId());
|
|
||||||
accountingBridgeData.put("currencyCode", loan.getCurrencyCode());
|
|
||||||
accountingBridgeData.put("cashBasedAccountingEnabled", loan.isNoneOrCashOrUpfrontAccrualAccountingEnabledOnLoanProduct());
|
|
||||||
accountingBridgeData.put("upfrontAccrualBasedAccountingEnabled", loan.isUpfrontAccrualAccountingEnabledOnLoanProduct());
|
|
||||||
accountingBridgeData.put("periodicAccrualBasedAccountingEnabled", loan.isPeriodicAccrualAccountingEnabledOnLoanProduct());
|
|
||||||
accountingBridgeData.put("isAccountTransfer", false);
|
|
||||||
accountingBridgeData.put("isChargeOff", false);
|
|
||||||
accountingBridgeData.put("isFraud", false);
|
|
||||||
accountingBridgeData.put("newLoanTransactions", newLoanTransactions);
|
|
||||||
return accountingBridgeData;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void postJournalEntries(final Loan loan, final List<Long> existingTransactionIds,
|
private void postJournalEntries(final Loan loan, final List<Long> existingTransactionIds,
|
||||||
final List<Long> existingReversedTransactionIds) {
|
final List<Long> existingReversedTransactionIds) {
|
||||||
final MonetaryCurrency currency = loan.getCurrency();
|
final MonetaryCurrency currency = loan.getCurrency();
|
||||||
boolean isAccountTransfer = false;
|
boolean isAccountTransfer = false;
|
||||||
final Map<String, Object> accountingBridgeData = loan.deriveAccountingBridgeData(currency.getCode(), existingTransactionIds,
|
final AccountingBridgeDataDTO accountingBridgeData = loanAccountingBridgeMapper.deriveAccountingBridgeData(currency.getCode(),
|
||||||
existingReversedTransactionIds, isAccountTransfer);
|
existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, loan);
|
||||||
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-4
@@ -90,6 +90,7 @@ import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
|||||||
import org.apache.fineract.portfolio.group.domain.Group;
|
import org.apache.fineract.portfolio.group.domain.Group;
|
||||||
import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
|
import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
|
||||||
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
|
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.data.AccountingBridgeDataDTO;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanChargePaidByData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanChargePaidByData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
|
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
@@ -128,6 +129,7 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.data.OverdueLoanSc
|
|||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.DefaultScheduledDateGenerator;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.DefaultScheduledDateGenerator;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.ScheduledDateGenerator;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.ScheduledDateGenerator;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.mapper.LoanAccountingBridgeMapper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeApiJsonValidator;
|
import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeApiJsonValidator;
|
||||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator;
|
import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator;
|
||||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanDownPaymentTransactionValidator;
|
import org.apache.fineract.portfolio.loanaccount.serialization.LoanDownPaymentTransactionValidator;
|
||||||
@@ -178,6 +180,7 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
|
|||||||
private final ReprocessLoanTransactionsService reprocessLoanTransactionsService;
|
private final ReprocessLoanTransactionsService reprocessLoanTransactionsService;
|
||||||
private final LoanAccountService loanAccountService;
|
private final LoanAccountService loanAccountService;
|
||||||
private final LoanAdjustmentService loanAdjustmentService;
|
private final LoanAdjustmentService loanAdjustmentService;
|
||||||
|
private final LoanAccountingBridgeMapper loanAccountingBridgeMapper;
|
||||||
|
|
||||||
private static boolean isPartOfThisInstallment(LoanCharge loanCharge, LoanRepaymentScheduleInstallment e) {
|
private static boolean isPartOfThisInstallment(LoanCharge loanCharge, LoanRepaymentScheduleInstallment e) {
|
||||||
return DateUtils.isAfter(loanCharge.getDueDate(), e.getFromDate()) && !DateUtils.isAfter(loanCharge.getDueDate(), e.getDueDate());
|
return DateUtils.isAfter(loanCharge.getDueDate(), e.getFromDate()) && !DateUtils.isAfter(loanCharge.getDueDate(), e.getDueDate());
|
||||||
@@ -929,8 +932,8 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
|
|||||||
|
|
||||||
loanAccountService.saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
loanAccountService.saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||||
|
|
||||||
final Map<String, Object> accountingBridgeData = loan.deriveAccountingBridgeData(loan.getCurrency().getCode(),
|
final AccountingBridgeDataDTO accountingBridgeData = loanAccountingBridgeMapper.deriveAccountingBridgeData(
|
||||||
existingTransactionIds, existingReversedTransactionIds, false);
|
loan.getCurrency().getCode(), existingTransactionIds, existingReversedTransactionIds, false, loan);
|
||||||
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
||||||
loanAccrualTransactionBusinessEventService.raiseBusinessEventForAccrualTransactions(loan, existingTransactionIds);
|
loanAccrualTransactionBusinessEventService.raiseBusinessEventForAccrualTransactions(loan, existingTransactionIds);
|
||||||
loanAccountDomainService.setLoanDelinquencyTag(loan, transactionDate);
|
loanAccountDomainService.setLoanDelinquencyTag(loan, transactionDate);
|
||||||
@@ -1302,8 +1305,8 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
|
|||||||
|
|
||||||
final MonetaryCurrency currency = loan.getCurrency();
|
final MonetaryCurrency currency = loan.getCurrency();
|
||||||
boolean isAccountTransfer = false;
|
boolean isAccountTransfer = false;
|
||||||
final Map<String, Object> accountingBridgeData = loan.deriveAccountingBridgeData(currency.getCode(), existingTransactionIds,
|
final AccountingBridgeDataDTO accountingBridgeData = loanAccountingBridgeMapper.deriveAccountingBridgeData(currency.getCode(),
|
||||||
existingReversedTransactionIds, isAccountTransfer);
|
existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, loan);
|
||||||
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+64
-2
@@ -24,15 +24,18 @@ import com.google.common.base.Splitter;
|
|||||||
import com.google.gson.JsonArray;
|
import com.google.gson.JsonArray;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonPrimitive;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.fineract.infrastructure.configuration.service.TemporaryConfigurationServiceContainer;
|
import org.apache.fineract.infrastructure.configuration.service.TemporaryConfigurationServiceContainer;
|
||||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
||||||
@@ -76,14 +79,14 @@ public class LoanDisbursementService {
|
|||||||
if (disbursementDataArray != null && !disbursementDataArray.isEmpty()) {
|
if (disbursementDataArray != null && !disbursementDataArray.isEmpty()) {
|
||||||
String dateFormat;
|
String dateFormat;
|
||||||
Locale locale = null;
|
Locale locale = null;
|
||||||
final Map<String, String> dateAndLocale = loan.getDateFormatAndLocale(jsonCommand);
|
final Map<String, String> dateAndLocale = getDateFormatAndLocale(jsonCommand);
|
||||||
dateFormat = dateAndLocale.get(LoanApiConstants.dateFormatParameterName);
|
dateFormat = dateAndLocale.get(LoanApiConstants.dateFormatParameterName);
|
||||||
if (dateAndLocale.containsKey(LoanApiConstants.localeParameterName)) {
|
if (dateAndLocale.containsKey(LoanApiConstants.localeParameterName)) {
|
||||||
locale = JsonParserHelper.localeFromString(dateAndLocale.get(LoanApiConstants.localeParameterName));
|
locale = JsonParserHelper.localeFromString(dateAndLocale.get(LoanApiConstants.localeParameterName));
|
||||||
}
|
}
|
||||||
for (JsonElement jsonElement : disbursementDataArray) {
|
for (JsonElement jsonElement : disbursementDataArray) {
|
||||||
final JsonObject jsonObject = jsonElement.getAsJsonObject();
|
final JsonObject jsonObject = jsonElement.getAsJsonObject();
|
||||||
final Map<String, Object> parsedDisbursementData = loan.parseDisbursementDetails(jsonObject, dateFormat, locale);
|
final Map<String, Object> parsedDisbursementData = parseDisbursementDetails(jsonObject, dateFormat, locale);
|
||||||
final LocalDate expectedDisbursementDate = (LocalDate) parsedDisbursementData
|
final LocalDate expectedDisbursementDate = (LocalDate) parsedDisbursementData
|
||||||
.get(LoanApiConstants.expectedDisbursementDateParameterName);
|
.get(LoanApiConstants.expectedDisbursementDateParameterName);
|
||||||
final BigDecimal principal = (BigDecimal) parsedDisbursementData
|
final BigDecimal principal = (BigDecimal) parsedDisbursementData
|
||||||
@@ -298,4 +301,63 @@ public class LoanDisbursementService {
|
|||||||
}) //
|
}) //
|
||||||
.forEach(loanCharge -> reprocessLoanTransactionsService.removeLoanCharge(loan, loanCharge));
|
.forEach(loanCharge -> reprocessLoanTransactionsService.removeLoanCharge(loan, loanCharge));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This method returns date format and locale if present in the JsonCommand
|
||||||
|
private Map<String, String> getDateFormatAndLocale(final JsonCommand jsonCommand) {
|
||||||
|
Map<String, String> returnObject = new HashMap<>();
|
||||||
|
JsonElement jsonElement = jsonCommand.parsedJson();
|
||||||
|
if (jsonElement.isJsonObject()) {
|
||||||
|
JsonObject topLevel = jsonElement.getAsJsonObject();
|
||||||
|
if (topLevel.has(LoanApiConstants.dateFormatParameterName)
|
||||||
|
&& topLevel.get(LoanApiConstants.dateFormatParameterName).isJsonPrimitive()) {
|
||||||
|
final JsonPrimitive primitive = topLevel.get(LoanApiConstants.dateFormatParameterName).getAsJsonPrimitive();
|
||||||
|
returnObject.put(LoanApiConstants.dateFormatParameterName, primitive.getAsString());
|
||||||
|
}
|
||||||
|
if (topLevel.has(LoanApiConstants.localeParameterName)
|
||||||
|
&& topLevel.get(LoanApiConstants.localeParameterName).isJsonPrimitive()) {
|
||||||
|
final JsonPrimitive primitive = topLevel.get(LoanApiConstants.localeParameterName).getAsJsonPrimitive();
|
||||||
|
String localeString = primitive.getAsString();
|
||||||
|
returnObject.put(LoanApiConstants.localeParameterName, localeString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return returnObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> parseDisbursementDetails(final JsonObject jsonObject, String dateFormat, Locale locale) {
|
||||||
|
Map<String, Object> returnObject = new HashMap<>();
|
||||||
|
if (jsonObject.get(LoanApiConstants.expectedDisbursementDateParameterName) != null
|
||||||
|
&& jsonObject.get(LoanApiConstants.expectedDisbursementDateParameterName).isJsonPrimitive()) {
|
||||||
|
final JsonPrimitive primitive = jsonObject.get(LoanApiConstants.expectedDisbursementDateParameterName).getAsJsonPrimitive();
|
||||||
|
final String valueAsString = primitive.getAsString();
|
||||||
|
if (StringUtils.isNotBlank(valueAsString)) {
|
||||||
|
LocalDate date = JsonParserHelper.convertFrom(valueAsString, LoanApiConstants.expectedDisbursementDateParameterName,
|
||||||
|
dateFormat, locale);
|
||||||
|
if (date != null) {
|
||||||
|
returnObject.put(LoanApiConstants.expectedDisbursementDateParameterName, date);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jsonObject.get(LoanApiConstants.disbursementPrincipalParameterName).isJsonPrimitive()
|
||||||
|
&& StringUtils.isNotBlank(jsonObject.get(LoanApiConstants.disbursementPrincipalParameterName).getAsString())) {
|
||||||
|
BigDecimal principal = jsonObject.getAsJsonPrimitive(LoanApiConstants.disbursementPrincipalParameterName).getAsBigDecimal();
|
||||||
|
returnObject.put(LoanApiConstants.disbursementPrincipalParameterName, principal);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jsonObject.has(LoanApiConstants.disbursementIdParameterName)
|
||||||
|
&& jsonObject.get(LoanApiConstants.disbursementIdParameterName).isJsonPrimitive()
|
||||||
|
&& StringUtils.isNotBlank(jsonObject.get(LoanApiConstants.disbursementIdParameterName).getAsString())) {
|
||||||
|
Long id = jsonObject.getAsJsonPrimitive(LoanApiConstants.disbursementIdParameterName).getAsLong();
|
||||||
|
returnObject.put(LoanApiConstants.disbursementIdParameterName, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jsonObject.has(LoanApiConstants.loanChargeIdParameterName)
|
||||||
|
&& jsonObject.get(LoanApiConstants.loanChargeIdParameterName).isJsonPrimitive()
|
||||||
|
&& StringUtils.isNotBlank(jsonObject.get(LoanApiConstants.loanChargeIdParameterName).getAsString())) {
|
||||||
|
returnObject.put(LoanApiConstants.loanChargeIdParameterName,
|
||||||
|
jsonObject.getAsJsonPrimitive(LoanApiConstants.loanChargeIdParameterName).getAsString());
|
||||||
|
}
|
||||||
|
return returnObject;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-14
@@ -18,13 +18,13 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.portfolio.loanaccount.service;
|
package org.apache.fineract.portfolio.loanaccount.service;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
|
import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
|
||||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.data.AccountingBridgeDataDTO;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.mapper.LoanAccountingBridgeMapper;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@@ -32,23 +32,24 @@ import org.springframework.stereotype.Component;
|
|||||||
public class LoanJournalEntryPoster {
|
public class LoanJournalEntryPoster {
|
||||||
|
|
||||||
private final JournalEntryWritePlatformService journalEntryWritePlatformService;
|
private final JournalEntryWritePlatformService journalEntryWritePlatformService;
|
||||||
|
private final LoanAccountingBridgeMapper loanAccountingBridgeMapper;
|
||||||
|
|
||||||
public void postJournalEntries(final Loan loan, final List<Long> existingTransactionIds,
|
public void postJournalEntries(final Loan loan, final List<Long> existingTransactionIds,
|
||||||
final List<Long> existingReversedTransactionIds) {
|
final List<Long> existingReversedTransactionIds) {
|
||||||
|
|
||||||
final MonetaryCurrency currency = loan.getCurrency();
|
final MonetaryCurrency currency = loan.getCurrency();
|
||||||
boolean isAccountTransfer = false;
|
boolean isAccountTransfer = false;
|
||||||
List<Map<String, Object>> accountingBridgeData = new ArrayList<>();
|
|
||||||
if (loan.isChargedOff()) {
|
|
||||||
accountingBridgeData = loan.deriveAccountingBridgeDataForChargeOff(currency.getCode(), existingTransactionIds,
|
|
||||||
existingReversedTransactionIds, isAccountTransfer);
|
|
||||||
} else {
|
|
||||||
accountingBridgeData.add(loan.deriveAccountingBridgeData(currency.getCode(), existingTransactionIds,
|
|
||||||
existingReversedTransactionIds, isAccountTransfer));
|
|
||||||
}
|
|
||||||
for (Map<String, Object> accountingData : accountingBridgeData) {
|
|
||||||
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingData);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (loan.isChargedOff()) {
|
||||||
|
List<AccountingBridgeDataDTO> accountingBridgeDataList = loanAccountingBridgeMapper.deriveAccountingBridgeDataForChargeOff(
|
||||||
|
currency.getCode(), existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, loan);
|
||||||
|
for (AccountingBridgeDataDTO accountingBridgeData : accountingBridgeDataList) {
|
||||||
|
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
AccountingBridgeDataDTO accountingBridgeData = loanAccountingBridgeMapper.deriveAccountingBridgeData(currency.getCode(),
|
||||||
|
existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, loan);
|
||||||
|
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-5
@@ -38,7 +38,7 @@ import java.util.Objects;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
|
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
|
||||||
import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformService;
|
import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformService;
|
||||||
@@ -141,15 +141,13 @@ import org.springframework.data.domain.Pageable;
|
|||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.jdbc.core.ResultSetExtractor;
|
import org.springframework.jdbc.core.ResultSetExtractor;
|
||||||
import org.springframework.jdbc.core.RowMapper;
|
import org.springframework.jdbc.core.RowMapper;
|
||||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, LoanReadPlatformServiceCommon {
|
public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, LoanReadPlatformServiceCommon {
|
||||||
|
|
||||||
private static final String ACCRUAL_ON_CHARGE_SUBMITTED_ON_DATE = "submitted-date";
|
|
||||||
private final JdbcTemplate jdbcTemplate;
|
private final JdbcTemplate jdbcTemplate;
|
||||||
private final PlatformSecurityContext context;
|
private final PlatformSecurityContext context;
|
||||||
private final LoanRepositoryWrapper loanRepositoryWrapper;
|
private final LoanRepositoryWrapper loanRepositoryWrapper;
|
||||||
@@ -164,7 +162,6 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
|
|||||||
private final CalendarReadPlatformService calendarReadPlatformService;
|
private final CalendarReadPlatformService calendarReadPlatformService;
|
||||||
private final StaffReadPlatformService staffReadPlatformService;
|
private final StaffReadPlatformService staffReadPlatformService;
|
||||||
private final PaginationHelper paginationHelper;
|
private final PaginationHelper paginationHelper;
|
||||||
private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
|
|
||||||
private final PaymentTypeReadPlatformService paymentTypeReadPlatformService;
|
private final PaymentTypeReadPlatformService paymentTypeReadPlatformService;
|
||||||
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
|
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
|
||||||
private final FloatingRatesReadPlatformService floatingRatesReadPlatformService;
|
private final FloatingRatesReadPlatformService floatingRatesReadPlatformService;
|
||||||
@@ -179,6 +176,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
|
|||||||
private final LoanTransactionRelationReadService loanTransactionRelationReadService;
|
private final LoanTransactionRelationReadService loanTransactionRelationReadService;
|
||||||
private final LoanForeclosureValidator loanForeclosureValidator;
|
private final LoanForeclosureValidator loanForeclosureValidator;
|
||||||
private final LoanTransactionMapper loanTransactionMapper;
|
private final LoanTransactionMapper loanTransactionMapper;
|
||||||
|
private final org.apache.fineract.portfolio.loanaccount.mapper.LoanMapper loanMapper;
|
||||||
private final LoanTransactionProcessingService loadTransactionProcessingService;
|
private final LoanTransactionProcessingService loadTransactionProcessingService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+13
-32
@@ -149,6 +149,7 @@ import org.apache.fineract.portfolio.group.domain.Group;
|
|||||||
import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
|
import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
|
||||||
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
|
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
|
||||||
import org.apache.fineract.portfolio.loanaccount.command.LoanUpdateCommand;
|
import org.apache.fineract.portfolio.loanaccount.command.LoanUpdateCommand;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.data.AccountingBridgeDataDTO;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
|
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
|
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.GLIMAccountInfoRepository;
|
import org.apache.fineract.portfolio.loanaccount.domain.GLIMAccountInfoRepository;
|
||||||
@@ -163,7 +164,6 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachin
|
|||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleProcessingWrapper;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleProcessingWrapper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
|
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
||||||
@@ -195,6 +195,8 @@ import org.apache.fineract.portfolio.loanaccount.guarantor.service.GuarantorDoma
|
|||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelPeriod;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelPeriod;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleHistoryWritePlatformService;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleHistoryWritePlatformService;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.mapper.LoanAccountingBridgeMapper;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.mapper.LoanMapper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
|
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
|
||||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanApplicationValidator;
|
import org.apache.fineract.portfolio.loanaccount.serialization.LoanApplicationValidator;
|
||||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator;
|
import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator;
|
||||||
@@ -247,14 +249,13 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
private final FromJsonHelper fromApiJsonHelper;
|
private final FromJsonHelper fromApiJsonHelper;
|
||||||
private final CalendarRepository calendarRepository;
|
private final CalendarRepository calendarRepository;
|
||||||
private final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService;
|
private final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService;
|
||||||
private final LoanApplicationValidator loanApplicationCommandFromApiJsonHelper;
|
private final LoanApplicationValidator loanApplicationValidator;
|
||||||
private final AccountAssociationsRepository accountAssociationRepository;
|
private final AccountAssociationsRepository accountAssociationRepository;
|
||||||
private final AccountTransferDetailRepository accountTransferDetailRepository;
|
private final AccountTransferDetailRepository accountTransferDetailRepository;
|
||||||
private final BusinessEventNotifierService businessEventNotifierService;
|
private final BusinessEventNotifierService businessEventNotifierService;
|
||||||
private final GuarantorDomainService guarantorDomainService;
|
private final GuarantorDomainService guarantorDomainService;
|
||||||
private final LoanUtilService loanUtilService;
|
private final LoanUtilService loanUtilService;
|
||||||
private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService;
|
private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService;
|
||||||
private final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessingStrategy;
|
|
||||||
private final CodeValueRepositoryWrapper codeValueRepository;
|
private final CodeValueRepositoryWrapper codeValueRepository;
|
||||||
private final CashierTransactionDataValidator cashierTransactionDataValidator;
|
private final CashierTransactionDataValidator cashierTransactionDataValidator;
|
||||||
private final GLIMAccountInfoRepository glimRepository;
|
private final GLIMAccountInfoRepository glimRepository;
|
||||||
@@ -280,6 +281,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
private final LoanAccountService loanAccountService;
|
private final LoanAccountService loanAccountService;
|
||||||
private final LoanJournalEntryPoster journalEntryPoster;
|
private final LoanJournalEntryPoster journalEntryPoster;
|
||||||
private final LoanAdjustmentService loanAdjustmentService;
|
private final LoanAdjustmentService loanAdjustmentService;
|
||||||
|
private final LoanAccountingBridgeMapper loanAccountingBridgeMapper;
|
||||||
|
private final LoanMapper loanMapper;
|
||||||
private final LoanTransactionProcessingService loanTransactionProcessingService;
|
private final LoanTransactionProcessingService loanTransactionProcessingService;
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@@ -378,27 +381,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
final ExternalId txnExternalId = externalIdFactory.createFromCommand(command, LoanApiConstants.externalIdParameterName);
|
final ExternalId txnExternalId = externalIdFactory.createFromCommand(command, LoanApiConstants.externalIdParameterName);
|
||||||
|
|
||||||
if (loan.isTopup() && loan.getClientId() != null) {
|
if (loan.isTopup() && loan.getClientId() != null) {
|
||||||
final Long loanIdToClose = loan.getTopupLoanDetails().getLoanIdToClose();
|
final BigDecimal loanOutstanding = loanApplicationValidator.validateTopupLoan(loan, actualDisbursementDate);
|
||||||
final Loan loanToClose = this.loanRepositoryWrapper.findNonClosedLoanThatBelongsToClient(loanIdToClose, loan.getClientId());
|
|
||||||
if (loanToClose == null) {
|
|
||||||
throw new GeneralPlatformDomainRuleException("error.msg.loan.to.be.closed.with.topup.is.not.active",
|
|
||||||
"Loan to be closed with this topup is not active.");
|
|
||||||
}
|
|
||||||
final LocalDate lastUserTransactionOnLoanToClose = loanToClose.getLastUserTransactionDate();
|
|
||||||
if (DateUtils.isBefore(loan.getDisbursementDate(), lastUserTransactionOnLoanToClose)) {
|
|
||||||
throw new GeneralPlatformDomainRuleException(
|
|
||||||
"error.msg.loan.disbursal.date.should.be.after.last.transaction.date.of.loan.to.be.closed",
|
|
||||||
"Disbursal date of this loan application " + loan.getDisbursementDate()
|
|
||||||
+ " should be after last transaction date of loan to be closed " + lastUserTransactionOnLoanToClose);
|
|
||||||
}
|
|
||||||
|
|
||||||
BigDecimal loanOutstanding = this.loanReadPlatformService
|
|
||||||
.retrieveLoanPrePaymentTemplate(LoanTransactionType.REPAYMENT, loanIdToClose, actualDisbursementDate).getAmount();
|
|
||||||
final BigDecimal firstDisbursalAmount = loan.getFirstDisbursalAmount();
|
|
||||||
if (loanOutstanding.compareTo(firstDisbursalAmount) > 0) {
|
|
||||||
throw new GeneralPlatformDomainRuleException("error.msg.loan.amount.less.than.outstanding.of.loan.to.be.closed",
|
|
||||||
"Topup loan amount should be greater than outstanding amount of loan to be closed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
amountToDisburse = disburseAmount.minus(loanOutstanding);
|
amountToDisburse = disburseAmount.minus(loanOutstanding);
|
||||||
disburseLoanToLoan(loan, command, loanOutstanding);
|
disburseLoanToLoan(loan, command, loanOutstanding);
|
||||||
@@ -625,7 +608,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
|
|
||||||
private void createAndSaveLoanScheduleArchive(final Loan loan, ScheduleGeneratorDTO scheduleGeneratorDTO) {
|
private void createAndSaveLoanScheduleArchive(final Loan loan, ScheduleGeneratorDTO scheduleGeneratorDTO) {
|
||||||
LoanRescheduleRequest loanRescheduleRequest = null;
|
LoanRescheduleRequest loanRescheduleRequest = null;
|
||||||
LoanScheduleModel loanScheduleModel = loan.regenerateScheduleModel(scheduleGeneratorDTO);
|
LoanScheduleModel loanScheduleModel = loanMapper.regenerateScheduleModel(scheduleGeneratorDTO, loan);
|
||||||
List<LoanRepaymentScheduleInstallment> installments = retrieveRepaymentScheduleFromModel(loanScheduleModel);
|
List<LoanRepaymentScheduleInstallment> installments = retrieveRepaymentScheduleFromModel(loanScheduleModel);
|
||||||
this.loanScheduleHistoryWritePlatformService.createAndSaveLoanScheduleArchive(installments, loan, loanRescheduleRequest);
|
this.loanScheduleHistoryWritePlatformService.createAndSaveLoanScheduleArchive(installments, loan, loanRescheduleRequest);
|
||||||
}
|
}
|
||||||
@@ -922,11 +905,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
}
|
}
|
||||||
loan = saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
loan = saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||||
this.accountTransfersWritePlatformService.reverseAllTransactions(loanId, PortfolioAccountType.LOAN);
|
this.accountTransfersWritePlatformService.reverseAllTransactions(loanId, PortfolioAccountType.LOAN);
|
||||||
String noteText;
|
|
||||||
createNote(loan, command, changes);
|
createNote(loan, command, changes);
|
||||||
boolean isAccountTransfer = false;
|
boolean isAccountTransfer = false;
|
||||||
final Map<String, Object> accountingBridgeData = loan.deriveAccountingBridgeData(currency.getCode(), existingTransactionIds,
|
final AccountingBridgeDataDTO accountingBridgeData = loanAccountingBridgeMapper.deriveAccountingBridgeData(currency.getCode(),
|
||||||
existingReversedTransactionIds, isAccountTransfer);
|
existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, loan);
|
||||||
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
||||||
loanAccrualTransactionBusinessEventService.raiseBusinessEventForAccrualTransactions(loan, existingTransactionIds);
|
loanAccrualTransactionBusinessEventService.raiseBusinessEventForAccrualTransactions(loan, existingTransactionIds);
|
||||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanUndoDisbursalBusinessEvent(loan));
|
businessEventNotifierService.notifyPostBusinessEvent(new LoanUndoDisbursalBusinessEvent(loan));
|
||||||
@@ -2353,8 +2335,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
|
|
||||||
final BigDecimal principal = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("approvedLoanAmount", element);
|
final BigDecimal principal = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("approvedLoanAmount", element);
|
||||||
|
|
||||||
loanApplicationCommandFromApiJsonHelper.validateLoanMultiDisbursementDate(element, baseDataValidator, expectedDisbursementDate,
|
loanApplicationValidator.validateLoanMultiDisbursementDate(element, baseDataValidator, expectedDisbursementDate, principal);
|
||||||
principal);
|
|
||||||
if (!dataValidationErrors.isEmpty()) {
|
if (!dataValidationErrors.isEmpty()) {
|
||||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||||
}
|
}
|
||||||
@@ -2791,8 +2772,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
loan = saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
loan = saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||||
createNote(loan, command, changes);
|
createNote(loan, command, changes);
|
||||||
boolean isAccountTransfer = false;
|
boolean isAccountTransfer = false;
|
||||||
final Map<String, Object> accountingBridgeData = loan.deriveAccountingBridgeData(currency.getCode(), existingTransactionIds,
|
final AccountingBridgeDataDTO accountingBridgeData = loanAccountingBridgeMapper.deriveAccountingBridgeData(currency.getCode(),
|
||||||
existingReversedTransactionIds, isAccountTransfer);
|
existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, loan);
|
||||||
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
||||||
loanAccrualTransactionBusinessEventService.raiseBusinessEventForAccrualTransactions(loan, existingTransactionIds);
|
loanAccrualTransactionBusinessEventService.raiseBusinessEventForAccrualTransactions(loan, existingTransactionIds);
|
||||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanUndoLastDisbursalBusinessEvent(loan));
|
businessEventNotifierService.notifyPostBusinessEvent(new LoanUndoLastDisbursalBusinessEvent(loan));
|
||||||
|
|||||||
+23
-18
@@ -83,8 +83,10 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanSchedul
|
|||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleAssembler;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleAssembler;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleCalculationPlatformService;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleCalculationPlatformService;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleHistoryWritePlatformService;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleHistoryWritePlatformService;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.mapper.LoanAccountingBridgeMapper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.mapper.LoanChargeMapper;
|
import org.apache.fineract.portfolio.loanaccount.mapper.LoanChargeMapper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.mapper.LoanCollateralManagementMapper;
|
import org.apache.fineract.portfolio.loanaccount.mapper.LoanCollateralManagementMapper;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.mapper.LoanMapper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.mapper.LoanTransactionMapper;
|
import org.apache.fineract.portfolio.loanaccount.mapper.LoanTransactionMapper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanTermVariationsRepository;
|
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanTermVariationsRepository;
|
||||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanApplicationTransitionValidator;
|
import org.apache.fineract.portfolio.loanaccount.serialization.LoanApplicationTransitionValidator;
|
||||||
@@ -162,7 +164,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
|||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
public class LoanAccountConfiguration {
|
public class LoanAccountConfiguration {
|
||||||
@@ -302,7 +303,8 @@ public class LoanAccountConfiguration {
|
|||||||
LoanAccrualsProcessingService loanAccrualsProcessingService,
|
LoanAccrualsProcessingService loanAccrualsProcessingService,
|
||||||
LoanDownPaymentTransactionValidator loanDownPaymentTransactionValidator, LoanChargeValidator loanChargeValidator,
|
LoanDownPaymentTransactionValidator loanDownPaymentTransactionValidator, LoanChargeValidator loanChargeValidator,
|
||||||
LoanScheduleService loanScheduleService, ReprocessLoanTransactionsService reprocessLoanTransactionsService,
|
LoanScheduleService loanScheduleService, ReprocessLoanTransactionsService reprocessLoanTransactionsService,
|
||||||
LoanAccountService loanAccountService, LoanAdjustmentService loanAdjustmentService) {
|
LoanAccountService loanAccountService, LoanAdjustmentService loanAdjustmentService,
|
||||||
|
LoanAccountingBridgeMapper loanAccountingBridgeMapper) {
|
||||||
return new LoanChargeWritePlatformServiceImpl(loanChargeApiJsonValidator, loanAssembler, chargeRepository,
|
return new LoanChargeWritePlatformServiceImpl(loanChargeApiJsonValidator, loanAssembler, chargeRepository,
|
||||||
businessEventNotifierService, loanTransactionRepository, accountTransfersWritePlatformService, loanRepositoryWrapper,
|
businessEventNotifierService, loanTransactionRepository, accountTransfersWritePlatformService, loanRepositoryWrapper,
|
||||||
journalEntryWritePlatformService, loanAccountDomainService, loanChargeRepository, loanWritePlatformService, loanUtilService,
|
journalEntryWritePlatformService, loanAccountDomainService, loanChargeRepository, loanWritePlatformService, loanUtilService,
|
||||||
@@ -310,7 +312,8 @@ public class LoanAccountConfiguration {
|
|||||||
configurationDomainService, loanRepaymentScheduleTransactionProcessorFactory, externalIdFactory,
|
configurationDomainService, loanRepaymentScheduleTransactionProcessorFactory, externalIdFactory,
|
||||||
accountTransferDetailRepository, loanChargeAssembler, paymentDetailWritePlatformService, noteRepository,
|
accountTransferDetailRepository, loanChargeAssembler, paymentDetailWritePlatformService, noteRepository,
|
||||||
loanAccrualTransactionBusinessEventService, loanAccrualsProcessingService, loanDownPaymentTransactionValidator,
|
loanAccrualTransactionBusinessEventService, loanAccrualsProcessingService, loanDownPaymentTransactionValidator,
|
||||||
loanChargeValidator, loanScheduleService, reprocessLoanTransactionsService, loanAccountService, loanAdjustmentService);
|
loanChargeValidator, loanScheduleService, reprocessLoanTransactionsService, loanAccountService, loanAdjustmentService,
|
||||||
|
loanAccountingBridgeMapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@@ -322,23 +325,23 @@ public class LoanAccountConfiguration {
|
|||||||
FundReadPlatformService fundReadPlatformService, ChargeReadPlatformService chargeReadPlatformService,
|
FundReadPlatformService fundReadPlatformService, ChargeReadPlatformService chargeReadPlatformService,
|
||||||
CodeValueReadPlatformService codeValueReadPlatformService, CalendarReadPlatformService calendarReadPlatformService,
|
CodeValueReadPlatformService codeValueReadPlatformService, CalendarReadPlatformService calendarReadPlatformService,
|
||||||
StaffReadPlatformService staffReadPlatformService, PaginationHelper paginationHelper,
|
StaffReadPlatformService staffReadPlatformService, PaginationHelper paginationHelper,
|
||||||
NamedParameterJdbcTemplate namedParameterJdbcTemplate, PaymentTypeReadPlatformService paymentTypeReadPlatformService,
|
PaymentTypeReadPlatformService paymentTypeReadPlatformService,
|
||||||
LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
|
LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
|
||||||
FloatingRatesReadPlatformService floatingRatesReadPlatformService, LoanUtilService loanUtilService,
|
FloatingRatesReadPlatformService floatingRatesReadPlatformService, LoanUtilService loanUtilService,
|
||||||
ConfigurationDomainService configurationDomainService, AccountDetailsReadPlatformService accountDetailsReadPlatformService,
|
ConfigurationDomainService configurationDomainService, AccountDetailsReadPlatformService accountDetailsReadPlatformService,
|
||||||
ColumnValidator columnValidator, DatabaseSpecificSQLGenerator sqlGenerator,
|
ColumnValidator columnValidator, DatabaseSpecificSQLGenerator sqlGenerator,
|
||||||
DelinquencyReadPlatformService delinquencyReadPlatformService, LoanTransactionRepository loanTransactionRepository,
|
DelinquencyReadPlatformService delinquencyReadPlatformService, LoanTransactionRepository loanTransactionRepository,
|
||||||
LoanChargePaidByReadService loanChargePaidByReadService, LoanTransactionRelationReadService loanTransactionRelationReadService,
|
LoanChargePaidByReadService loanChargePaidByReadService, LoanTransactionRelationReadService loanTransactionRelationReadService,
|
||||||
LoanForeclosureValidator loanForeclosureValidator, LoanTransactionMapper loanTransactionMapper,
|
LoanForeclosureValidator loanForeclosureValidator, LoanTransactionMapper loanTransactionMapper, LoanMapper loanMapper,
|
||||||
LoanTransactionProcessingService loanTransactionProcessingService) {
|
LoanTransactionProcessingService loanTransactionProcessingService) {
|
||||||
return new LoanReadPlatformServiceImpl(jdbcTemplate, context, loanRepositoryWrapper, applicationCurrencyRepository,
|
return new LoanReadPlatformServiceImpl(jdbcTemplate, context, loanRepositoryWrapper, applicationCurrencyRepository,
|
||||||
loanProductReadPlatformService, clientReadPlatformService, groupReadPlatformService, loanDropdownReadPlatformService,
|
loanProductReadPlatformService, clientReadPlatformService, groupReadPlatformService, loanDropdownReadPlatformService,
|
||||||
fundReadPlatformService, chargeReadPlatformService, codeValueReadPlatformService, calendarReadPlatformService,
|
fundReadPlatformService, chargeReadPlatformService, codeValueReadPlatformService, calendarReadPlatformService,
|
||||||
staffReadPlatformService, paginationHelper, namedParameterJdbcTemplate, paymentTypeReadPlatformService,
|
staffReadPlatformService, paginationHelper, paymentTypeReadPlatformService,
|
||||||
loanRepaymentScheduleTransactionProcessorFactory, floatingRatesReadPlatformService, loanUtilService,
|
loanRepaymentScheduleTransactionProcessorFactory, floatingRatesReadPlatformService, loanUtilService,
|
||||||
configurationDomainService, accountDetailsReadPlatformService, columnValidator, sqlGenerator,
|
configurationDomainService, accountDetailsReadPlatformService, columnValidator, sqlGenerator,
|
||||||
delinquencyReadPlatformService, loanTransactionRepository, loanChargePaidByReadService, loanTransactionRelationReadService,
|
delinquencyReadPlatformService, loanTransactionRepository, loanChargePaidByReadService, loanTransactionRelationReadService,
|
||||||
loanForeclosureValidator, loanTransactionMapper, loanTransactionProcessingService);
|
loanForeclosureValidator, loanTransactionMapper, loanMapper, loanTransactionProcessingService);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@@ -387,9 +390,9 @@ public class LoanAccountConfiguration {
|
|||||||
AccountTransferDetailRepository accountTransferDetailRepository, BusinessEventNotifierService businessEventNotifierService,
|
AccountTransferDetailRepository accountTransferDetailRepository, BusinessEventNotifierService businessEventNotifierService,
|
||||||
GuarantorDomainService guarantorDomainService, LoanUtilService loanUtilService,
|
GuarantorDomainService guarantorDomainService, LoanUtilService loanUtilService,
|
||||||
EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService,
|
EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService,
|
||||||
LoanRepaymentScheduleTransactionProcessorFactory transactionProcessingStrategy, CodeValueRepositoryWrapper codeValueRepository,
|
CodeValueRepositoryWrapper codeValueRepository, CashierTransactionDataValidator cashierTransactionDataValidator,
|
||||||
CashierTransactionDataValidator cashierTransactionDataValidator, GLIMAccountInfoRepository glimRepository,
|
GLIMAccountInfoRepository glimRepository, LoanRepository loanRepository,
|
||||||
LoanRepository loanRepository, RepaymentWithPostDatedChecksAssembler repaymentWithPostDatedChecksAssembler,
|
RepaymentWithPostDatedChecksAssembler repaymentWithPostDatedChecksAssembler,
|
||||||
PostDatedChecksRepository postDatedChecksRepository,
|
PostDatedChecksRepository postDatedChecksRepository,
|
||||||
LoanRepaymentScheduleInstallmentRepository loanRepaymentScheduleInstallmentRepository,
|
LoanRepaymentScheduleInstallmentRepository loanRepaymentScheduleInstallmentRepository,
|
||||||
LoanLifecycleStateMachine defaultLoanLifecycleStateMachine, LoanAccountLockService loanAccountLockService,
|
LoanLifecycleStateMachine defaultLoanLifecycleStateMachine, LoanAccountLockService loanAccountLockService,
|
||||||
@@ -401,6 +404,7 @@ public class LoanAccountConfiguration {
|
|||||||
LoanChargeValidator loanChargeValidator, LoanOfficerService loanOfficerService,
|
LoanChargeValidator loanChargeValidator, LoanOfficerService loanOfficerService,
|
||||||
ReprocessLoanTransactionsService reprocessLoanTransactionsService, LoanAccountService loanAccountService,
|
ReprocessLoanTransactionsService reprocessLoanTransactionsService, LoanAccountService loanAccountService,
|
||||||
LoanJournalEntryPoster journalEntryPoster, LoanAdjustmentService loanAdjustmentService,
|
LoanJournalEntryPoster journalEntryPoster, LoanAdjustmentService loanAdjustmentService,
|
||||||
|
LoanAccountingBridgeMapper loanAccountingBridgeMapper, LoanMapper loanMapper,
|
||||||
LoanTransactionProcessingService loanTransactionProcessingService) {
|
LoanTransactionProcessingService loanTransactionProcessingService) {
|
||||||
return new LoanWritePlatformServiceJpaRepositoryImpl(context, loanTransactionValidator, loanUpdateCommandFromApiJsonDeserializer,
|
return new LoanWritePlatformServiceJpaRepositoryImpl(context, loanTransactionValidator, loanUpdateCommandFromApiJsonDeserializer,
|
||||||
loanRepositoryWrapper, loanAccountDomainService, noteRepository, loanTransactionRepository,
|
loanRepositoryWrapper, loanAccountDomainService, noteRepository, loanTransactionRepository,
|
||||||
@@ -409,14 +413,14 @@ public class LoanAccountConfiguration {
|
|||||||
accountTransfersWritePlatformService, accountTransfersReadPlatformService, accountAssociationsReadPlatformService,
|
accountTransfersWritePlatformService, accountTransfersReadPlatformService, accountAssociationsReadPlatformService,
|
||||||
loanReadPlatformService, fromApiJsonHelper, calendarRepository, loanScheduleHistoryWritePlatformService,
|
loanReadPlatformService, fromApiJsonHelper, calendarRepository, loanScheduleHistoryWritePlatformService,
|
||||||
loanApplicationValidator, accountAssociationRepository, accountTransferDetailRepository, businessEventNotifierService,
|
loanApplicationValidator, accountAssociationRepository, accountTransferDetailRepository, businessEventNotifierService,
|
||||||
guarantorDomainService, loanUtilService, entityDatatableChecksWritePlatformService, transactionProcessingStrategy,
|
guarantorDomainService, loanUtilService, entityDatatableChecksWritePlatformService, codeValueRepository,
|
||||||
codeValueRepository, cashierTransactionDataValidator, glimRepository, loanRepository, repaymentWithPostDatedChecksAssembler,
|
cashierTransactionDataValidator, glimRepository, loanRepository, repaymentWithPostDatedChecksAssembler,
|
||||||
postDatedChecksRepository, loanRepaymentScheduleInstallmentRepository, defaultLoanLifecycleStateMachine,
|
postDatedChecksRepository, loanRepaymentScheduleInstallmentRepository, defaultLoanLifecycleStateMachine,
|
||||||
loanAccountLockService, externalIdFactory, loanAccrualTransactionBusinessEventService, errorHandler,
|
loanAccountLockService, externalIdFactory, loanAccrualTransactionBusinessEventService, errorHandler,
|
||||||
loanDownPaymentHandlerService, loanTransactionAssembler, loanAccrualsProcessingService, loanOfficerValidator,
|
loanDownPaymentHandlerService, loanTransactionAssembler, loanAccrualsProcessingService, loanOfficerValidator,
|
||||||
loanDownPaymentTransactionValidator, loanDisbursementService, loanScheduleService, loanChargeValidator, loanOfficerService,
|
loanDownPaymentTransactionValidator, loanDisbursementService, loanScheduleService, loanChargeValidator, loanOfficerService,
|
||||||
reprocessLoanTransactionsService, loanAccountService, journalEntryPoster, loanAdjustmentService,
|
reprocessLoanTransactionsService, loanAccountService, journalEntryPoster, loanAdjustmentService, loanAccountingBridgeMapper,
|
||||||
loanTransactionProcessingService);
|
loanMapper, loanTransactionProcessingService);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@@ -461,10 +465,11 @@ public class LoanAccountConfiguration {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean(LoanScheduleService.class)
|
@ConditionalOnMissingBean(LoanScheduleService.class)
|
||||||
public LoanScheduleService loanScheduleService(LoanChargeService loanChargeService,
|
public LoanScheduleService loanScheduleService(final LoanChargeService loanChargeService,
|
||||||
ReprocessLoanTransactionsService reprocessLoanTransactionsService,
|
final ReprocessLoanTransactionsService reprocessLoanTransactionsService, final LoanMapper loanMapper,
|
||||||
LoanTransactionProcessingService loanTransactionProcessingService, LoanScheduleComponent loanSchedule) {
|
final LoanTransactionProcessingService loanTransactionProcessingService, LoanScheduleComponent loanSchedule) {
|
||||||
return new LoanScheduleService(loanChargeService, reprocessLoanTransactionsService, loanTransactionProcessingService, loanSchedule);
|
return new LoanScheduleService(loanChargeService, reprocessLoanTransactionsService, loanMapper, loanTransactionProcessingService,
|
||||||
|
loanSchedule);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|||||||
+3
-2
@@ -18,10 +18,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.portfolio.loanaccount.service;
|
package org.apache.fineract.portfolio.loanaccount.service;
|
||||||
|
|
||||||
import static org.mockito.Mockito.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.verifyNoInteractions;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
@@ -89,7 +90,7 @@ public class LoanAccrualsProcessingServiceImplTest {
|
|||||||
verify(loan, times(1)).isClosed();
|
verify(loan, times(1)).isClosed();
|
||||||
|
|
||||||
verify(loanTransactionRepository, never()).saveAndFlush(any());
|
verify(loanTransactionRepository, never()).saveAndFlush(any());
|
||||||
verify(journalEntryWritePlatformService, never()).createJournalEntriesForLoan(any());
|
verifyNoInteractions(journalEntryWritePlatformService);
|
||||||
verify(businessEventNotifierService, never()).notifyPostBusinessEvent(any());
|
verify(businessEventNotifierService, never()).notifyPostBusinessEvent(any());
|
||||||
verify(loan, never()).addLoanTransaction(any());
|
verify(loan, never()).addLoanTransaction(any());
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-1
@@ -19,7 +19,11 @@
|
|||||||
package org.apache.fineract.portfolio.loanaccount.service;
|
package org.apache.fineract.portfolio.loanaccount.service;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyList;
|
||||||
import static org.mockito.ArgumentMatchers.anyLong;
|
import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.Mockito.doNothing;
|
||||||
import static org.mockito.Mockito.mockStatic;
|
import static org.mockito.Mockito.mockStatic;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
@@ -27,6 +31,8 @@ import static org.mockito.Mockito.verify;
|
|||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
|
import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
|
||||||
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||||
@@ -38,6 +44,7 @@ import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
|||||||
import org.apache.fineract.portfolio.charge.domain.Charge;
|
import org.apache.fineract.portfolio.charge.domain.Charge;
|
||||||
import org.apache.fineract.portfolio.charge.domain.ChargePaymentMode;
|
import org.apache.fineract.portfolio.charge.domain.ChargePaymentMode;
|
||||||
import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
|
import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.data.AccountingBridgeDataDTO;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountDomainService;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountDomainService;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountService;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountService;
|
||||||
@@ -46,6 +53,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeRepository;
|
|||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.mapper.LoanAccountingBridgeMapper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeApiJsonValidator;
|
import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeApiJsonValidator;
|
||||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator;
|
import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
||||||
@@ -71,6 +79,7 @@ class LoanChargeWritePlatformServiceImplTest {
|
|||||||
private static final LocalDate BUSINESS_DATE_AFTER = LocalDate.of(2024, 2, 26);
|
private static final LocalDate BUSINESS_DATE_AFTER = LocalDate.of(2024, 2, 26);
|
||||||
private static final LocalDate BUSINESS_DATE_ON = MATURITY_DATE;
|
private static final LocalDate BUSINESS_DATE_ON = MATURITY_DATE;
|
||||||
private static final LocalDate BUSINESS_DATE_BEFORE = LocalDate.of(2024, 2, 14);
|
private static final LocalDate BUSINESS_DATE_BEFORE = LocalDate.of(2024, 2, 14);
|
||||||
|
private static final String CURRENCY_CODE = "USD";
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private LoanChargeWritePlatformServiceImpl loanChargeWritePlatformService;
|
private LoanChargeWritePlatformServiceImpl loanChargeWritePlatformService;
|
||||||
@@ -138,19 +147,35 @@ class LoanChargeWritePlatformServiceImplTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private LoanAccountService loanAccountService;
|
private LoanAccountService loanAccountService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private LoanAccountingBridgeMapper loanAccountingBridgeMapper;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() {
|
void setUp() {
|
||||||
when(loanAssembler.assembleFrom(LOAN_ID)).thenReturn(loan);
|
when(loanAssembler.assembleFrom(LOAN_ID)).thenReturn(loan);
|
||||||
when(chargeRepository.findOneWithNotFoundDetection(anyLong())).thenReturn(chargeDefinition);
|
when(chargeRepository.findOneWithNotFoundDetection(anyLong())).thenReturn(chargeDefinition);
|
||||||
when(chargeDefinition.getChargeTimeType()).thenReturn(SPECIFIED_DUE_DATE);
|
when(chargeDefinition.getChargeTimeType()).thenReturn(SPECIFIED_DUE_DATE);
|
||||||
|
when(chargeDefinition.getCurrencyCode()).thenReturn(CURRENCY_CODE);
|
||||||
when(loanChargeAssembler.createNewFromJson(loan, chargeDefinition, jsonCommand)).thenReturn(loanCharge);
|
when(loanChargeAssembler.createNewFromJson(loan, chargeDefinition, jsonCommand)).thenReturn(loanCharge);
|
||||||
when(loan.repaymentScheduleDetail()).thenReturn(loanRepaymentScheduleDetail);
|
when(loan.repaymentScheduleDetail()).thenReturn(loanRepaymentScheduleDetail);
|
||||||
when(loan.hasCurrencyCodeOf(any())).thenReturn(true);
|
when(loan.hasCurrencyCodeOf(CURRENCY_CODE)).thenReturn(true);
|
||||||
when(loanCharge.getChargePaymentMode()).thenReturn(ChargePaymentMode.REGULAR);
|
when(loanCharge.getChargePaymentMode()).thenReturn(ChargePaymentMode.REGULAR);
|
||||||
when(loan.getStatus()).thenReturn(LoanStatus.ACTIVE);
|
when(loan.getStatus()).thenReturn(LoanStatus.ACTIVE);
|
||||||
when(loanChargeRepository.saveAndFlush(any(LoanCharge.class))).thenReturn(loanCharge);
|
when(loanChargeRepository.saveAndFlush(any(LoanCharge.class))).thenReturn(loanCharge);
|
||||||
when(loan.getCurrency()).thenReturn(monetaryCurrency);
|
when(loan.getCurrency()).thenReturn(monetaryCurrency);
|
||||||
|
when(monetaryCurrency.getCode()).thenReturn(CURRENCY_CODE);
|
||||||
when(loanAccountService.saveAndFlushLoanWithDataIntegrityViolationChecks(any())).thenReturn(loan);
|
when(loanAccountService.saveAndFlushLoanWithDataIntegrityViolationChecks(any())).thenReturn(loan);
|
||||||
|
List<Long> existingTransactionIds = new ArrayList<>();
|
||||||
|
List<Long> existingReversedTransactionIds = new ArrayList<>();
|
||||||
|
when(loan.findExistingTransactionIds()).thenReturn(existingTransactionIds);
|
||||||
|
when(loan.findExistingReversedTransactionIds()).thenReturn(existingReversedTransactionIds);
|
||||||
|
|
||||||
|
when(loan.isPeriodicAccrualAccountingEnabledOnLoanProduct()).thenReturn(false);
|
||||||
|
when(loan.isCashBasedAccountingEnabledOnLoanProduct()).thenReturn(false);
|
||||||
|
when(loan.isUpfrontAccrualAccountingEnabledOnLoanProduct()).thenReturn(false);
|
||||||
|
|
||||||
|
when(loanAccountingBridgeMapper.deriveAccountingBridgeData(anyString(), anyList(), anyList(), anyBoolean(), any(Loan.class))).thenReturn(new AccountingBridgeDataDTO());
|
||||||
|
doNothing().when(journalEntryWritePlatformService).createJournalEntriesForLoan(any(AccountingBridgeDataDTO.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@@ -160,6 +185,10 @@ class LoanChargeWritePlatformServiceImplTest {
|
|||||||
when(loan.getMaturityDate()).thenReturn(maturityDate);
|
when(loan.getMaturityDate()).thenReturn(maturityDate);
|
||||||
when(loan.handleChargeAppliedTransaction(loanCharge, null)).thenReturn(loanTransaction);
|
when(loan.handleChargeAppliedTransaction(loanCharge, null)).thenReturn(loanTransaction);
|
||||||
|
|
||||||
|
if (isAccrualExpected) {
|
||||||
|
when(loan.isPeriodicAccrualAccountingEnabledOnLoanProduct()).thenReturn(true);
|
||||||
|
}
|
||||||
|
|
||||||
try (MockedStatic<DateUtils> mockedDateUtils = mockStatic(DateUtils.class)) {
|
try (MockedStatic<DateUtils> mockedDateUtils = mockStatic(DateUtils.class)) {
|
||||||
mockedDateUtils.when(DateUtils::getBusinessLocalDate).thenReturn(businessDate);
|
mockedDateUtils.when(DateUtils::getBusinessLocalDate).thenReturn(businessDate);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user