Merge pull request #1043 from pramodn02/develop
MIFOSX-1421 : corrected interest calculation for different interest comp...
This commit is contained in:
+24
-41
@@ -964,7 +964,6 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void updateLoanSchedule(final LoanScheduleModel modifiedLoanSchedule) {
|
public void updateLoanSchedule(final LoanScheduleModel modifiedLoanSchedule) {
|
||||||
clearInstallmentLoanCharge();
|
|
||||||
this.repaymentScheduleInstallments.clear();
|
this.repaymentScheduleInstallments.clear();
|
||||||
|
|
||||||
for (final LoanScheduleModelPeriod scheduledLoanInstallment : modifiedLoanSchedule.getPeriods()) {
|
for (final LoanScheduleModelPeriod scheduledLoanInstallment : modifiedLoanSchedule.getPeriods()) {
|
||||||
@@ -984,14 +983,6 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearInstallmentLoanCharge() {
|
|
||||||
for (final LoanCharge loanCharge : charges()) {
|
|
||||||
if (loanCharge.isInstalmentFee()) {
|
|
||||||
loanCharge.clearLoanInstallmentCharges();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateLoanScheduleDependentDerivedFields() {
|
private void updateLoanScheduleDependentDerivedFields() {
|
||||||
this.expectedMaturityDate = determineExpectedMaturityDate().toDate();
|
this.expectedMaturityDate = determineExpectedMaturityDate().toDate();
|
||||||
this.actualMaturityDate = determineExpectedMaturityDate().toDate();
|
this.actualMaturityDate = determineExpectedMaturityDate().toDate();
|
||||||
@@ -1203,14 +1194,8 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
final String chargesParamName = "charges";
|
final String chargesParamName = "charges";
|
||||||
|
|
||||||
if (isChargesModified) {
|
if (isChargesModified) {
|
||||||
actualChanges.put(chargesParamName, getLoanCharges(possiblyModifedLoanCharges));
|
|
||||||
|
|
||||||
actualChanges.put(chargesParamName, getLoanCharges(possiblyModifedLoanCharges));
|
actualChanges.put(chargesParamName, getLoanCharges(possiblyModifedLoanCharges));
|
||||||
actualChanges.put("recalculateLoanSchedule", true);
|
actualChanges.put("recalculateLoanSchedule", true);
|
||||||
|
|
||||||
for (final LoanCharge loanCharge : possiblyModifedLoanCharges) {
|
|
||||||
recalculateLoanCharge(loanCharge);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final String collateralParamName = "collateral";
|
final String collateralParamName = "collateral";
|
||||||
@@ -1269,6 +1254,13 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
return actualChanges;
|
return actualChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void recalculateAllCharges() {
|
||||||
|
Set<LoanCharge> charges = this.charges();
|
||||||
|
for (final LoanCharge loanCharge : charges) {
|
||||||
|
recalculateLoanCharge(loanCharge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isInterestRecalculationEnabledForProduct() {
|
private boolean isInterestRecalculationEnabledForProduct() {
|
||||||
return this.loanProduct.isInterestRecalculationEnabled();
|
return this.loanProduct.isInterestRecalculationEnabled();
|
||||||
}
|
}
|
||||||
@@ -1723,12 +1715,12 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
return ids;
|
return ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disburse(final LoanScheduleGeneratorFactory loanScheduleFactory, final AppUser currentUser, final JsonCommand command,
|
public ChangedTransactionDetail disburse(final LoanScheduleGeneratorFactory loanScheduleFactory, final AppUser currentUser,
|
||||||
final ApplicationCurrency currency, final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
|
final JsonCommand command, final ApplicationCurrency currency, final List<Long> existingTransactionIds,
|
||||||
final Map<String, Object> actualChanges, final LocalDate calculatedRepaymentsStartingFromDate, final boolean isHolidayEnabled,
|
final List<Long> existingReversedTransactionIds, final Map<String, Object> actualChanges,
|
||||||
final List<Holiday> holidays, final WorkingDays workingDays, final boolean allowTransactionsOnHoliday,
|
final LocalDate calculatedRepaymentsStartingFromDate, final boolean isHolidayEnabled, final List<Holiday> holidays,
|
||||||
final boolean allowTransactionsOnNonWorkingDay, final boolean recalculateSchedule,
|
final WorkingDays workingDays, final boolean allowTransactionsOnHoliday, final boolean allowTransactionsOnNonWorkingDay,
|
||||||
final CalendarInstance calendarInstanceForInterestRecalculation) {
|
final boolean recalculateSchedule, final CalendarInstance calendarInstanceForInterestRecalculation) {
|
||||||
|
|
||||||
final LoanStatus statusEnum = this.loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSED,
|
final LoanStatus statusEnum = this.loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSED,
|
||||||
LoanStatus.fromInt(this.loanStatus));
|
LoanStatus.fromInt(this.loanStatus));
|
||||||
@@ -1763,13 +1755,7 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
if (isRepaymentScheduleRegenerationRequiredForDisbursement(actualDisbursementDate) || recalculateSchedule || isEmiAmountChanged) {
|
if (isRepaymentScheduleRegenerationRequiredForDisbursement(actualDisbursementDate) || recalculateSchedule || isEmiAmountChanged) {
|
||||||
regenerateRepaymentSchedule(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays,
|
regenerateRepaymentSchedule(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays,
|
||||||
workingDays);
|
workingDays);
|
||||||
if (recalculateSchedule) {
|
updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());
|
||||||
Set<LoanCharge> charges = this.charges();
|
|
||||||
for (LoanCharge loanCharge : charges) {
|
|
||||||
recalculateLoanCharge(loanCharge);
|
|
||||||
}
|
|
||||||
updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()
|
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()
|
||||||
&& fetchRepaymentScheduleInstallment(1).getDueDate().isBefore(LocalDate.now())) {
|
&& fetchRepaymentScheduleInstallment(1).getDueDate().isBefore(LocalDate.now())) {
|
||||||
@@ -1794,8 +1780,7 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
this.loanTransactions.add(interestAppliedTransaction);
|
this.loanTransactions.add(interestAppliedTransaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
// changedTransactionDetail =
|
return reprocessTransactionForDisbursement();
|
||||||
// reprocessTransactionForDisbursement(changedTransactionDetail);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1860,14 +1845,8 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
return disburseAmount;
|
return disburseAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChangedTransactionDetail reprocessTransactionForDisbursement() {
|
private ChangedTransactionDetail reprocessTransactionForDisbursement() {
|
||||||
ChangedTransactionDetail changedTransactionDetail = null;
|
ChangedTransactionDetail changedTransactionDetail = null;
|
||||||
for (LoanCharge loanCharge : this.charges) {
|
|
||||||
if (loanCharge.isInstalmentFee() && loanCharge.hasNoLoanInstallmentCharges()) {
|
|
||||||
final Set<LoanInstallmentCharge> chargePerInstallments = generateInstallmentLoanCharges(loanCharge);
|
|
||||||
loanCharge.addLoanInstallmentCharges(chargePerInstallments);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.loanProduct.isMultiDisburseLoan()) {
|
if (this.loanProduct.isMultiDisburseLoan()) {
|
||||||
if (!this.actualDisbursementDate.equals(fetchLastDisburseDetail().getDisbursementDate())) {
|
if (!this.actualDisbursementDate.equals(fetchLastDisburseDetail().getDisbursementDate())) {
|
||||||
@@ -2015,6 +1994,10 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
isHolidayEnabled, holidays, workingDays);
|
isHolidayEnabled, holidays, workingDays);
|
||||||
|
|
||||||
updateLoanSchedule(loanSchedule);
|
updateLoanSchedule(loanSchedule);
|
||||||
|
Set<LoanCharge> charges = this.charges();
|
||||||
|
for (LoanCharge loanCharge : charges) {
|
||||||
|
recalculateLoanCharge(loanCharge);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleDisbursementTransaction(final LocalDate disbursedOn) {
|
private void handleDisbursementTransaction(final LocalDate disbursedOn) {
|
||||||
@@ -2146,10 +2129,6 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
regenerateRepaymentSchedule(loanScheduleFactory, applicationCurrency, calculatedRepaymentsStartingFromDate,
|
regenerateRepaymentSchedule(loanScheduleFactory, applicationCurrency, calculatedRepaymentsStartingFromDate,
|
||||||
isHolidayEnabled, holidays, workingDays);
|
isHolidayEnabled, holidays, workingDays);
|
||||||
if (isDisbueseAmtChanged) {
|
if (isDisbueseAmtChanged) {
|
||||||
Set<LoanCharge> charges = charges();
|
|
||||||
for (LoanCharge loanCharge : charges) {
|
|
||||||
recalculateLoanCharge(loanCharge);
|
|
||||||
}
|
|
||||||
updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());
|
updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4149,4 +4128,8 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
return cumulativeOurstanding;
|
return cumulativeOurstanding;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<LoanRepaymentScheduleInstallment> fetchRepaymentScheduleInstallments() {
|
||||||
|
return this.repaymentScheduleInstallments;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+50
-34
@@ -67,6 +67,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
|||||||
private final LoanScheduleGeneratorFactory loanScheduleFactory;
|
private final LoanScheduleGeneratorFactory loanScheduleFactory;
|
||||||
private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository;
|
private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository;
|
||||||
private final CalendarInstanceRepository calendarInstanceRepository;
|
private final CalendarInstanceRepository calendarInstanceRepository;
|
||||||
|
private final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LoanAccountDomainServiceJpa(final LoanAssembler loanAccountAssembler, final LoanRepository loanRepository,
|
public LoanAccountDomainServiceJpa(final LoanAssembler loanAccountAssembler, final LoanRepository loanRepository,
|
||||||
@@ -77,7 +78,8 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
|||||||
final JournalEntryWritePlatformService journalEntryWritePlatformService,
|
final JournalEntryWritePlatformService journalEntryWritePlatformService,
|
||||||
final AccountTransferRepository accountTransferRepository, final LoanScheduleGeneratorFactory loanScheduleFactory,
|
final AccountTransferRepository accountTransferRepository, final LoanScheduleGeneratorFactory loanScheduleFactory,
|
||||||
final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository,
|
final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository,
|
||||||
final CalendarInstanceRepository calendarInstanceRepository) {
|
final CalendarInstanceRepository calendarInstanceRepository,
|
||||||
|
final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository) {
|
||||||
this.loanAccountAssembler = loanAccountAssembler;
|
this.loanAccountAssembler = loanAccountAssembler;
|
||||||
this.loanRepository = loanRepository;
|
this.loanRepository = loanRepository;
|
||||||
this.loanTransactionRepository = loanTransactionRepository;
|
this.loanTransactionRepository = loanTransactionRepository;
|
||||||
@@ -91,6 +93,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
|||||||
this.loanScheduleFactory = loanScheduleFactory;
|
this.loanScheduleFactory = loanScheduleFactory;
|
||||||
this.applicationCurrencyRepository = applicationCurrencyRepository;
|
this.applicationCurrencyRepository = applicationCurrencyRepository;
|
||||||
this.calendarInstanceRepository = calendarInstanceRepository;
|
this.calendarInstanceRepository = calendarInstanceRepository;
|
||||||
|
this.repaymentScheduleInstallmentRepository = repaymentScheduleInstallmentRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@@ -156,19 +159,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
|||||||
holidays, workingDays, allowTransactionsOnNonWorkingDay, isHolidayEnabled, isRecoveryRepayment, this.loanScheduleFactory,
|
holidays, workingDays, allowTransactionsOnNonWorkingDay, isHolidayEnabled, isRecoveryRepayment, this.loanScheduleFactory,
|
||||||
applicationCurrency, calculatedRepaymentsStartingFromDate, restCalendarInstance);
|
applicationCurrency, calculatedRepaymentsStartingFromDate, restCalendarInstance);
|
||||||
|
|
||||||
try {
|
saveLoanTransactionWithDataIntegrityViolationChecks(newRepaymentTransaction);
|
||||||
this.loanTransactionRepository.save(newRepaymentTransaction);
|
|
||||||
} catch (DataIntegrityViolationException e) {
|
|
||||||
final Throwable realCause = e.getCause();
|
|
||||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
|
||||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan.transaction");
|
|
||||||
if (realCause.getMessage().toLowerCase().contains("external_id_unique")) {
|
|
||||||
baseDataValidator.reset().parameter("externalId").value(newRepaymentTransaction.getExternalId())
|
|
||||||
.failWithCode("value.must.be.unique");
|
|
||||||
}
|
|
||||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
|
|
||||||
"Validation errors exist.", dataValidationErrors); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* TODO Vishwas Batch save is giving me a
|
* TODO Vishwas Batch save is giving me a
|
||||||
@@ -178,11 +169,11 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
|||||||
* recorded against the loan)
|
* recorded against the loan)
|
||||||
***/
|
***/
|
||||||
|
|
||||||
this.loanRepository.saveAndFlush(loan);
|
saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||||
|
|
||||||
if (changedTransactionDetail != null) {
|
if (changedTransactionDetail != null) {
|
||||||
for (Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
for (Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||||
this.loanTransactionRepository.save(mapEntry.getValue());
|
saveLoanTransactionWithDataIntegrityViolationChecks(mapEntry.getValue());
|
||||||
// update loan with references to the newly created transactions
|
// update loan with references to the newly created transactions
|
||||||
loan.getLoanTransactions().add(mapEntry.getValue());
|
loan.getLoanTransactions().add(mapEntry.getValue());
|
||||||
updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
|
updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
|
||||||
@@ -204,6 +195,43 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
|||||||
return newRepaymentTransaction;
|
return newRepaymentTransaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void saveLoanTransactionWithDataIntegrityViolationChecks(LoanTransaction newRepaymentTransaction) {
|
||||||
|
try {
|
||||||
|
this.loanTransactionRepository.save(newRepaymentTransaction);
|
||||||
|
} catch (DataIntegrityViolationException e) {
|
||||||
|
final Throwable realCause = e.getCause();
|
||||||
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||||
|
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan.transaction");
|
||||||
|
if (realCause.getMessage().toLowerCase().contains("external_id_unique")) {
|
||||||
|
baseDataValidator.reset().parameter("externalId").value(newRepaymentTransaction.getExternalId())
|
||||||
|
.failWithCode("value.must.be.unique");
|
||||||
|
}
|
||||||
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
|
||||||
|
"Validation errors exist.", dataValidationErrors); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveAndFlushLoanWithDataIntegrityViolationChecks(final Loan loan) {
|
||||||
|
try {
|
||||||
|
List<LoanRepaymentScheduleInstallment> installments = loan.fetchRepaymentScheduleInstallments();
|
||||||
|
for (LoanRepaymentScheduleInstallment installment : installments) {
|
||||||
|
if (installment.getId() == null) {
|
||||||
|
this.repaymentScheduleInstallmentRepository.save(installment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.loanRepository.saveAndFlush(loan);
|
||||||
|
} catch (final DataIntegrityViolationException e) {
|
||||||
|
final Throwable realCause = e.getCause();
|
||||||
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||||
|
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan.transaction");
|
||||||
|
if (realCause.getMessage().toLowerCase().contains("external_id_unique")) {
|
||||||
|
baseDataValidator.reset().parameter("externalId").failWithCode("value.must.be.unique");
|
||||||
|
}
|
||||||
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
|
||||||
|
"Validation errors exist.", dataValidationErrors); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public LoanTransaction makeChargePayment(final Loan loan, final Long chargeId, final LocalDate transactionDate,
|
public LoanTransaction makeChargePayment(final Loan loan, final Long chargeId, final LocalDate transactionDate,
|
||||||
@@ -233,8 +261,8 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
|||||||
allowTransactionsOnHoliday, holidays, workingDays, allowTransactionsOnNonWorkingDay, newPaymentTransaction,
|
allowTransactionsOnHoliday, holidays, workingDays, allowTransactionsOnNonWorkingDay, newPaymentTransaction,
|
||||||
installmentNumber);
|
installmentNumber);
|
||||||
}
|
}
|
||||||
this.loanTransactionRepository.save(newPaymentTransaction);
|
saveLoanTransactionWithDataIntegrityViolationChecks(newPaymentTransaction);
|
||||||
this.loanRepository.saveAndFlush(loan);
|
saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(noteText)) {
|
if (StringUtils.isNotBlank(noteText)) {
|
||||||
final Note note = Note.loanTransactionNote(loan, newPaymentTransaction, noteText);
|
final Note note = Note.loanTransactionNote(loan, newPaymentTransaction, noteText);
|
||||||
@@ -295,7 +323,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
|||||||
loan.makeRefund(newRefundTransaction, defaultLoanLifecycleStateMachine(), existingTransactionIds, existingReversedTransactionIds,
|
loan.makeRefund(newRefundTransaction, defaultLoanLifecycleStateMachine(), existingTransactionIds, existingReversedTransactionIds,
|
||||||
allowTransactionsOnHoliday, holidays, workingDays, allowTransactionsOnNonWorkingDay);
|
allowTransactionsOnHoliday, holidays, workingDays, allowTransactionsOnNonWorkingDay);
|
||||||
|
|
||||||
this.loanTransactionRepository.save(newRefundTransaction);
|
saveLoanTransactionWithDataIntegrityViolationChecks(newRefundTransaction);
|
||||||
this.loanRepository.save(loan);
|
this.loanRepository.save(loan);
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(noteText)) {
|
if (StringUtils.isNotBlank(noteText)) {
|
||||||
@@ -327,20 +355,8 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
|||||||
txnExternalId);
|
txnExternalId);
|
||||||
disbursementTransaction.updateLoan(loan);
|
disbursementTransaction.updateLoan(loan);
|
||||||
loan.getLoanTransactions().add(disbursementTransaction);
|
loan.getLoanTransactions().add(disbursementTransaction);
|
||||||
try {
|
saveLoanTransactionWithDataIntegrityViolationChecks(disbursementTransaction);
|
||||||
this.loanTransactionRepository.save(disbursementTransaction);
|
saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||||
} catch (DataIntegrityViolationException e) {
|
|
||||||
final Throwable realCause = e.getCause();
|
|
||||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
|
||||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan.transaction");
|
|
||||||
if (realCause.getMessage().toLowerCase().contains("external_id_unique")) {
|
|
||||||
baseDataValidator.reset().parameter("externalId").value(disbursementTransaction.getExternalId())
|
|
||||||
.failWithCode("value.must.be.unique");
|
|
||||||
}
|
|
||||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
|
|
||||||
"Validation errors exist.", dataValidationErrors); }
|
|
||||||
}
|
|
||||||
this.loanRepository.saveAndFlush(loan);
|
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(noteText)) {
|
if (StringUtils.isNotBlank(noteText)) {
|
||||||
final Note note = Note.loanTransactionNote(loan, disbursementTransaction, noteText);
|
final Note note = Note.loanTransactionNote(loan, disbursementTransaction, noteText);
|
||||||
@@ -355,7 +371,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
|||||||
@Override
|
@Override
|
||||||
public void reverseTransfer(final LoanTransaction loanTransaction) {
|
public void reverseTransfer(final LoanTransaction loanTransaction) {
|
||||||
loanTransaction.reverse();
|
loanTransaction.reverse();
|
||||||
this.loanTransactionRepository.save(loanTransaction);
|
saveLoanTransactionWithDataIntegrityViolationChecks(loanTransaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+30
-38
@@ -280,17 +280,7 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
this.amountOrPercentage = chargeAmount;
|
this.amountOrPercentage = chargeAmount;
|
||||||
if (this.loan != null && isInstalmentFee()) {
|
if (this.loan != null && isInstalmentFee()) {
|
||||||
final Set<LoanInstallmentCharge> chargePerInstallments = this.loan.generateInstallmentLoanCharges(this);
|
updateInstallmentCharges();
|
||||||
if (this.loanInstallmentCharge.isEmpty()) {
|
|
||||||
this.loanInstallmentCharge.addAll(chargePerInstallments);
|
|
||||||
} else {
|
|
||||||
int index = 0;
|
|
||||||
final LoanInstallmentCharge[] loanChargePerInstallments = new LoanInstallmentCharge[chargePerInstallments.size()];
|
|
||||||
final LoanInstallmentCharge[] loanChargePerInstallmentArray = chargePerInstallments.toArray(loanChargePerInstallments);
|
|
||||||
for (final LoanInstallmentCharge chargePerInstallment : this.loanInstallmentCharge) {
|
|
||||||
chargePerInstallment.copyFrom(loanChargePerInstallmentArray[index++]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -386,17 +376,7 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
this.amountOrPercentage = amount;
|
this.amountOrPercentage = amount;
|
||||||
this.amountOutstanding = calculateOutstanding();
|
this.amountOutstanding = calculateOutstanding();
|
||||||
if (this.loan != null && isInstalmentFee()) {
|
if (this.loan != null && isInstalmentFee()) {
|
||||||
final Set<LoanInstallmentCharge> chargePerInstallments = this.loan.generateInstallmentLoanCharges(this);
|
updateInstallmentCharges();
|
||||||
if (this.loanInstallmentCharge.isEmpty()) {
|
|
||||||
this.loanInstallmentCharge.addAll(chargePerInstallments);
|
|
||||||
} else {
|
|
||||||
int index = 0;
|
|
||||||
final LoanInstallmentCharge[] loanChargePerInstallments = new LoanInstallmentCharge[chargePerInstallments.size()];
|
|
||||||
final LoanInstallmentCharge[] loanChargePerInstallmentArray = chargePerInstallments.toArray(loanChargePerInstallments);
|
|
||||||
for (final LoanInstallmentCharge chargePerInstallment : this.loanInstallmentCharge) {
|
|
||||||
chargePerInstallment.copyFrom(loanChargePerInstallmentArray[index++]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -474,22 +454,36 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
this.amountOrPercentage = newValue;
|
this.amountOrPercentage = newValue;
|
||||||
if (isInstalmentFee()) {
|
if (isInstalmentFee()) {
|
||||||
final Set<LoanInstallmentCharge> chargePerInstallments = this.loan.generateInstallmentLoanCharges(this);
|
updateInstallmentCharges();
|
||||||
if (this.loanInstallmentCharge.isEmpty()) {
|
|
||||||
this.loanInstallmentCharge.addAll(chargePerInstallments);
|
|
||||||
} else {
|
|
||||||
int index = 0;
|
|
||||||
final LoanInstallmentCharge[] loanChargePerInstallments = new LoanInstallmentCharge[chargePerInstallments.size()];
|
|
||||||
final LoanInstallmentCharge[] loanChargePerInstallmentArray = chargePerInstallments.toArray(loanChargePerInstallments);
|
|
||||||
for (final LoanInstallmentCharge chargePerInstallment : this.loanInstallmentCharge) {
|
|
||||||
chargePerInstallment.copyFrom(loanChargePerInstallmentArray[index++]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return actualChanges;
|
return actualChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateInstallmentCharges() {
|
||||||
|
final Collection<LoanInstallmentCharge> remove = new HashSet<>();
|
||||||
|
final Set<LoanInstallmentCharge> chargePerInstallments = this.loan.generateInstallmentLoanCharges(this);
|
||||||
|
if (this.loanInstallmentCharge.isEmpty()) {
|
||||||
|
this.loanInstallmentCharge.addAll(chargePerInstallments);
|
||||||
|
} else {
|
||||||
|
int index = 0;
|
||||||
|
final LoanInstallmentCharge[] loanChargePerInstallments = new LoanInstallmentCharge[chargePerInstallments.size()];
|
||||||
|
final LoanInstallmentCharge[] loanChargePerInstallmentArray = chargePerInstallments.toArray(loanChargePerInstallments);
|
||||||
|
for (final LoanInstallmentCharge chargePerInstallment : this.loanInstallmentCharge) {
|
||||||
|
if (index == loanChargePerInstallmentArray.length) {
|
||||||
|
remove.add(chargePerInstallment);
|
||||||
|
chargePerInstallment.updateInstallment(null);
|
||||||
|
} else {
|
||||||
|
chargePerInstallment.copyFrom(loanChargePerInstallmentArray[index++]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.loanInstallmentCharge.removeAll(remove);
|
||||||
|
/*while (index < loanChargePerInstallmentArray.length - 1) {
|
||||||
|
chargePerInstallments.add(loanChargePerInstallmentArray[index++]);
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isDueAtDisbursement() {
|
public boolean isDueAtDisbursement() {
|
||||||
return ChargeTimeType.fromInt(this.chargeTime).equals(ChargeTimeType.DISBURSEMENT);
|
return ChargeTimeType.fromInt(this.chargeTime).equals(ChargeTimeType.DISBURSEMENT);
|
||||||
}
|
}
|
||||||
@@ -811,7 +805,7 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
public List<LoanChargePaidDetail> fetchRepaymentInstallment(final MonetaryCurrency currency) {
|
public List<LoanChargePaidDetail> fetchRepaymentInstallment(final MonetaryCurrency currency) {
|
||||||
List<LoanChargePaidDetail> chargePaidDetails = new ArrayList<>();
|
List<LoanChargePaidDetail> chargePaidDetails = new ArrayList<>();
|
||||||
for (final LoanInstallmentCharge loanChargePerInstallment : this.loanInstallmentCharge) {
|
for (final LoanInstallmentCharge loanChargePerInstallment : this.loanInstallmentCharge) {
|
||||||
if (loanChargePerInstallment.isPending()
|
if (!loanChargePerInstallment.isChargeAmountpaid(currency)
|
||||||
&& loanChargePerInstallment.getAmountThroughChargePayment(currency).isGreaterThanZero()) {
|
&& loanChargePerInstallment.getAmountThroughChargePayment(currency).isGreaterThanZero()) {
|
||||||
LoanChargePaidDetail chargePaidDetail = new LoanChargePaidDetail(
|
LoanChargePaidDetail chargePaidDetail = new LoanChargePaidDetail(
|
||||||
loanChargePerInstallment.getAmountThroughChargePayment(currency),
|
loanChargePerInstallment.getAmountThroughChargePayment(currency),
|
||||||
@@ -857,11 +851,9 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
public void updateWaivedAmount(MonetaryCurrency currency) {
|
public void updateWaivedAmount(MonetaryCurrency currency) {
|
||||||
if (isInstalmentFee()) {
|
if (isInstalmentFee()) {
|
||||||
|
this.amountWaived = BigDecimal.ZERO;
|
||||||
for (final LoanInstallmentCharge chargePerInstallment : this.loanInstallmentCharge) {
|
for (final LoanInstallmentCharge chargePerInstallment : this.loanInstallmentCharge) {
|
||||||
final Money amountWaived = chargePerInstallment.updateWaivedAmount(currency);
|
final Money amountWaived = chargePerInstallment.updateWaivedAndAmountPaidThroughChargePaymentAmount(currency);
|
||||||
if (this.amountWaived == null) {
|
|
||||||
this.amountWaived = BigDecimal.ZERO;
|
|
||||||
}
|
|
||||||
this.amountWaived = this.amountWaived.add(amountWaived.getAmount());
|
this.amountWaived = this.amountWaived.add(amountWaived.getAmount());
|
||||||
this.amountOutstanding = this.amountOutstanding.subtract(amountWaived.getAmount());
|
this.amountOutstanding = this.amountOutstanding.subtract(amountWaived.getAmount());
|
||||||
if (determineIfFullyPaid()) {
|
if (determineIfFullyPaid()) {
|
||||||
|
|||||||
+31
-2
@@ -145,6 +145,12 @@ public class LoanInstallmentCharge extends AbstractPersistable<Long> {
|
|||||||
return !(isPaid() || isWaived());
|
return !(isPaid() || isWaived());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isChargeAmountpaid(MonetaryCurrency currency) {
|
||||||
|
Money amounPaidThroughChargePayment = Money.of(currency, this.amountThroughChargePayment);
|
||||||
|
Money paid = Money.of(currency, this.amountPaid);
|
||||||
|
return amounPaidThroughChargePayment.isEqualTo(paid);
|
||||||
|
}
|
||||||
|
|
||||||
public LoanRepaymentScheduleInstallment getRepaymentInstallment() {
|
public LoanRepaymentScheduleInstallment getRepaymentInstallment() {
|
||||||
return this.installment;
|
return this.installment;
|
||||||
}
|
}
|
||||||
@@ -199,16 +205,35 @@ public class LoanInstallmentCharge extends AbstractPersistable<Long> {
|
|||||||
this.amountPaid = BigDecimal.ZERO;
|
this.amountPaid = BigDecimal.ZERO;
|
||||||
this.amountWaived = BigDecimal.ZERO;
|
this.amountWaived = BigDecimal.ZERO;
|
||||||
this.amountWrittenOff = BigDecimal.ZERO;
|
this.amountWrittenOff = BigDecimal.ZERO;
|
||||||
|
this.amountThroughChargePayment = BigDecimal.ZERO;
|
||||||
this.amountOutstanding = calculateAmountOutstanding(currency);
|
this.amountOutstanding = calculateAmountOutstanding(currency);
|
||||||
this.paid = false;
|
this.paid = false;
|
||||||
this.waived = false;
|
this.waived = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money getAmountThroughChargePayment(final MonetaryCurrency currency) {
|
public Money getAmountThroughChargePayment(final MonetaryCurrency currency) {
|
||||||
return Money.of(currency, this.amountThroughChargePayment);
|
return Money.of(currency, this.amountThroughChargePayment);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money updateWaivedAmount(final MonetaryCurrency currency) {
|
public Money getUnpaidAmountThroughChargePayment(final MonetaryCurrency currency) {
|
||||||
|
return Money.of(currency, this.amountThroughChargePayment).minus(this.amountPaid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateAmountThroughChargePayment(final MonetaryCurrency currency) {
|
||||||
|
Money amountThroughChargePayment = getAmountThroughChargePayment(currency);
|
||||||
|
if (amountThroughChargePayment.isGreaterThanZero() && amountThroughChargePayment.isGreaterThan(this.getAmount(currency))) {
|
||||||
|
this.amountThroughChargePayment = this.getAmount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Money updateWaivedAndAmountPaidThroughChargePaymentAmount(final MonetaryCurrency currency) {
|
||||||
|
updateWaivedAmount(currency);
|
||||||
|
updateAmountThroughChargePayment(currency);
|
||||||
|
return getAmountWaived(currency);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateWaivedAmount(final MonetaryCurrency currency) {
|
||||||
Money waivedAmount = getAmountWaived(currency);
|
Money waivedAmount = getAmountWaived(currency);
|
||||||
if (waivedAmount.isGreaterThanZero()) {
|
if (waivedAmount.isGreaterThanZero()) {
|
||||||
if (waivedAmount.isGreaterThan(this.getAmount(currency))) {
|
if (waivedAmount.isGreaterThan(this.getAmount(currency))) {
|
||||||
@@ -221,7 +246,11 @@ public class LoanInstallmentCharge extends AbstractPersistable<Long> {
|
|||||||
this.waived = false;
|
this.waived = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return getAmountWaived(currency);
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void updateInstallment(LoanRepaymentScheduleInstallment installment) {
|
||||||
|
this.installment = installment;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
package org.mifosplatform.portfolio.loanaccount.domain;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
|
||||||
|
public interface LoanRepaymentScheduleInstallmentRepository extends JpaRepository<LoanRepaymentScheduleInstallment, Long>,
|
||||||
|
JpaSpecificationExecutor<LoanRepaymentScheduleInstallment> {
|
||||||
|
|
||||||
|
}
|
||||||
+1
@@ -263,6 +263,7 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
|
|||||||
this.interestPortion = null;
|
this.interestPortion = null;
|
||||||
this.feeChargesPortion = null;
|
this.feeChargesPortion = null;
|
||||||
this.penaltyChargesPortion = null;
|
this.penaltyChargesPortion = null;
|
||||||
|
this.overPaymentPortion = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateLoan(final Loan loan) {
|
public void updateLoan(final Loan loan) {
|
||||||
|
|||||||
+42
-25
@@ -86,8 +86,12 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
|||||||
for (final LoanRepaymentScheduleInstallment installment : installments) {
|
for (final LoanRepaymentScheduleInstallment installment : installments) {
|
||||||
for (final LoanCharge loanCharge : transferCharges) {
|
for (final LoanCharge loanCharge : transferCharges) {
|
||||||
if (loanCharge.isDueForCollectionFromAndUpToAndIncluding(startDate, installment.getDueDate())) {
|
if (loanCharge.isDueForCollectionFromAndUpToAndIncluding(startDate, installment.getDueDate())) {
|
||||||
LoanChargePaidDetail chargePaidDetail = new LoanChargePaidDetail(
|
Money amountForProcess = loanCharge.getAmount(currency);
|
||||||
installment.getFeeChargesOutstanding(currency), installment, loanCharge.isFeeCharge());
|
if (amountForProcess.isGreaterThan(loanTransaction.getAmount(currency))) {
|
||||||
|
amountForProcess = loanTransaction.getAmount(currency);
|
||||||
|
}
|
||||||
|
LoanChargePaidDetail chargePaidDetail = new LoanChargePaidDetail(amountForProcess, installment,
|
||||||
|
loanCharge.isFeeCharge());
|
||||||
chargePaidDetails.add(chargePaidDetail);
|
chargePaidDetails.add(chargePaidDetail);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -98,11 +102,13 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
|||||||
Money unprocessed = loanTransaction.getAmount(currency);
|
Money unprocessed = loanTransaction.getAmount(currency);
|
||||||
for (LoanChargePaidDetail chargePaidDetail : chargePaidDetails) {
|
for (LoanChargePaidDetail chargePaidDetail : chargePaidDetails) {
|
||||||
final List<LoanRepaymentScheduleInstallment> processInstallments = new ArrayList<>(1);
|
final List<LoanRepaymentScheduleInstallment> processInstallments = new ArrayList<>(1);
|
||||||
unprocessed = unprocessed.minus(chargePaidDetail.getAmount());
|
|
||||||
processInstallments.add(chargePaidDetail.getInstallment());
|
processInstallments.add(chargePaidDetail.getInstallment());
|
||||||
Money unprocessedAfterProcess = handleTransactionAndCharges(loanTransaction, currency, processInstallments,
|
Money processAmt = chargePaidDetail.getAmount();
|
||||||
transferCharges, chargePaidDetail.getAmount(), chargePaidDetail.isFeeCharge());
|
if(processAmt.isGreaterThan(unprocessed)){
|
||||||
unprocessed = unprocessed.plus(unprocessedAfterProcess);
|
processAmt = unprocessed;
|
||||||
|
}
|
||||||
|
unprocessed = handleTransactionAndCharges(loanTransaction, currency, processInstallments,
|
||||||
|
transferCharges, processAmt, chargePaidDetail.isFeeCharge());
|
||||||
if (!unprocessed.isGreaterThanZero()) {
|
if (!unprocessed.isGreaterThanZero()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -206,7 +212,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
|||||||
if (loanTransaction.isNotWaiver()) {
|
if (loanTransaction.isNotWaiver()) {
|
||||||
Money feeCharges = loanTransaction.getFeeChargesPortion(currency);
|
Money feeCharges = loanTransaction.getFeeChargesPortion(currency);
|
||||||
Money penaltyCharges = loanTransaction.getPenaltyChargesPortion(currency);
|
Money penaltyCharges = loanTransaction.getPenaltyChargesPortion(currency);
|
||||||
if (chargeAmountToProcess != null) {
|
if (chargeAmountToProcess != null && feeCharges.isGreaterThan(chargeAmountToProcess)) {
|
||||||
if (isFeeCharge) {
|
if (isFeeCharge) {
|
||||||
feeCharges = chargeAmountToProcess;
|
feeCharges = chargeAmountToProcess;
|
||||||
} else {
|
} else {
|
||||||
@@ -235,23 +241,26 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (final LoanRepaymentScheduleInstallment currentInstallment : installments) {
|
for (final LoanRepaymentScheduleInstallment currentInstallment : installments) {
|
||||||
|
if (transactionAmountUnprocessed.isGreaterThanZero()) {
|
||||||
|
if (currentInstallment.isNotFullyPaidOff()) {
|
||||||
|
|
||||||
if (currentInstallment.isNotFullyPaidOff()) {
|
// is this transaction early/late/on-time with respect to
|
||||||
|
// the
|
||||||
// is this transaction early/late/on-time with respect to the
|
// current installment?
|
||||||
// current installment?
|
if (isTransactionInAdvanceOfInstallment(installmentIndex, installments, transactionDate, transactionAmountUnprocessed)) {
|
||||||
if (isTransactionInAdvanceOfInstallment(installmentIndex, installments, transactionDate, transactionAmountUnprocessed)) {
|
transactionAmountUnprocessed = handleTransactionThatIsPaymentInAdvanceOfInstallment(currentInstallment,
|
||||||
transactionAmountUnprocessed = handleTransactionThatIsPaymentInAdvanceOfInstallment(currentInstallment, installments,
|
installments, loanTransaction, transactionDate, transactionAmountUnprocessed);
|
||||||
loanTransaction, transactionDate, transactionAmountUnprocessed);
|
} else if (isTransactionALateRepaymentOnInstallment(installmentIndex, installments,
|
||||||
} else if (isTransactionALateRepaymentOnInstallment(installmentIndex, installments, loanTransaction.getTransactionDate())) {
|
loanTransaction.getTransactionDate())) {
|
||||||
// does this result in a late payment of existing
|
// does this result in a late payment of existing
|
||||||
// installment?
|
// installment?
|
||||||
transactionAmountUnprocessed = handleTransactionThatIsALateRepaymentOfInstallment(currentInstallment, installments,
|
transactionAmountUnprocessed = handleTransactionThatIsALateRepaymentOfInstallment(currentInstallment, installments,
|
||||||
loanTransaction, transactionAmountUnprocessed);
|
loanTransaction, transactionAmountUnprocessed);
|
||||||
} else {
|
} else {
|
||||||
// standard transaction
|
// standard transaction
|
||||||
transactionAmountUnprocessed = handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment, loanTransaction,
|
transactionAmountUnprocessed = handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment,
|
||||||
transactionAmountUnprocessed);
|
loanTransaction, transactionAmountUnprocessed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,10 +301,18 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
|||||||
}
|
}
|
||||||
final Money amountPaidTowardsCharge = unpaidCharge.updatePaidAmountBy(amountRemaining, installmentNumber, feeAmount);
|
final Money amountPaidTowardsCharge = unpaidCharge.updatePaidAmountBy(amountRemaining, installmentNumber, feeAmount);
|
||||||
if (!amountPaidTowardsCharge.isZero()) {
|
if (!amountPaidTowardsCharge.isZero()) {
|
||||||
if (!loanTransaction.isChargePayment()) {
|
Set<LoanChargePaidBy> chargesPaidBies = loanTransaction.getLoanChargesPaid();
|
||||||
|
if (loanTransaction.isChargePayment()) {
|
||||||
|
for (final LoanChargePaidBy chargePaidBy : chargesPaidBies) {
|
||||||
|
LoanCharge loanCharge = chargePaidBy.getLoanCharge();
|
||||||
|
if (loanCharge.getId().equals(unpaidCharge.getId())) {
|
||||||
|
chargePaidBy.setAmount(amountPaidTowardsCharge.getAmount());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(loanTransaction, unpaidCharge,
|
final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(loanTransaction, unpaidCharge,
|
||||||
amountPaidTowardsCharge.getAmount());
|
amountPaidTowardsCharge.getAmount());
|
||||||
loanTransaction.getLoanChargesPaid().add(loanChargePaidBy);
|
chargesPaidBies.add(loanChargePaidBy);
|
||||||
}
|
}
|
||||||
amountRemaining = amountRemaining.minus(amountPaidTowardsCharge);
|
amountRemaining = amountRemaining.minus(amountPaidTowardsCharge);
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-17
@@ -231,15 +231,14 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
principalForThisPeriod = principalForThisPeriod.plus(actualOutstanding);
|
principalForThisPeriod = principalForThisPeriod.plus(actualOutstanding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interestReducedDueToEarlyPayment = interestReducedDueToEarlyPayment.plus(loanApplicationTerms.interestRateFor(
|
interestReducedDueToEarlyPayment = interestReducedDueToEarlyPayment.plus(loanApplicationTerms.interestRateFor(
|
||||||
this.paymentPeriodsInOneYearCalculator, mc, diffDays, detail.getAmount()));
|
this.paymentPeriodsInOneYearCalculator, mc, detail.getAmount(), detail.getStartDate(), scheduledDueDate));
|
||||||
|
|
||||||
} else if (detail.isLatePayment() && detail.isOverlapping(periodStartDate, scheduledDueDate)
|
} else if (detail.isLatePayment() && detail.isOverlapping(periodStartDate, scheduledDueDate)
|
||||||
&& periodStartDate.isBefore(LocalDate.now())) {
|
&& periodStartDate.isBefore(LocalDate.now())) {
|
||||||
LocalDate fromDate = periodStartDate;
|
LocalDate fromDate = periodStartDate;
|
||||||
LocalDate toDate = scheduledDueDate;
|
LocalDate toDate = scheduledDueDate;
|
||||||
if (!detail.getStartDate().isAfter(periodStartDate)) {
|
if (!detail.getStartDate().isBefore(periodStartDate)) {
|
||||||
fromDate = detail.getStartDate();
|
fromDate = detail.getStartDate();
|
||||||
}
|
}
|
||||||
if (!detail.getToDate().isAfter(scheduledDueDate)) {
|
if (!detail.getToDate().isAfter(scheduledDueDate)) {
|
||||||
@@ -248,9 +247,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
if (toDate.isAfter(LocalDate.now())) {
|
if (toDate.isAfter(LocalDate.now())) {
|
||||||
toDate = LocalDate.now();
|
toDate = LocalDate.now();
|
||||||
}
|
}
|
||||||
int diffDays = Days.daysBetween(fromDate, toDate).getDays();
|
|
||||||
interestDueToLatePayment = interestDueToLatePayment.plus(loanApplicationTerms.interestRateFor(
|
interestDueToLatePayment = interestDueToLatePayment.plus(loanApplicationTerms.interestRateFor(
|
||||||
this.paymentPeriodsInOneYearCalculator, mc, diffDays, detail.getAmount()));
|
this.paymentPeriodsInOneYearCalculator, mc, detail.getAmount(), fromDate, toDate));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,18 +331,19 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
for (RecalculationDetail detail : processDetails.values()) {
|
for (RecalculationDetail detail : processDetails.values()) {
|
||||||
LocalDate fromDate = detail.getStartDate();
|
LocalDate fromDate = detail.getStartDate();
|
||||||
LocalDate toDate = detail.getToDate();
|
LocalDate toDate = detail.getToDate();
|
||||||
int diffDays = Days.daysBetween(fromDate, toDate).getDays();
|
if (!toDate.isAfter(LocalDate.now())) {
|
||||||
Money interestDueToLatePayment = loanApplicationTerms.interestRateFor(this.paymentPeriodsInOneYearCalculator, mc, diffDays,
|
Money interestDueToLatePayment = loanApplicationTerms.interestRateFor(this.paymentPeriodsInOneYearCalculator, mc,
|
||||||
detail.getAmount());
|
detail.getAmount(), fromDate, toDate);
|
||||||
|
|
||||||
totalInterestCharged = totalInterestCharged.add(interestDueToLatePayment.getAmount());
|
totalInterestCharged = totalInterestCharged.add(interestDueToLatePayment.getAmount());
|
||||||
totalRepaymentExpected = totalRepaymentExpected.add(interestDueToLatePayment.getAmount());
|
totalRepaymentExpected = totalRepaymentExpected.add(interestDueToLatePayment.getAmount());
|
||||||
|
|
||||||
final LoanScheduleModelPeriod installment = LoanScheduleModelRepaymentPeriod.repayment(periodNumber, fromDate, toDate,
|
final LoanScheduleModelPeriod installment = LoanScheduleModelRepaymentPeriod.repayment(periodNumber, fromDate, toDate,
|
||||||
interestDueToLatePayment.zero(), interestDueToLatePayment.zero(), interestDueToLatePayment,
|
interestDueToLatePayment.zero(), interestDueToLatePayment.zero(), interestDueToLatePayment,
|
||||||
interestDueToLatePayment.zero(), interestDueToLatePayment.zero(), interestDueToLatePayment);
|
interestDueToLatePayment.zero(), interestDueToLatePayment.zero(), interestDueToLatePayment);
|
||||||
periods.add(installment);
|
periods.add(installment);
|
||||||
periodNumber++;
|
periodNumber++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -711,8 +710,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int days = Days.daysBetween(calculateInterestFrom, LocalDate.now()).getDays();
|
Money interest = applicationTerms.interestRateFor(this.paymentPeriodsInOneYearCalculator, mc, prepaymentAmount,
|
||||||
Money interest = applicationTerms.interestRateFor(this.paymentPeriodsInOneYearCalculator, mc, days, prepaymentAmount);
|
calculateInterestFrom, LocalDate.now());
|
||||||
prepaymentAmount = prepaymentAmount.plus(interest).plus(amount);
|
prepaymentAmount = prepaymentAmount.plus(interest).plus(amount);
|
||||||
return prepaymentAmount;
|
return prepaymentAmount;
|
||||||
}
|
}
|
||||||
|
|||||||
+67
-4
@@ -13,6 +13,8 @@ import java.util.List;
|
|||||||
|
|
||||||
import org.joda.time.Days;
|
import org.joda.time.Days;
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
|
import org.joda.time.Period;
|
||||||
|
import org.joda.time.PeriodType;
|
||||||
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
|
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
|
||||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||||
@@ -661,15 +663,21 @@ public final class LoanApplicationTerms {
|
|||||||
return periodicInterestRate;
|
return periodicInterestRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money interestRateFor(final PaymentPeriodsInOneYearCalculator calculator, final MathContext mc, int days,
|
public Money interestRateFor(final PaymentPeriodsInOneYearCalculator calculator, final MathContext mc, final Money outstandingBalance,
|
||||||
final Money outstandingBalance) {
|
final LocalDate fromDate, final LocalDate toDate) {
|
||||||
final long loanTermPeriodsInOneYear = calculatePeriodsInOneYear(calculator);
|
|
||||||
|
long loanTermPeriodsInOneYear = calculator.calculate(PeriodFrequencyType.DAYS).longValue();
|
||||||
|
int repaymentEvery = Days.daysBetween(fromDate, toDate).getDays();
|
||||||
|
if (isFallingInRepaymentPeriod(fromDate, toDate)) {
|
||||||
|
loanTermPeriodsInOneYear = calculatePeriodsInOneYear(calculator);
|
||||||
|
repaymentEvery = getPeriodsBetween(fromDate, toDate);
|
||||||
|
}
|
||||||
|
|
||||||
final BigDecimal divisor = BigDecimal.valueOf(Double.valueOf("100.0"));
|
final BigDecimal divisor = BigDecimal.valueOf(Double.valueOf("100.0"));
|
||||||
final BigDecimal loanTermPeriodsInYearBigDecimal = BigDecimal.valueOf(loanTermPeriodsInOneYear);
|
final BigDecimal loanTermPeriodsInYearBigDecimal = BigDecimal.valueOf(loanTermPeriodsInOneYear);
|
||||||
final BigDecimal oneDayOfYearInterestRate = this.annualNominalInterestRate.divide(loanTermPeriodsInYearBigDecimal, mc).divide(
|
final BigDecimal oneDayOfYearInterestRate = this.annualNominalInterestRate.divide(loanTermPeriodsInYearBigDecimal, mc).divide(
|
||||||
divisor, mc);
|
divisor, mc);
|
||||||
BigDecimal interestRate = oneDayOfYearInterestRate.multiply(BigDecimal.valueOf(days), mc);
|
BigDecimal interestRate = oneDayOfYearInterestRate.multiply(BigDecimal.valueOf(repaymentEvery), mc);
|
||||||
return outstandingBalance.multiplyRetainScale(interestRate, mc.getRoundingMode());
|
return outstandingBalance.multiplyRetainScale(interestRate, mc.getRoundingMode());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -967,4 +975,59 @@ public final class LoanApplicationTerms {
|
|||||||
public CalendarInstance getRestCalendarInstance() {
|
public CalendarInstance getRestCalendarInstance() {
|
||||||
return this.restCalendarInstance;
|
return this.restCalendarInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isFallingInRepaymentPeriod(LocalDate fromDate, LocalDate toDate) {
|
||||||
|
boolean isSameAsRepaymentPeriod = false;
|
||||||
|
if (this.interestCalculationPeriodMethod.getValue().equals(InterestCalculationPeriodMethod.SAME_AS_REPAYMENT_PERIOD.getValue())) {
|
||||||
|
switch (this.repaymentPeriodFrequencyType) {
|
||||||
|
case WEEKS:
|
||||||
|
int days = getPeriodsBetween(fromDate, toDate);
|
||||||
|
isSameAsRepaymentPeriod = (days % 7) == 0;
|
||||||
|
break;
|
||||||
|
case MONTHS:
|
||||||
|
boolean isFromDateOnEndDate = false;
|
||||||
|
if (fromDate.getDayOfMonth() > fromDate.plusDays(1).getDayOfMonth()) {
|
||||||
|
isFromDateOnEndDate = true;
|
||||||
|
}
|
||||||
|
boolean isToDateOnEndDate = false;
|
||||||
|
if (toDate.getDayOfMonth() > toDate.plusDays(1).getDayOfMonth()) {
|
||||||
|
isToDateOnEndDate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFromDateOnEndDate && isToDateOnEndDate) {
|
||||||
|
isSameAsRepaymentPeriod = true;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
int months = getPeriodsBetween(fromDate, toDate);
|
||||||
|
fromDate = fromDate.plusMonths(months);
|
||||||
|
isSameAsRepaymentPeriod = fromDate.isEqual(toDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isSameAsRepaymentPeriod;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer getPeriodsBetween(LocalDate fromDate, LocalDate toDate) {
|
||||||
|
Integer numberOfPeriods = 0;
|
||||||
|
PeriodType periodType = PeriodType.yearMonthDay();
|
||||||
|
Period difference = new Period(fromDate, toDate, periodType);
|
||||||
|
switch (this.repaymentPeriodFrequencyType) {
|
||||||
|
case WEEKS:
|
||||||
|
numberOfPeriods = difference.getDays();
|
||||||
|
break;
|
||||||
|
case MONTHS:
|
||||||
|
numberOfPeriods = difference.getMonths();
|
||||||
|
break;
|
||||||
|
case YEARS:
|
||||||
|
numberOfPeriods = difference.getYears();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return numberOfPeriods;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+33
-23
@@ -54,9 +54,9 @@ import org.mifosplatform.portfolio.loanaccount.data.LoanChargeData;
|
|||||||
import org.mifosplatform.portfolio.loanaccount.domain.DefaultLoanLifecycleStateMachine;
|
import org.mifosplatform.portfolio.loanaccount.domain.DefaultLoanLifecycleStateMachine;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
|
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.LoanLifecycleStateMachine;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
|
||||||
@@ -119,8 +119,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
private final CalendarInstanceRepository calendarInstanceRepository;
|
private final CalendarInstanceRepository calendarInstanceRepository;
|
||||||
private final SavingsAccountAssembler savingsAccountAssembler;
|
private final SavingsAccountAssembler savingsAccountAssembler;
|
||||||
private final AccountAssociationsRepository accountAssociationsRepository;
|
private final AccountAssociationsRepository accountAssociationsRepository;
|
||||||
private final LoanChargeRepository loanChargeRepository;
|
|
||||||
private final LoanReadPlatformService loanReadPlatformService;
|
private final LoanReadPlatformService loanReadPlatformService;
|
||||||
|
private final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LoanApplicationWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final FromJsonHelper fromJsonHelper,
|
public LoanApplicationWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final FromJsonHelper fromJsonHelper,
|
||||||
@@ -135,7 +135,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
|
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
|
||||||
final CalendarRepository calendarRepository, final CalendarInstanceRepository calendarInstanceRepository,
|
final CalendarRepository calendarRepository, final CalendarInstanceRepository calendarInstanceRepository,
|
||||||
final SavingsAccountAssembler savingsAccountAssembler, final AccountAssociationsRepository accountAssociationsRepository,
|
final SavingsAccountAssembler savingsAccountAssembler, final AccountAssociationsRepository accountAssociationsRepository,
|
||||||
final LoanChargeRepository loanChargeRepository, final LoanReadPlatformService loanReadPlatformService) {
|
final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository,
|
||||||
|
final LoanReadPlatformService loanReadPlatformService) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.fromJsonHelper = fromJsonHelper;
|
this.fromJsonHelper = fromJsonHelper;
|
||||||
this.loanApplicationTransitionApiJsonValidator = loanApplicationTransitionApiJsonValidator;
|
this.loanApplicationTransitionApiJsonValidator = loanApplicationTransitionApiJsonValidator;
|
||||||
@@ -158,7 +159,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
this.calendarInstanceRepository = calendarInstanceRepository;
|
this.calendarInstanceRepository = calendarInstanceRepository;
|
||||||
this.savingsAccountAssembler = savingsAccountAssembler;
|
this.savingsAccountAssembler = savingsAccountAssembler;
|
||||||
this.accountAssociationsRepository = accountAssociationsRepository;
|
this.accountAssociationsRepository = accountAssociationsRepository;
|
||||||
this.loanChargeRepository = loanChargeRepository;
|
this.repaymentScheduleInstallmentRepository = repaymentScheduleInstallmentRepository;
|
||||||
this.loanReadPlatformService = loanReadPlatformService;
|
this.loanReadPlatformService = loanReadPlatformService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -517,36 +518,22 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
|
|
||||||
final LoanScheduleModel loanSchedule = this.calculationPlatformService.calculateLoanSchedule(query, false);
|
final LoanScheduleModel loanSchedule = this.calculationPlatformService.calculateLoanSchedule(query, false);
|
||||||
existingLoanApplication.updateLoanSchedule(loanSchedule);
|
existingLoanApplication.updateLoanSchedule(loanSchedule);
|
||||||
|
existingLoanApplication.recalculateAllCharges();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loanRepository.saveAndFlush(existingLoanApplication);
|
|
||||||
|
|
||||||
// FIXME: adding loan installment charges along with the other
|
|
||||||
// charges,
|
|
||||||
// is trying to add extra entries with null values. Because of that
|
|
||||||
// persisting charges separately
|
|
||||||
final String chargesParamName = "charges";
|
final String chargesParamName = "charges";
|
||||||
if (changes.containsKey(chargesParamName)) {
|
if (changes.containsKey(chargesParamName)) {
|
||||||
final Set<LoanCharge> loanCharges = this.loanChargeAssembler.fromParsedJson(command.parsedJson());
|
existingLoanApplication.updateLoanCharges(possiblyModifedLoanCharges);
|
||||||
existingLoanApplication.updateLoanCharges(loanCharges);
|
|
||||||
this.loanRepository.saveAndFlush(existingLoanApplication);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
saveAndFlushLoanWithDataIntegrityViolationChecks(existingLoanApplication);
|
||||||
|
|
||||||
final String submittedOnNote = command.stringValueOfParameterNamed("submittedOnNote");
|
final String submittedOnNote = command.stringValueOfParameterNamed("submittedOnNote");
|
||||||
if (StringUtils.isNotBlank(submittedOnNote)) {
|
if (StringUtils.isNotBlank(submittedOnNote)) {
|
||||||
final Note note = Note.loanNote(existingLoanApplication, submittedOnNote);
|
final Note note = Note.loanNote(existingLoanApplication, submittedOnNote);
|
||||||
this.noteRepository.save(note);
|
this.noteRepository.save(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final LoanCharge loanCharge : existingLoanApplication.charges()) {
|
|
||||||
if (loanCharge.isInstalmentFee() && loanCharge.hasNoLoanInstallmentCharges()) {
|
|
||||||
final Set<LoanInstallmentCharge> chargePerInstallments = existingLoanApplication
|
|
||||||
.generateInstallmentLoanCharges(loanCharge);
|
|
||||||
loanCharge.addLoanInstallmentCharges(chargePerInstallments);
|
|
||||||
this.loanChargeRepository.save(loanCharge);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final Long calendarId = command.longValueOfParameterNamed("calendarId");
|
final Long calendarId = command.longValueOfParameterNamed("calendarId");
|
||||||
Calendar calendar = null;
|
Calendar calendar = null;
|
||||||
if (calendarId != null && calendarId != 0) {
|
if (calendarId != null && calendarId != 0) {
|
||||||
@@ -896,4 +883,27 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void saveAndFlushLoanWithDataIntegrityViolationChecks(final Loan loan) {
|
||||||
|
try {
|
||||||
|
List<LoanRepaymentScheduleInstallment> installments = loan.fetchRepaymentScheduleInstallments();
|
||||||
|
for (LoanRepaymentScheduleInstallment installment : installments) {
|
||||||
|
if (installment.getId() == null) {
|
||||||
|
this.repaymentScheduleInstallmentRepository.save(installment);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.loanRepository.saveAndFlush(loan);
|
||||||
|
} catch (final DataIntegrityViolationException e) {
|
||||||
|
final Throwable realCause = e.getCause();
|
||||||
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||||
|
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan.application");
|
||||||
|
if (realCause.getMessage().toLowerCase().contains("external_id_unique")) {
|
||||||
|
baseDataValidator.reset().parameter("externalId").failWithCode("value.must.be.unique");
|
||||||
|
}
|
||||||
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
|
||||||
|
"Validation errors exist.", dataValidationErrors); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+69
-51
@@ -98,6 +98,7 @@ import org.mifosplatform.portfolio.loanaccount.domain.LoanInstallmentCharge;
|
|||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanOverdueInstallmentCharge;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanOverdueInstallmentCharge;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
||||||
@@ -166,6 +167,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
private final FromJsonHelper fromApiJsonHelper;
|
private final FromJsonHelper fromApiJsonHelper;
|
||||||
private final AccountTransferRepository accountTransferRepository;
|
private final AccountTransferRepository accountTransferRepository;
|
||||||
private final CalendarRepository calendarRepository;
|
private final CalendarRepository calendarRepository;
|
||||||
|
private final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||||
@@ -185,7 +187,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService,
|
final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService,
|
||||||
final LoanChargeReadPlatformService loanChargeReadPlatformService, final LoanReadPlatformService loanReadPlatformService,
|
final LoanChargeReadPlatformService loanChargeReadPlatformService, final LoanReadPlatformService loanReadPlatformService,
|
||||||
final FromJsonHelper fromApiJsonHelper, final AccountTransferRepository accountTransferRepository,
|
final FromJsonHelper fromApiJsonHelper, final AccountTransferRepository accountTransferRepository,
|
||||||
final CalendarRepository calendarRepository) {
|
final CalendarRepository calendarRepository,
|
||||||
|
final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.loanEventApiJsonValidator = loanEventApiJsonValidator;
|
this.loanEventApiJsonValidator = loanEventApiJsonValidator;
|
||||||
this.loanAssembler = loanAssembler;
|
this.loanAssembler = loanAssembler;
|
||||||
@@ -213,6 +216,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||||
this.accountTransferRepository = accountTransferRepository;
|
this.accountTransferRepository = accountTransferRepository;
|
||||||
this.calendarRepository = calendarRepository;
|
this.calendarRepository = calendarRepository;
|
||||||
|
this.repaymentScheduleInstallmentRepository = repaymentScheduleInstallmentRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
|
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
|
||||||
@@ -267,6 +271,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
Money amountBeforeAdjust = loan.getPrincpal();
|
Money amountBeforeAdjust = loan.getPrincpal();
|
||||||
loan.validateAccountStatus(LoanEvent.LOAN_DISBURSED);
|
loan.validateAccountStatus(LoanEvent.LOAN_DISBURSED);
|
||||||
boolean canDisburse = loan.canDisburse(actualDisbursementDate);
|
boolean canDisburse = loan.canDisburse(actualDisbursementDate);
|
||||||
|
ChangedTransactionDetail changedTransactionDetail = null;
|
||||||
if (canDisburse) {
|
if (canDisburse) {
|
||||||
Money disburseAmount = loan.adjustDisburseAmount(command, actualDisbursementDate);
|
Money disburseAmount = loan.adjustDisburseAmount(command, actualDisbursementDate);
|
||||||
boolean recalcualteSchedule = amountBeforeAdjust.isNotEqualTo(loan.getPrincpal());
|
boolean recalcualteSchedule = amountBeforeAdjust.isNotEqualTo(loan.getPrincpal());
|
||||||
@@ -286,9 +291,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
loan.disburse(this.loanScheduleFactory, currentUser, command, applicationCurrency, existingTransactionIds,
|
changedTransactionDetail = loan.disburse(this.loanScheduleFactory, currentUser, command, applicationCurrency,
|
||||||
existingReversedTransactionIds, changes, calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays, workingDays,
|
existingTransactionIds, existingReversedTransactionIds, changes, calculatedRepaymentsStartingFromDate,
|
||||||
allowTransactionsOnHoliday, allowTransactionsOnNonWorkingDay, recalcualteSchedule, restCalendarInstance);
|
isHolidayEnabled, holidays, workingDays, allowTransactionsOnHoliday, allowTransactionsOnNonWorkingDay,
|
||||||
|
recalcualteSchedule, restCalendarInstance);
|
||||||
}
|
}
|
||||||
if (!changes.isEmpty()) {
|
if (!changes.isEmpty()) {
|
||||||
saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||||
@@ -299,11 +305,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
this.noteRepository.save(note);
|
this.noteRepository.save(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
// fix me
|
|
||||||
// adding loan installment charges along with the actual
|
|
||||||
// disbursement, is trying to add 2 extra entries with null values.
|
|
||||||
// which is causing issues
|
|
||||||
ChangedTransactionDetail changedTransactionDetail = loan.reprocessTransactionForDisbursement();
|
|
||||||
saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||||
|
|
||||||
if (changedTransactionDetail != null) {
|
if (changedTransactionDetail != null) {
|
||||||
@@ -367,6 +368,14 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
|
|
||||||
private void saveAndFlushLoanWithDataIntegrityViolationChecks(final Loan loan) {
|
private void saveAndFlushLoanWithDataIntegrityViolationChecks(final Loan loan) {
|
||||||
try {
|
try {
|
||||||
|
List<LoanRepaymentScheduleInstallment> installments = loan.fetchRepaymentScheduleInstallments();
|
||||||
|
for (LoanRepaymentScheduleInstallment installment : installments) {
|
||||||
|
if (installment.getId() == null) {
|
||||||
|
this.repaymentScheduleInstallmentRepository.save(installment);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
this.loanRepository.saveAndFlush(loan);
|
this.loanRepository.saveAndFlush(loan);
|
||||||
} catch (final DataIntegrityViolationException e) {
|
} catch (final DataIntegrityViolationException e) {
|
||||||
final Throwable realCause = e.getCause();
|
final Throwable realCause = e.getCause();
|
||||||
@@ -380,6 +389,29 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void saveLoanWithDataIntegrityViolationChecks(final Loan loan) {
|
||||||
|
try {
|
||||||
|
List<LoanRepaymentScheduleInstallment> installments = loan.fetchRepaymentScheduleInstallments();
|
||||||
|
for (LoanRepaymentScheduleInstallment installment : installments) {
|
||||||
|
if (installment.getId() == null) {
|
||||||
|
this.repaymentScheduleInstallmentRepository.save(installment);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.loanRepository.save(loan);
|
||||||
|
} catch (final DataIntegrityViolationException e) {
|
||||||
|
final Throwable realCause = e.getCause();
|
||||||
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||||
|
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan.transaction");
|
||||||
|
if (realCause.getMessage().toLowerCase().contains("external_id_unique")) {
|
||||||
|
baseDataValidator.reset().parameter("externalId").failWithCode("value.must.be.unique");
|
||||||
|
}
|
||||||
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
|
||||||
|
"Validation errors exist.", dataValidationErrors); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/****
|
/****
|
||||||
* TODO Vishwas: Pair with Ashok and re-factor collection sheet code-base
|
* TODO Vishwas: Pair with Ashok and re-factor collection sheet code-base
|
||||||
*
|
*
|
||||||
@@ -426,6 +458,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
loan.validateAccountStatus(LoanEvent.LOAN_DISBURSED);
|
loan.validateAccountStatus(LoanEvent.LOAN_DISBURSED);
|
||||||
updateLoanCounters(loan, actualDisbursementDate);
|
updateLoanCounters(loan, actualDisbursementDate);
|
||||||
boolean canDisburse = loan.canDisburse(actualDisbursementDate);
|
boolean canDisburse = loan.canDisburse(actualDisbursementDate);
|
||||||
|
ChangedTransactionDetail changedTransactionDetail = null;
|
||||||
if (canDisburse) {
|
if (canDisburse) {
|
||||||
Money amountBeforeAdjust = loan.getPrincpal();
|
Money amountBeforeAdjust = loan.getPrincpal();
|
||||||
Money disburseAmount = loan.adjustDisburseAmount(command, actualDisbursementDate);
|
Money disburseAmount = loan.adjustDisburseAmount(command, actualDisbursementDate);
|
||||||
@@ -445,24 +478,14 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
loan.disburse(this.loanScheduleFactory, currentUser, command, applicationCurrency, existingTransactionIds,
|
changedTransactionDetail = loan.disburse(this.loanScheduleFactory, currentUser, command, applicationCurrency,
|
||||||
existingReversedTransactionIds, changes, firstRepaymentOnDate, isHolidayEnabled, holidays, workingDays,
|
existingTransactionIds, existingReversedTransactionIds, changes, firstRepaymentOnDate, isHolidayEnabled, holidays,
|
||||||
allowTransactionsOnHoliday, allowTransactionsOnNonWorkingDay, recalcualteSchedule, restCalendarInstance);
|
workingDays, allowTransactionsOnHoliday, allowTransactionsOnNonWorkingDay, recalcualteSchedule,
|
||||||
|
restCalendarInstance);
|
||||||
}
|
}
|
||||||
if (!changes.isEmpty()) {
|
if (!changes.isEmpty()) {
|
||||||
try {
|
|
||||||
this.loanRepository.save(loan);
|
saveLoanWithDataIntegrityViolationChecks(loan);
|
||||||
} catch (final DataIntegrityViolationException e) {
|
|
||||||
final Throwable realCause = e.getCause();
|
|
||||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
|
||||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
|
||||||
.resource("loan.transaction");
|
|
||||||
if (realCause.getMessage().toLowerCase().contains("external_id_unique")) {
|
|
||||||
baseDataValidator.reset().parameter("externalId").failWithCode("value.must.be.unique");
|
|
||||||
}
|
|
||||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(
|
|
||||||
"validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors); }
|
|
||||||
}
|
|
||||||
|
|
||||||
final String noteText = command.stringValueOfParameterNamed("note");
|
final String noteText = command.stringValueOfParameterNamed("note");
|
||||||
if (StringUtils.isNotBlank(noteText)) {
|
if (StringUtils.isNotBlank(noteText)) {
|
||||||
@@ -470,11 +493,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
this.noteRepository.save(note);
|
this.noteRepository.save(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
// fix me
|
|
||||||
// adding loan installment charges along with the actual
|
|
||||||
// disbursement, is trying to add 2 extra entries with null
|
|
||||||
// values. which is causing issues
|
|
||||||
ChangedTransactionDetail changedTransactionDetail = loan.reprocessTransactionForDisbursement();
|
|
||||||
saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||||
if (changedTransactionDetail != null) {
|
if (changedTransactionDetail != null) {
|
||||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||||
@@ -542,7 +560,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
existingReversedTransactionIds, calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays, workingDays);
|
existingReversedTransactionIds, calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays, workingDays);
|
||||||
|
|
||||||
if (!changes.isEmpty()) {
|
if (!changes.isEmpty()) {
|
||||||
this.loanRepository.saveAndFlush(loan);
|
saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||||
this.accountTransfersWritePlatformService.reverseAllTransactions(loanId, PortfolioAccountType.LOAN);
|
this.accountTransfersWritePlatformService.reverseAllTransactions(loanId, PortfolioAccountType.LOAN);
|
||||||
String noteText = null;
|
String noteText = null;
|
||||||
if (command.hasParameter("note")) {
|
if (command.hasParameter("note")) {
|
||||||
@@ -719,7 +737,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
* only in edge cases (when a adjustment is made before the latest
|
* only in edge cases (when a adjustment is made before the latest
|
||||||
* payment recorded against the loan)
|
* payment recorded against the loan)
|
||||||
***/
|
***/
|
||||||
this.loanRepository.saveAndFlush(loan);
|
saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||||
if (changedTransactionDetail != null) {
|
if (changedTransactionDetail != null) {
|
||||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||||
this.loanTransactionRepository.save(mapEntry.getValue());
|
this.loanTransactionRepository.save(mapEntry.getValue());
|
||||||
@@ -821,7 +839,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
* only in edge cases (when a waiver is made before the latest payment
|
* only in edge cases (when a waiver is made before the latest payment
|
||||||
* recorded against the loan)
|
* recorded against the loan)
|
||||||
***/
|
***/
|
||||||
this.loanRepository.saveAndFlush(loan);
|
saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||||
if (changedTransactionDetail != null) {
|
if (changedTransactionDetail != null) {
|
||||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||||
this.loanTransactionRepository.save(mapEntry.getValue());
|
this.loanTransactionRepository.save(mapEntry.getValue());
|
||||||
@@ -898,7 +916,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
this.loanTransactionRepository.save(mapEntry.getValue());
|
this.loanTransactionRepository.save(mapEntry.getValue());
|
||||||
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
|
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
|
||||||
}
|
}
|
||||||
this.loanRepository.save(loan);
|
saveLoanWithDataIntegrityViolationChecks(loan);
|
||||||
final String noteText = command.stringValueOfParameterNamed("note");
|
final String noteText = command.stringValueOfParameterNamed("note");
|
||||||
if (StringUtils.isNotBlank(noteText)) {
|
if (StringUtils.isNotBlank(noteText)) {
|
||||||
changes.put("note", noteText);
|
changes.put("note", noteText);
|
||||||
@@ -968,7 +986,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
this.loanTransactionRepository.save(mapEntry.getValue());
|
this.loanTransactionRepository.save(mapEntry.getValue());
|
||||||
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
|
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
|
||||||
}
|
}
|
||||||
this.loanRepository.save(loan);
|
saveLoanWithDataIntegrityViolationChecks(loan);
|
||||||
|
|
||||||
final String noteText = command.stringValueOfParameterNamed("note");
|
final String noteText = command.stringValueOfParameterNamed("note");
|
||||||
if (StringUtils.isNotBlank(noteText)) {
|
if (StringUtils.isNotBlank(noteText)) {
|
||||||
@@ -1026,7 +1044,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
|
|
||||||
loan.closeAsMarkedForReschedule(command, defaultLoanLifecycleStateMachine(), changes);
|
loan.closeAsMarkedForReschedule(command, defaultLoanLifecycleStateMachine(), changes);
|
||||||
|
|
||||||
this.loanRepository.save(loan);
|
saveLoanWithDataIntegrityViolationChecks(loan);
|
||||||
|
|
||||||
final String noteText = command.stringValueOfParameterNamed("note");
|
final String noteText = command.stringValueOfParameterNamed("note");
|
||||||
if (StringUtils.isNotBlank(noteText)) {
|
if (StringUtils.isNotBlank(noteText)) {
|
||||||
@@ -1120,7 +1138,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
* entered only in edge cases (when a payment is made before the
|
* entered only in edge cases (when a payment is made before the
|
||||||
* latest payment recorded against the loan)
|
* latest payment recorded against the loan)
|
||||||
***/
|
***/
|
||||||
this.loanRepository.save(loan);
|
saveLoanWithDataIntegrityViolationChecks(loan);
|
||||||
if (changedTransactionDetail != null) {
|
if (changedTransactionDetail != null) {
|
||||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||||
this.loanTransactionRepository.save(mapEntry.getValue());
|
this.loanTransactionRepository.save(mapEntry.getValue());
|
||||||
@@ -1155,7 +1173,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
|
|
||||||
final Map<String, Object> changes = loan.updateLoanCharge(loanCharge, command);
|
final Map<String, Object> changes = loan.updateLoanCharge(loanCharge, command);
|
||||||
|
|
||||||
this.loanRepository.save(loan);
|
saveLoanWithDataIntegrityViolationChecks(loan);
|
||||||
|
|
||||||
return new CommandProcessingResultBuilder() //
|
return new CommandProcessingResultBuilder() //
|
||||||
.withCommandId(command.commandId()) //
|
.withCommandId(command.commandId()) //
|
||||||
@@ -1220,7 +1238,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
existingTransactionIds, existingReversedTransactionIds, loanInstallmentNumber);
|
existingTransactionIds, existingReversedTransactionIds, loanInstallmentNumber);
|
||||||
|
|
||||||
this.loanTransactionRepository.save(waiveTransaction);
|
this.loanTransactionRepository.save(waiveTransaction);
|
||||||
this.loanRepository.save(loan);
|
saveLoanWithDataIntegrityViolationChecks(loan);
|
||||||
|
|
||||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||||
|
|
||||||
@@ -1251,7 +1269,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
LOAN_CHARGE_CANNOT_BE_DELETED_REASON.LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE, loanCharge.getId()); }
|
LOAN_CHARGE_CANNOT_BE_DELETED_REASON.LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE, loanCharge.getId()); }
|
||||||
|
|
||||||
loan.removeLoanCharge(loanCharge);
|
loan.removeLoanCharge(loanCharge);
|
||||||
this.loanRepository.save(loan);
|
saveLoanWithDataIntegrityViolationChecks(loan);
|
||||||
|
|
||||||
return new CommandProcessingResultBuilder() //
|
return new CommandProcessingResultBuilder() //
|
||||||
.withCommandId(command.commandId()) //
|
.withCommandId(command.commandId()) //
|
||||||
@@ -1448,7 +1466,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
loan.setLoanStatus(LoanStatus.TRANSFER_IN_PROGRESS.getValue());
|
loan.setLoanStatus(LoanStatus.TRANSFER_IN_PROGRESS.getValue());
|
||||||
|
|
||||||
this.loanTransactionRepository.save(newTransferTransaction);
|
this.loanTransactionRepository.save(newTransferTransaction);
|
||||||
this.loanRepository.save(loan);
|
saveLoanWithDataIntegrityViolationChecks(loan);
|
||||||
|
|
||||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||||
|
|
||||||
@@ -1477,7 +1495,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.loanTransactionRepository.save(newTransferAcceptanceTransaction);
|
this.loanTransactionRepository.save(newTransferAcceptanceTransaction);
|
||||||
this.loanRepository.save(loan);
|
saveLoanWithDataIntegrityViolationChecks(loan);
|
||||||
|
|
||||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||||
|
|
||||||
@@ -1497,7 +1515,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
loan.setLoanStatus(LoanStatus.ACTIVE.getValue());
|
loan.setLoanStatus(LoanStatus.ACTIVE.getValue());
|
||||||
|
|
||||||
this.loanTransactionRepository.save(newTransferAcceptanceTransaction);
|
this.loanTransactionRepository.save(newTransferAcceptanceTransaction);
|
||||||
this.loanRepository.save(loan);
|
saveLoanWithDataIntegrityViolationChecks(loan);
|
||||||
|
|
||||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||||
|
|
||||||
@@ -1509,7 +1527,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
public void rejectLoanTransfer(final Long accountId) {
|
public void rejectLoanTransfer(final Long accountId) {
|
||||||
final Loan loan = this.loanAssembler.assembleFrom(accountId);
|
final Loan loan = this.loanAssembler.assembleFrom(accountId);
|
||||||
loan.setLoanStatus(LoanStatus.TRANSFER_ON_HOLD.getValue());
|
loan.setLoanStatus(LoanStatus.TRANSFER_ON_HOLD.getValue());
|
||||||
this.loanRepository.save(loan);
|
saveLoanWithDataIntegrityViolationChecks(loan);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@@ -1534,7 +1552,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
|
|
||||||
loan.reassignLoanOfficer(toLoanOfficer, dateOfLoanOfficerAssignment);
|
loan.reassignLoanOfficer(toLoanOfficer, dateOfLoanOfficerAssignment);
|
||||||
|
|
||||||
this.loanRepository.save(loan);
|
saveLoanWithDataIntegrityViolationChecks(loan);
|
||||||
|
|
||||||
return new CommandProcessingResultBuilder() //
|
return new CommandProcessingResultBuilder() //
|
||||||
.withCommandId(command.commandId()) //
|
.withCommandId(command.commandId()) //
|
||||||
@@ -1570,7 +1588,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
if (!loan.hasLoanOfficer(fromLoanOfficer)) { throw new LoanOfficerAssignmentException(loanId, fromLoanOfficerId); }
|
if (!loan.hasLoanOfficer(fromLoanOfficer)) { throw new LoanOfficerAssignmentException(loanId, fromLoanOfficerId); }
|
||||||
|
|
||||||
loan.reassignLoanOfficer(toLoanOfficer, dateOfLoanOfficerAssignment);
|
loan.reassignLoanOfficer(toLoanOfficer, dateOfLoanOfficerAssignment);
|
||||||
this.loanRepository.save(loan);
|
saveLoanWithDataIntegrityViolationChecks(loan);
|
||||||
}
|
}
|
||||||
this.loanRepository.flush();
|
this.loanRepository.flush();
|
||||||
|
|
||||||
@@ -1598,7 +1616,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
|
|
||||||
loan.removeLoanOfficer(dateOfLoanOfficerunAssigned);
|
loan.removeLoanOfficer(dateOfLoanOfficerunAssigned);
|
||||||
|
|
||||||
this.loanRepository.save(loan);
|
saveLoanWithDataIntegrityViolationChecks(loan);
|
||||||
|
|
||||||
return new CommandProcessingResultBuilder() //
|
return new CommandProcessingResultBuilder() //
|
||||||
.withCommandId(command.commandId()) //
|
.withCommandId(command.commandId()) //
|
||||||
@@ -1644,7 +1662,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan.getDisbursementDate().toDate());
|
holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan.getDisbursementDate().toDate());
|
||||||
loan.updateLoanRepaymentScheduleDates(calendar.getStartDateLocalDate(), calendar.getRecurrence(), isHolidayEnabled,
|
loan.updateLoanRepaymentScheduleDates(calendar.getStartDateLocalDate(), calendar.getRecurrence(), isHolidayEnabled,
|
||||||
holidays, workingDays);
|
holidays, workingDays);
|
||||||
this.loanRepository.save(loan);
|
saveLoanWithDataIntegrityViolationChecks(loan);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2022,7 +2040,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
|
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.loanRepository.save(loan);
|
saveLoanWithDataIntegrityViolationChecks(loan);
|
||||||
|
|
||||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||||
return new CommandProcessingResultBuilder() //
|
return new CommandProcessingResultBuilder() //
|
||||||
@@ -2064,7 +2082,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
existingTransactionIds, existingReversedTransactionIds, changes, this.loanScheduleFactory, applicationCurrency,
|
existingTransactionIds, existingReversedTransactionIds, changes, this.loanScheduleFactory, applicationCurrency,
|
||||||
calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays, workingDays, restCalendarInstance);
|
calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays, workingDays, restCalendarInstance);
|
||||||
|
|
||||||
this.loanRepository.saveAndFlush(loan);
|
saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||||
|
|
||||||
if (changedTransactionDetail != null) {
|
if (changedTransactionDetail != null) {
|
||||||
for (Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
for (Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||||
@@ -2191,7 +2209,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays, workingDays, restCalendarInstance,
|
calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays, workingDays, restCalendarInstance,
|
||||||
existingTransactionIds, existingReversedTransactionIds);
|
existingTransactionIds, existingReversedTransactionIds);
|
||||||
|
|
||||||
this.loanRepository.save(loan);
|
saveLoanWithDataIntegrityViolationChecks(loan);
|
||||||
|
|
||||||
if (changedTransactionDetail != null) {
|
if (changedTransactionDetail != null) {
|
||||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user