}
existingLoanApplication.updateIsInterestRecalculationEnabled();
validateSubmittedOnDate(existingLoanApplication);
final LoanProductRelatedDetail productRelatedDetail = existingLoanApplication.repaymentScheduleDetail();
this.fromApiJsonDeserializer.validateLoanTermAndRepaidEveryValues(existingLoanApplication.getTermFrequency(),
existingLoanApplication.getTermPeriodFrequencyType(), productRelatedDetail.getNumberOfRepayments(),
productRelatedDetail.getRepayEvery(), productRelatedDetail.getRepaymentPeriodFrequencyType().getValue());
final String fundIdParamName = "fundId";
if (changes.containsKey(fundIdParamName)) {
final Long fundId = command.longValueOfParameterNamed(fundIdParamName);
final Fund fund = this.loanAssembler.findFundByIdIfProvided(fundId);
existingLoanApplication.updateFund(fund);
}
final String loanPurposeIdParamName = "loanPurposeId";
if (changes.containsKey(loanPurposeIdParamName)) {
final Long loanPurposeId = command.longValueOfParameterNamed(loanPurposeIdParamName);
final CodeValue loanPurpose = this.loanAssembler.findCodeValueByIdIfProvided(loanPurposeId);
existingLoanApplication.updateLoanPurpose(loanPurpose);
}
final String loanOfficerIdParamName = "loanOfficerId";
if (changes.containsKey(loanOfficerIdParamName)) {
final Long loanOfficerId = command.longValueOfParameterNamed(loanOfficerIdParamName);
final Staff newValue = this.loanAssembler.findLoanOfficerByIdIfProvided(loanOfficerId);
existingLoanApplication.updateLoanOfficerOnLoanApplication(newValue);
}
final String strategyIdParamName = "transactionProcessingStrategyId";
if (changes.containsKey(strategyIdParamName)) {
final Long strategyId = command.longValueOfParameterNamed(strategyIdParamName);
final LoanTransactionProcessingStrategy strategy = this.loanAssembler.findStrategyByIdIfProvided(strategyId);
existingLoanApplication.updateTransactionProcessingStrategy(strategy);
}
final String collateralParamName = "collateral";
if (changes.containsKey(collateralParamName)) {
final Set<LoanCollateral> loanCollateral = this.loanCollateralAssembler.fromParsedJson(command.parsedJson());
existingLoanApplication.updateLoanCollateral(loanCollateral);
}
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);
final LoanScheduleModel loanSchedule = this.calculationPlatformService.calculateLoanSchedule(query, false);
existingLoanApplication.updateLoanSchedule(loanSchedule);
existingLoanApplication.recalculateAllCharges();
}
final String chargesParamName = "charges";
if (changes.containsKey(chargesParamName)) {
existingLoanApplication.updateLoanCharges(possiblyModifedLoanCharges);
}
saveAndFlushLoanWithDataIntegrityViolationChecks(existingLoanApplication);
final String submittedOnNote = command.stringValueOfParameterNamed("submittedOnNote");
if (StringUtils.isNotBlank(submittedOnNote)) {
final Note note = Note.loanNote(existingLoanApplication, submittedOnNote);
this.noteRepository.save(note);
}
final Long calendarId = command.longValueOfParameterNamed("calendarId");
Calendar calendar = null;
if (calendarId != null && calendarId != 0) {
calendar = this.calendarRepository.findOne(calendarId);
if (calendar == null) { throw new CalendarNotFoundException(calendarId); }
}
final List<CalendarInstance> ciList = (List<CalendarInstance>) this.calendarInstanceRepository.findByEntityIdAndEntityTypeId(
loanId, CalendarEntityType.LOANS.getValue());
if (calendar != null) {
// For loans, allow to attach only one calendar instance per
// loan
if (ciList != null && !ciList.isEmpty()) {
final CalendarInstance calendarInstance = ciList.get(0);
if (calendarInstance.getCalendar().getId() != calendar.getId()) {
calendarInstance.updateCalendar(calendar);
this.calendarInstanceRepository.saveAndFlush(calendarInstance);
}
} else {
// attaching new calendar
final CalendarInstance calendarInstance = new CalendarInstance(calendar, existingLoanApplication.getId(),
CalendarEntityType.LOANS.getValue());
this.calendarInstanceRepository.save(calendarInstance);
}
} else if (ciList != null && !ciList.isEmpty()) {
final CalendarInstance calendarInstance = ciList.get(0);
this.calendarInstanceRepository.delete(calendarInstance);
}
// Save linked account information
final String linkAccountIdParamName = "linkAccountId";
final Long savingsAccountId = command.longValueOfParameterNamed(linkAccountIdParamName);
AccountAssociations accountAssociations = this.accountAssociationsRepository.findByLoanId(loanId);
boolean isLinkedAccPresent = false;
if (savingsAccountId == null) {
if (accountAssociations != null) {
if (this.fromJsonHelper.parameterExists(linkAccountIdParamName, command.parsedJson())) {
this.accountAssociationsRepository.delete(accountAssociations);
changes.put(linkAccountIdParamName, null);
} else {
isLinkedAccPresent = true;
}
}
} else {
isLinkedAccPresent = true;
boolean isModified = false;
if (accountAssociations == null) {
isModified = true;
} else {
final SavingsAccount savingsAccount = accountAssociations.linkedSavingsAccount();
if (savingsAccount == null || savingsAccount.getId() != savingsAccountId) {
isModified = true;
}
}
if (isModified) {
final SavingsAccount savingsAccount = this.savingsAccountAssembler.assembleFrom(savingsAccountId);
this.fromApiJsonDeserializer.validatelinkedSavingsAccount(savingsAccount, existingLoanApplication);
if (accountAssociations == null) {
accountAssociations = AccountAssociations.associateSavingsAccount(existingLoanApplication, savingsAccount);
} else {
accountAssociations.updateLinkedSavingsAccount(savingsAccount);
}
changes.put(linkAccountIdParamName, savingsAccountId);
this.accountAssociationsRepository.save(accountAssociations);
}
}
if (!isLinkedAccPresent) {
final Set<LoanCharge> charges = existingLoanApplication.charges();
for (final LoanCharge loanCharge : charges) {
if (loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()) {
final String errorMessage = "one of the charges requires linked savings account for payment";
throw new LinkedAccountRequiredException("loanCharge", errorMessage);
}
}
}
// updating loan interest recalculation details throwing null
// pointer exception after saveAndFlush
// http://stackoverflow.com/questions/17151757/hibernate-cascade-update-gives-null-pointer/17334374#17334374
this.loanRepository.save(existingLoanApplication);
if (productRelatedDetail.isInterestRecalculationEnabled()) {
LocalDate recalculationFrequencyDate = existingLoanApplication.loanInterestRecalculationDetails()
.getRestFrequencyLocalDate();
if (recalculationFrequencyDate == null) {
recalculationFrequencyDate = existingLoanApplication.loanProduct().getProductInterestRecalculationDetails()
.getRestFrequencyLocalDate();