waive and payment of installment charge corrections

This commit is contained in:
Pramod Nuthakki
2013-11-13 11:45:59 +05:30
parent 51d8083dc5
commit d15b40bf33
10 changed files with 209 additions and 73 deletions
@@ -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;
@@ -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;
@@ -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;
}
}
@@ -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;
}
}
@@ -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);
}
}
@@ -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;
@@ -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,
@@ -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;
@@ -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 "
@@ -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());