waive and payment of installment charge corrections
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
CREATE TABLE `m_loan_installment_charge` (
|
||||
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
`loan_charge_id` BIGINT(20) NOT NULL,
|
||||
`loan_schedule_id` BIGINT(20) NOT NULL,
|
||||
`due_date` DATE NULL DEFAULT NULL,
|
||||
`amount` DECIMAL(19,6) NOT NULL,
|
||||
`amount_paid_derived` DECIMAL(19,6) NULL DEFAULT NULL,
|
||||
`amount_waived_derived` DECIMAL(19,6) NULL DEFAULT NULL,
|
||||
`amount_writtenoff_derived` DECIMAL(19,6) NULL DEFAULT NULL,
|
||||
`amount_outstanding_derived` DECIMAL(19,6) NOT NULL DEFAULT '0.000000',
|
||||
`is_paid_derived` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
`waived` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
`amount_through_charge_payment` DECIMAL(19,6) NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
CONSTRAINT `FK_loan_charge_id_charge_schedule` FOREIGN KEY (`loan_charge_id`) REFERENCES `m_loan_charge` (`id`),
|
||||
CONSTRAINT `FK_loan_schedule_id_charge_schedule` FOREIGN KEY (`loan_schedule_id`) REFERENCES `m_loan_repayment_schedule` (`id`)
|
||||
)
|
||||
COLLATE='utf8_general_ci'
|
||||
ENGINE=InnoDB;
|
||||
+3
-18
@@ -21,45 +21,32 @@ import org.mifosplatform.portfolio.charge.domain.ChargeTimeType;
|
||||
public class LoanChargeData {
|
||||
|
||||
private final Long id;
|
||||
@SuppressWarnings("unused")
|
||||
private final Long chargeId;
|
||||
@SuppressWarnings("unused")
|
||||
private final String name;
|
||||
@SuppressWarnings("unused")
|
||||
private final EnumOptionData chargeTimeType;
|
||||
|
||||
private final LocalDate dueDate;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final EnumOptionData chargeCalculationType;
|
||||
|
||||
private final BigDecimal percentage;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal amountPercentageAppliedTo;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final CurrencyData currency;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal amount;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal amountPaid;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal amountWaived;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal amountWrittenOff;
|
||||
|
||||
private final BigDecimal amountOutstanding;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal amountOrPercentage;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final Collection<ChargeData> chargeOptions;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final boolean penalty;
|
||||
|
||||
private final EnumOptionData chargePaymentMode;
|
||||
@@ -68,17 +55,15 @@ public class LoanChargeData {
|
||||
|
||||
private final boolean waived;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final boolean chargePayable;
|
||||
|
||||
private final Long loanId;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal minCap;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal maxCap;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final Collection<LoanInstallmentChargeData> installmentChargeData;
|
||||
|
||||
public static LoanChargeData template(final Collection<ChargeData> chargeOptions) {
|
||||
@@ -181,7 +166,7 @@ public class LoanChargeData {
|
||||
this.installmentChargeData = installmentChargeData;
|
||||
}
|
||||
|
||||
public LoanChargeData(final Long id, final LocalDate dueAsOfDate, final BigDecimal amountOutstanding, final Long loanId, Collection<LoanInstallmentChargeData> installmentChargeData) {
|
||||
public LoanChargeData(final Long id, final LocalDate dueAsOfDate, final BigDecimal amountOutstanding, EnumOptionData chargeTimeType, final Long loanId, Collection<LoanInstallmentChargeData> installmentChargeData) {
|
||||
this.id = id;
|
||||
this.chargeId = null;
|
||||
this.name = null;
|
||||
@@ -191,7 +176,7 @@ public class LoanChargeData {
|
||||
this.amountWaived = null;
|
||||
this.amountWrittenOff = null;
|
||||
this.amountOutstanding = amountOutstanding;
|
||||
this.chargeTimeType = null;
|
||||
this.chargeTimeType = chargeTimeType;
|
||||
this.dueDate = dueAsOfDate;
|
||||
this.chargeCalculationType = null;
|
||||
this.percentage = null;
|
||||
|
||||
+17
-6
@@ -885,8 +885,9 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
public void updateLoanSchedule(final LoanScheduleModel modifiedLoanSchedule) {
|
||||
clearInstallmentLoanCharge();
|
||||
this.repaymentScheduleInstallments.clear();
|
||||
|
||||
|
||||
for (final LoanScheduleModelPeriod scheduledLoanInstallment : modifiedLoanSchedule.getPeriods()) {
|
||||
|
||||
if (scheduledLoanInstallment.isRepaymentPeriod()) {
|
||||
@@ -901,6 +902,15 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
|
||||
updateLoanScheduleDependentDerivedFields();
|
||||
updateLoanSummaryDerivedFields();
|
||||
|
||||
}
|
||||
|
||||
private void clearInstallmentLoanCharge(){
|
||||
for(LoanCharge loanCharge:this.charges){
|
||||
if(loanCharge.isInstalmentFee()){
|
||||
loanCharge.clearLoanInstallmentCharges();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateLoanScheduleDependentDerivedFields() {
|
||||
@@ -2979,20 +2989,21 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
return this.charges;
|
||||
}
|
||||
|
||||
public Set<LoanInstallmentCharge> createInstallmentLoanCharges(final LoanCharge loanCharge){
|
||||
public Set<LoanInstallmentCharge> generateInstallmentLoanCharges(final LoanCharge loanCharge){
|
||||
Set<LoanInstallmentCharge> loanChargePerInstallments = new HashSet<LoanInstallmentCharge>();
|
||||
if(loanCharge.isInstalmentFee()){
|
||||
for (final LoanRepaymentScheduleInstallment installment : this.repaymentScheduleInstallments) {
|
||||
BigDecimal amount = BigDecimal.ZERO;;
|
||||
BigDecimal amount = BigDecimal.ZERO;
|
||||
if(loanCharge.getChargeCalculation().isFlat()){
|
||||
amount = loanCharge.amount();
|
||||
amount = loanCharge.amount().divide(BigDecimal.valueOf(repaymentScheduleDetail().getNumberOfRepayments()));
|
||||
}else{
|
||||
amount = calculateInstallmentChargeAmount(loanCharge.getChargeCalculation(), loanCharge.getPercentage(), installment).getAmount();
|
||||
}
|
||||
LoanInstallmentCharge loanChargePerInstallment = new LoanInstallmentCharge(amount, loanCharge, installment);
|
||||
loanChargePerInstallments.add(loanChargePerInstallment);
|
||||
LoanInstallmentCharge loanInstallmentCharge = new LoanInstallmentCharge(amount, loanCharge, installment);
|
||||
loanChargePerInstallments.add(loanInstallmentCharge);
|
||||
}
|
||||
}
|
||||
return loanChargePerInstallments;
|
||||
}
|
||||
|
||||
}
|
||||
+50
-22
@@ -8,6 +8,7 @@ package org.mifosplatform.portfolio.loanaccount.domain;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -107,7 +108,7 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
||||
|
||||
@LazyCollection(LazyCollectionOption.FALSE)
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loancharge", orphanRemoval = true)
|
||||
private Set<LoanInstallmentCharge> loanChargePerInstallments = new HashSet<LoanInstallmentCharge>();
|
||||
private Set<LoanInstallmentCharge> loanInstallmentCharge = new HashSet<LoanInstallmentCharge>();
|
||||
|
||||
public static LoanCharge createNewFromJson(final Loan loan, final Charge chargeDefinition, final JsonCommand command) {
|
||||
|
||||
@@ -248,14 +249,14 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
||||
}
|
||||
this.amountOrPercentage = chargeAmount;
|
||||
if(this.loan!=null && this.isInstalmentFee()){
|
||||
Set<LoanInstallmentCharge> chargePerInstallments = this.loan.createInstallmentLoanCharges(this);
|
||||
if(this.loanChargePerInstallments.isEmpty()){
|
||||
this.loanChargePerInstallments.addAll(chargePerInstallments);
|
||||
Set<LoanInstallmentCharge> chargePerInstallments = this.loan.generateInstallmentLoanCharges(this);
|
||||
if(this.loanInstallmentCharge.isEmpty()){
|
||||
this.loanInstallmentCharge.addAll(chargePerInstallments);
|
||||
}else{
|
||||
int index = 0;
|
||||
LoanInstallmentCharge[] loanChargePerInstallments = new LoanInstallmentCharge[chargePerInstallments.size()];
|
||||
LoanInstallmentCharge[] loanChargePerInstallmentArray = chargePerInstallments.toArray(loanChargePerInstallments);
|
||||
for(LoanInstallmentCharge chargePerInstallment:this.loanChargePerInstallments){
|
||||
for(LoanInstallmentCharge chargePerInstallment:this.loanInstallmentCharge){
|
||||
chargePerInstallment.copyFrom(loanChargePerInstallmentArray[index++]);
|
||||
}
|
||||
}
|
||||
@@ -275,12 +276,18 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
||||
this.amountOutstanding = calculateAmountOutstanding(currency);
|
||||
this.paid = false;
|
||||
this.waived = false;
|
||||
for(LoanInstallmentCharge installmentCharge:loanInstallmentCharge){
|
||||
installmentCharge.resetPaidAmount(currency);
|
||||
}
|
||||
}
|
||||
|
||||
public void resetPaidAmount(final MonetaryCurrency currency) {
|
||||
this.amountPaid = BigDecimal.ZERO;
|
||||
this.amountOutstanding = calculateAmountOutstanding(currency);
|
||||
this.paid = false;
|
||||
for(LoanInstallmentCharge installmentCharge:loanInstallmentCharge){
|
||||
installmentCharge.resetPaidAmount(currency);
|
||||
}
|
||||
}
|
||||
|
||||
public Money waive(final MonetaryCurrency currency, Integer loanInstallmentNumber) {
|
||||
@@ -347,14 +354,14 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
||||
}
|
||||
this.amountOrPercentage = amount;
|
||||
if(this.loan !=null && this.isInstalmentFee()){
|
||||
Set<LoanInstallmentCharge> chargePerInstallments = this.loan.createInstallmentLoanCharges(this);
|
||||
if(this.loanChargePerInstallments.isEmpty()){
|
||||
this.loanChargePerInstallments.addAll(chargePerInstallments);
|
||||
Set<LoanInstallmentCharge> chargePerInstallments = this.loan.generateInstallmentLoanCharges(this);
|
||||
if(this.loanInstallmentCharge.isEmpty()){
|
||||
this.loanInstallmentCharge.addAll(chargePerInstallments);
|
||||
}else{
|
||||
int index = 0;
|
||||
LoanInstallmentCharge[] loanChargePerInstallments = new LoanInstallmentCharge[chargePerInstallments.size()];
|
||||
LoanInstallmentCharge[] loanChargePerInstallmentArray = chargePerInstallments.toArray(loanChargePerInstallments);
|
||||
for(LoanInstallmentCharge chargePerInstallment:this.loanChargePerInstallments){
|
||||
for(LoanInstallmentCharge chargePerInstallment:this.loanInstallmentCharge){
|
||||
chargePerInstallment.copyFrom(loanChargePerInstallmentArray[index++]);
|
||||
}
|
||||
}
|
||||
@@ -410,14 +417,14 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
||||
}
|
||||
this.amountOrPercentage = newValue;
|
||||
if(this.isInstalmentFee()){
|
||||
Set<LoanInstallmentCharge> chargePerInstallments = this.loan.createInstallmentLoanCharges(this);
|
||||
if(this.loanChargePerInstallments.isEmpty()){
|
||||
this.loanChargePerInstallments.addAll(chargePerInstallments);
|
||||
Set<LoanInstallmentCharge> chargePerInstallments = this.loan.generateInstallmentLoanCharges(this);
|
||||
if(this.loanInstallmentCharge.isEmpty()){
|
||||
this.loanInstallmentCharge.addAll(chargePerInstallments);
|
||||
}else{
|
||||
int index = 0;
|
||||
LoanInstallmentCharge[] loanChargePerInstallments = new LoanInstallmentCharge[chargePerInstallments.size()];
|
||||
LoanInstallmentCharge[] loanChargePerInstallmentArray = chargePerInstallments.toArray(loanChargePerInstallments);
|
||||
for(LoanInstallmentCharge chargePerInstallment:this.loanChargePerInstallments){
|
||||
for(LoanInstallmentCharge chargePerInstallment:this.loanInstallmentCharge){
|
||||
chargePerInstallment.copyFrom(loanChargePerInstallmentArray[index++]);
|
||||
}
|
||||
}
|
||||
@@ -603,17 +610,18 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param feeAmount TODO
|
||||
* @param processAmount
|
||||
* Amount used to pay off this charge
|
||||
* @return Actual amount paid on this charge
|
||||
*/
|
||||
public Money updatePaidAmountBy(final Money incrementBy,final Integer installmentNumber) {
|
||||
public Money updatePaidAmountBy(final Money incrementBy,final Integer installmentNumber, Money feeAmount) {
|
||||
Money processAmount = Money.zero(incrementBy.getCurrency());
|
||||
if(this.isInstalmentFee()){
|
||||
if(installmentNumber == null){
|
||||
processAmount = getUnpaidInstallmentLoanCharge().updatePaidAmountBy(incrementBy);
|
||||
processAmount = getUnpaidInstallmentLoanCharge().updatePaidAmountBy(incrementBy, feeAmount);
|
||||
}else{
|
||||
processAmount = getInstallmentLoanCharge(installmentNumber).updatePaidAmountBy(incrementBy);
|
||||
processAmount = getInstallmentLoanCharge(installmentNumber).updatePaidAmountBy(incrementBy, feeAmount);
|
||||
}
|
||||
}else{
|
||||
processAmount = incrementBy;
|
||||
@@ -631,9 +639,7 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
||||
amountPaidOnThisCharge = processAmount;
|
||||
amountPaidToDate = amountPaidToDate.plus(processAmount);
|
||||
this.amountPaid = amountPaidToDate.getAmount();
|
||||
|
||||
final Money amountExpected = Money.of(processAmount.getCurrency(), this.amount);
|
||||
this.amountOutstanding = amountExpected.minus(amountPaidToDate).getAmount();
|
||||
this.amountOutstanding = calculateAmountOutstanding(incrementBy.getCurrency());
|
||||
}
|
||||
|
||||
this.paid = determineIfFullyPaid();
|
||||
@@ -695,7 +701,7 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
||||
|
||||
public LoanInstallmentCharge getUnpaidInstallmentLoanCharge() {
|
||||
LoanInstallmentCharge unpaidChargePerInstallment = null;
|
||||
for (LoanInstallmentCharge loanChargePerInstallment : this.loanChargePerInstallments) {
|
||||
for (LoanInstallmentCharge loanChargePerInstallment : this.loanInstallmentCharge) {
|
||||
if (loanChargePerInstallment.isPending()
|
||||
&& (unpaidChargePerInstallment == null || unpaidChargePerInstallment.getRepaymentInstallment().getDueDate()
|
||||
.isAfter(loanChargePerInstallment.getRepaymentInstallment().getDueDate()))) {
|
||||
@@ -706,7 +712,7 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
public LoanInstallmentCharge getInstallmentLoanCharge(LocalDate periodDueDate) {
|
||||
for (LoanInstallmentCharge loanChargePerInstallment : this.loanChargePerInstallments) {
|
||||
for (LoanInstallmentCharge loanChargePerInstallment : this.loanInstallmentCharge) {
|
||||
if (periodDueDate.isEqual(loanChargePerInstallment.getRepaymentInstallment().getDueDate())) {
|
||||
return loanChargePerInstallment;
|
||||
}
|
||||
@@ -715,11 +721,33 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
public LoanInstallmentCharge getInstallmentLoanCharge(Integer installmentNumber) {
|
||||
for (LoanInstallmentCharge loanChargePerInstallment : this.loanChargePerInstallments) {
|
||||
for (LoanInstallmentCharge loanChargePerInstallment : this.loanInstallmentCharge) {
|
||||
if (installmentNumber.equals(loanChargePerInstallment.getRepaymentInstallment().getInstallmentNumber().intValue()) ){
|
||||
return loanChargePerInstallment;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void clearLoanInstallmentCharges(){
|
||||
this.loanInstallmentCharge.clear();
|
||||
}
|
||||
|
||||
public void addLoanInstallmentCharges(Collection<LoanInstallmentCharge> installmentCharges){
|
||||
this.loanInstallmentCharge.addAll(installmentCharges);
|
||||
}
|
||||
|
||||
public boolean hasNoLoanInstallmentCharges(){
|
||||
return this.loanInstallmentCharge.isEmpty();
|
||||
}
|
||||
|
||||
public LoanRepaymentScheduleInstallment fetchRepaymentInstallment(Money trasferedAmount){
|
||||
for (LoanInstallmentCharge loanChargePerInstallment : this.loanInstallmentCharge) {
|
||||
if (loanChargePerInstallment.isPending() &&
|
||||
trasferedAmount.getAmount().equals(loanChargePerInstallment.getAmountThroughChargePayment(trasferedAmount.getCurrency()).getAmount()) ){
|
||||
return loanChargePerInstallment.getRepaymentInstallment();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+40
-6
@@ -44,6 +44,9 @@ public class LoanInstallmentCharge extends AbstractPersistable<Long> {
|
||||
|
||||
@Column(name = "amount_outstanding_derived", scale = 6, precision = 19, nullable = false)
|
||||
private BigDecimal amountOutstanding;
|
||||
|
||||
@Column(name = "amount_through_charge_payment", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal amountThroughChargePayment;
|
||||
|
||||
@Column(name = "is_paid_derived", nullable = false)
|
||||
private boolean paid = false;
|
||||
@@ -122,12 +125,24 @@ public class LoanInstallmentCharge extends AbstractPersistable<Long> {
|
||||
public BigDecimal getAmount() {
|
||||
return this.amount;
|
||||
}
|
||||
|
||||
|
||||
public Money getAmount(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.amount);
|
||||
}
|
||||
|
||||
private Money getAmountPaid(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.amountPaid);
|
||||
}
|
||||
|
||||
public BigDecimal getAmountOutstanding() {
|
||||
return this.amountOutstanding;
|
||||
}
|
||||
|
||||
private BigDecimal calculateAmountOutstanding(final MonetaryCurrency currency) {
|
||||
return getAmount(currency).minus(getAmountWaived(currency)).minus(getAmountPaid(currency)).getAmount();
|
||||
}
|
||||
|
||||
|
||||
public boolean isPaid() {
|
||||
return this.paid;
|
||||
}
|
||||
@@ -145,7 +160,7 @@ public class LoanInstallmentCharge extends AbstractPersistable<Long> {
|
||||
return this.installment;
|
||||
}
|
||||
|
||||
public Money updatePaidAmountBy(final Money incrementBy) {
|
||||
public Money updatePaidAmountBy(final Money incrementBy, Money feeAmount) {
|
||||
|
||||
Money amountPaidToDate = Money.of(incrementBy.getCurrency(), this.amountPaid);
|
||||
final Money amountOutstanding = Money.of(incrementBy.getCurrency(), this.amountOutstanding);
|
||||
@@ -160,11 +175,9 @@ public class LoanInstallmentCharge extends AbstractPersistable<Long> {
|
||||
amountPaidOnThisCharge = incrementBy;
|
||||
amountPaidToDate = amountPaidToDate.plus(incrementBy);
|
||||
this.amountPaid = amountPaidToDate.getAmount();
|
||||
|
||||
final Money amountExpected = Money.of(incrementBy.getCurrency(), this.amount);
|
||||
this.amountOutstanding = amountExpected.minus(amountPaidToDate).getAmount();
|
||||
this.amountOutstanding = calculateAmountOutstanding(incrementBy.getCurrency());
|
||||
}
|
||||
|
||||
this.amountThroughChargePayment = feeAmount.getAmount();
|
||||
this.paid = determineIfFullyPaid();
|
||||
|
||||
return amountPaidOnThisCharge;
|
||||
@@ -174,4 +187,25 @@ public class LoanInstallmentCharge extends AbstractPersistable<Long> {
|
||||
public Money getAmountWrittenOff(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.amountWrittenOff);
|
||||
}
|
||||
|
||||
public void resetPaidAmount(final MonetaryCurrency currency) {
|
||||
this.amountPaid = BigDecimal.ZERO;
|
||||
this.amountOutstanding = calculateAmountOutstanding(currency);
|
||||
this.paid = false;
|
||||
}
|
||||
|
||||
public void resetToOriginal(final MonetaryCurrency currency) {
|
||||
this.amountPaid = BigDecimal.ZERO;
|
||||
this.amountWaived = BigDecimal.ZERO;
|
||||
this.amountWrittenOff = BigDecimal.ZERO;
|
||||
this.amountOutstanding = calculateAmountOutstanding(currency);
|
||||
this.paid = false;
|
||||
this.waived = false;
|
||||
}
|
||||
|
||||
|
||||
public Money getAmountThroughChargePayment(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.amountThroughChargePayment);
|
||||
}
|
||||
|
||||
}
|
||||
+1
-5
@@ -13,6 +13,7 @@ import java.util.Set;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
@@ -105,11 +106,6 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
|
||||
@Column(name = "obligations_met_on_date")
|
||||
private Date obligationsMetOnDate;
|
||||
|
||||
@LazyCollection(LazyCollectionOption.FALSE)
|
||||
@OneToMany(cascade = CascadeType.ALL)
|
||||
private Set<LoanInstallmentCharge> loanChargePerInstallments = new HashSet<LoanInstallmentCharge>();
|
||||
|
||||
|
||||
protected LoanRepaymentScheduleInstallment() {
|
||||
this.installmentNumber = null;
|
||||
this.fromDate = null;
|
||||
|
||||
+19
-3
@@ -69,12 +69,24 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
final List<LoanTransaction> transactionstoBeProcessed = new ArrayList<LoanTransaction>();
|
||||
for (final LoanTransaction loanTransaction : transactionsPostDisbursement) {
|
||||
if (loanTransaction.isChargePayment()) {
|
||||
final List<LoanRepaymentScheduleInstallment> chargePaymentInstallments = new ArrayList<LoanRepaymentScheduleInstallment>();
|
||||
final Set<LoanChargePaidBy> chargePaidBies = loanTransaction.getLoanChargesPaid();
|
||||
final Set<LoanCharge> transferCharges = new HashSet<LoanCharge>();
|
||||
for (final LoanChargePaidBy chargePaidBy : chargePaidBies) {
|
||||
transferCharges.add(chargePaidBy.getLoanCharge());
|
||||
LoanCharge loanCharge = chargePaidBy.getLoanCharge();
|
||||
transferCharges.add(loanCharge);
|
||||
if(loanCharge.isInstalmentFee()){
|
||||
LoanRepaymentScheduleInstallment installment = null;
|
||||
if(loanCharge.isFeeCharge()){
|
||||
installment = loanCharge.fetchRepaymentInstallment(loanTransaction.getFeeChargesPortion(currency));
|
||||
}else{
|
||||
installment = loanCharge.fetchRepaymentInstallment(loanTransaction.getPenaltyChargesPortion(currency));
|
||||
}
|
||||
if(installment !=null){
|
||||
chargePaymentInstallments.add(installment);
|
||||
}
|
||||
}
|
||||
}
|
||||
final List<LoanRepaymentScheduleInstallment> chargePaymentInstallments = new ArrayList<LoanRepaymentScheduleInstallment>();
|
||||
LocalDate startDate = disbursementDate;
|
||||
for (final LoanRepaymentScheduleInstallment installment : installments) {
|
||||
for (final LoanCharge loanCharge : transferCharges) {
|
||||
@@ -221,7 +233,11 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
Money amountRemaining = feeCharges;
|
||||
while(amountRemaining.isGreaterThanZero()) {
|
||||
final LoanCharge unpaidCharge = findEarliestUnpaidChargeFromUnOrderedSet(charges);
|
||||
final Money amountPaidTowardsCharge = unpaidCharge.updatePaidAmountBy(amountRemaining,installmentNumber);
|
||||
Money feeAmount = feeCharges.zero();
|
||||
if(loanTransaction.isChargePayment()){
|
||||
feeAmount = feeCharges;
|
||||
}
|
||||
final Money amountPaidTowardsCharge = unpaidCharge.updatePaidAmountBy(amountRemaining,installmentNumber, feeAmount);
|
||||
if (!amountPaidTowardsCharge.isZero()) {
|
||||
if (!loanTransaction.isChargePayment()) {
|
||||
final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(loanTransaction, unpaidCharge,
|
||||
|
||||
+17
-2
@@ -5,8 +5,10 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.loanaccount.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -47,6 +49,8 @@ import org.mifosplatform.portfolio.group.exception.GroupNotActiveException;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.DefaultLoanLifecycleStateMachine;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanChargeRepository;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanInstallmentCharge;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
|
||||
@@ -109,6 +113,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
private final CalendarInstanceRepository calendarInstanceRepository;
|
||||
private final SavingsAccountAssembler savingsAccountAssembler;
|
||||
private final AccountAssociationsRepository accountAssociationsRepository;
|
||||
private final LoanChargeRepository loanChargeRepository;
|
||||
|
||||
@Autowired
|
||||
public LoanApplicationWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final FromJsonHelper fromJsonHelper,
|
||||
@@ -122,7 +127,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
final LoanSummaryWrapper loanSummaryWrapper, final GroupRepositoryWrapper groupRepository,
|
||||
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
|
||||
final CalendarRepository calendarRepository, final CalendarInstanceRepository calendarInstanceRepository,
|
||||
final SavingsAccountAssembler savingsAccountAssembler, final AccountAssociationsRepository accountAssociationsRepository) {
|
||||
final SavingsAccountAssembler savingsAccountAssembler, final AccountAssociationsRepository accountAssociationsRepository,
|
||||
final LoanChargeRepository loanChargeRepository) {
|
||||
this.context = context;
|
||||
this.fromJsonHelper = fromJsonHelper;
|
||||
this.loanApplicationTransitionApiJsonValidator = loanApplicationTransitionApiJsonValidator;
|
||||
@@ -145,6 +151,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
this.calendarInstanceRepository = calendarInstanceRepository;
|
||||
this.savingsAccountAssembler = savingsAccountAssembler;
|
||||
this.accountAssociationsRepository = accountAssociationsRepository;
|
||||
this.loanChargeRepository = loanChargeRepository;
|
||||
}
|
||||
|
||||
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
|
||||
@@ -333,7 +340,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
|
||||
if (changes.containsKey("recalculateLoanSchedule")) {
|
||||
changes.remove("recalculateLoanSchedule");
|
||||
|
||||
|
||||
final JsonElement parsedQuery = this.fromJsonHelper.parse(command.json());
|
||||
final JsonQuery query = JsonQuery.from(command.json(), parsedQuery, this.fromJsonHelper);
|
||||
|
||||
@@ -354,6 +361,14 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
final Note note = Note.loanNote(existingLoanApplication, submittedOnNote);
|
||||
this.noteRepository.save(note);
|
||||
}
|
||||
|
||||
for (final LoanCharge loanCharge : existingLoanApplication.charges()) {
|
||||
if(loanCharge.isInstalmentFee() && loanCharge.hasNoLoanInstallmentCharges()){
|
||||
Set<LoanInstallmentCharge> chargePerInstallments = existingLoanApplication.generateInstallmentLoanCharges(loanCharge);
|
||||
loanCharge.addLoanInstallmentCharges(chargePerInstallments);
|
||||
this.loanChargeRepository.save(loanCharge);
|
||||
}
|
||||
}
|
||||
|
||||
final Long calendarId = command.longValueOfParameterNamed("calendarId");
|
||||
Calendar calendar = null;
|
||||
|
||||
+10
-4
@@ -169,7 +169,10 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
|
||||
|
||||
public String schema() {
|
||||
return "lc.id as id, lc.due_for_collection_as_of_date as dueAsOfDate, "
|
||||
+ "lc.amount_outstanding_derived as amountOutstanding, " + "loan.id as loanId " + "from m_loan_charge lc "
|
||||
+ "lc.amount_outstanding_derived as amountOutstanding, "
|
||||
+ "lc.charge_time_enum as chargeTime, "
|
||||
+ "loan.id as loanId "
|
||||
+ "from m_loan_charge lc "
|
||||
+ "join m_loan loan on loan.id = lc.loan_id ";
|
||||
}
|
||||
|
||||
@@ -180,7 +183,10 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
|
||||
final LocalDate dueAsOfDate = JdbcSupport.getLocalDate(rs, "dueAsOfDate");
|
||||
final Long loanId = rs.getLong("loanId");
|
||||
final BigDecimal amountOutstanding = rs.getBigDecimal("amountOutstanding");
|
||||
return new LoanChargeData(id, dueAsOfDate, amountOutstanding, loanId, null);
|
||||
final int chargeTime = rs.getInt("chargeTime");
|
||||
final EnumOptionData chargeTimeType = ChargeEnumerations.chargeTimeType(chargeTime);
|
||||
|
||||
return new LoanChargeData(id, dueAsOfDate, amountOutstanding, chargeTimeType, loanId, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,7 +196,7 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
|
||||
String sql = "select " + rm.schema()
|
||||
+ "where lic.loan_charge_id= ? ";
|
||||
if(onlyPaymentPendingCharges){
|
||||
sql = sql +"and lc.waived =0 and lc.is_paid_derived=0";
|
||||
sql = sql +"and lic.waived =0 and lic.is_paid_derived=0";
|
||||
}
|
||||
return this.jdbcTemplate.query(sql, rm, new Object[] { loanChargeId });
|
||||
}
|
||||
@@ -200,7 +206,7 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
|
||||
public String schema() {
|
||||
return " lsi.installment as installmentNumber, lsi.duedate as dueAsOfDate, "
|
||||
+ "lic.amount_outstanding_derived as amountOutstanding,"
|
||||
+ "lic.amount as amount"
|
||||
+ "lic.amount as amount, "
|
||||
+ "lic.is_paid_derived as paid, "
|
||||
+ "lic.waived as waied "
|
||||
+ "from m_loan_installment_charge lic "
|
||||
|
||||
+33
-7
@@ -266,6 +266,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
for (final LoanCharge loanCharge : loanCharges) {
|
||||
if (loanCharge.isDueAtDisbursement() && loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()) {
|
||||
disBuLoanCharges.put(loanCharge.getId(), loanCharge.amount());
|
||||
}else if(loanCharge.isInstalmentFee() && loanCharge.hasNoLoanInstallmentCharges()){
|
||||
Set<LoanInstallmentCharge> chargePerInstallments = loan.generateInstallmentLoanCharges(loanCharge);
|
||||
loanCharge.addLoanInstallmentCharges(chargePerInstallments);
|
||||
this.loanChargeRepository.save(loanCharge);
|
||||
}
|
||||
}
|
||||
final Locale locale = command.extractLocale();
|
||||
@@ -384,6 +388,26 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||
}
|
||||
final Set<LoanCharge> loanCharges = loan.charges();
|
||||
final Map<Long, BigDecimal> disBuLoanCharges = new HashMap<Long, BigDecimal>();
|
||||
for (final LoanCharge loanCharge : loanCharges) {
|
||||
if (loanCharge.isDueAtDisbursement() && loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()) {
|
||||
disBuLoanCharges.put(loanCharge.getId(), loanCharge.amount());
|
||||
}else if(loanCharge.isInstalmentFee() && loanCharge.hasNoLoanInstallmentCharges()){
|
||||
Set<LoanInstallmentCharge> chargePerInstallments = loan.generateInstallmentLoanCharges(loanCharge);
|
||||
loanCharge.addLoanInstallmentCharges(chargePerInstallments);
|
||||
this.loanChargeRepository.save(loanCharge);
|
||||
}
|
||||
}
|
||||
final Locale locale = command.extractLocale();
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
for (final Map.Entry<Long, BigDecimal> entrySet : disBuLoanCharges.entrySet()) {
|
||||
final PortfolioAccountData savingAccountData = this.accountAssociationsReadPlatformService.retriveLoanAssociation(loan.getId());
|
||||
final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(actualDisbursementDate, entrySet.getValue(),
|
||||
PortfolioAccountType.SAVINGS, PortfolioAccountType.LOAN, savingAccountData.accountId(), loan.getId(), "Loan Charge Payment",
|
||||
locale, fmt, null, null, LoanTransactionType.REPAYMENT_AT_DISBURSEMENT.getValue(), entrySet.getKey(), null);
|
||||
this.accountTransfersWritePlatformService.transferFunds(accountTransferDTO);
|
||||
}
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
@@ -933,12 +957,14 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
Integer loanInstallmentNumber = null;
|
||||
if (loanCharge.isInstalmentFee()){
|
||||
LoanInstallmentCharge chargePerInstallment = null;
|
||||
final LocalDate dueDate = command.localDateValueOfParameterNamed("dueDate");
|
||||
final Integer installmentNumber = command.integerValueOfParameterNamed("installmentNumber");
|
||||
if(dueDate !=null){
|
||||
chargePerInstallment = loanCharge.getInstallmentLoanCharge(dueDate);
|
||||
}else if(installmentNumber!=null){
|
||||
chargePerInstallment = loanCharge.getInstallmentLoanCharge(installmentNumber);
|
||||
if(!StringUtils.isBlank(command.json())){
|
||||
final LocalDate dueDate = command.localDateValueOfParameterNamed("dueDate");
|
||||
final Integer installmentNumber = command.integerValueOfParameterNamed("installmentNumber");
|
||||
if(dueDate !=null){
|
||||
chargePerInstallment = loanCharge.getInstallmentLoanCharge(dueDate);
|
||||
}else if(installmentNumber!=null){
|
||||
chargePerInstallment = loanCharge.getInstallmentLoanCharge(installmentNumber);
|
||||
}
|
||||
}
|
||||
if(chargePerInstallment == null){
|
||||
chargePerInstallment = loanCharge.getUnpaidInstallmentLoanCharge();
|
||||
@@ -1090,7 +1116,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
Collection<LoanInstallmentChargeData> chargePerInstallments = this.LoanChargeReadPlatformService.retrieveInstallmentLoanCharges(chargeData.getId(), true);
|
||||
PortfolioAccountData portfolioAccountData = null;
|
||||
for(LoanInstallmentChargeData installmentChargeData : chargePerInstallments){
|
||||
if(installmentChargeData.getDueDate().isAfter(new LocalDate())){
|
||||
if(!installmentChargeData.getDueDate().isAfter(new LocalDate())){
|
||||
if(portfolioAccountData == null){
|
||||
portfolioAccountData = this.accountAssociationsReadPlatformService
|
||||
.retriveLoanAssociation(chargeData.getLoanId());
|
||||
|
||||
Reference in New Issue
Block a user