final Long loanOfficerId = this.fromApiJsonHelper.extractLongNamed("loanOfficerId", element);
final Long transactionProcessingStrategyId = this.fromApiJsonHelper.extractLongNamed("transactionProcessingStrategyId", element);
final Long loanPurposeId = this.fromApiJsonHelper.extractLongNamed("loanPurposeId", element);
final Boolean syncDisbursementWithMeeting = this.fromApiJsonHelper.extractBooleanNamed("syncDisbursementWithMeeting", element);
final LoanProduct loanProduct = this.loanProductRepository.findOne(productId);
if (loanProduct == null) { throw new LoanProductNotFoundException(productId); }
final Fund fund = findFundByIdIfProvided(fundId);
final Staff loanOfficer = findLoanOfficerByIdIfProvided(loanOfficerId);
final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy = findStrategyByIdIfProvided(transactionProcessingStrategyId);
CodeValue loanPurpose = null;
if (loanPurposeId != null) {
loanPurpose = this.codeValueRepository.findOneWithNotFoundDetection(loanPurposeId);
}
final Set<LoanCollateral> collateral = this.loanCollateralAssembler.fromParsedJson(element);
final Set<LoanCharge> loanCharges = this.loanChargeAssembler.fromParsedJson(element);
for (final LoanCharge loanCharge : loanCharges) {
if (!loanProduct.hasCurrencyCodeOf(loanCharge.currencyCode())) {
final String errorMessage = "Charge and Loan must have the same currency.";
throw new InvalidCurrencyException("loanCharge", "attach.to.loan", errorMessage);
}
if (loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()) {
final Long savingsAccountId = this.fromApiJsonHelper.extractLongNamed("linkAccountId", element);
if (savingsAccountId == null) {
final String errorMessage = "one of the charges requires linked savings account for payment";
throw new LinkedAccountRequiredException("loanCharge", errorMessage);
}
}
}
Loan loanApplication = null;
Client client = null;
Group group = null;
final LoanProductRelatedDetail loanProductRelatedDetail = this.loanScheduleAssembler.assembleLoanProductRelatedDetail(element);
final String loanTypeParameterName = "loanType";
final String loanTypeStr = this.fromApiJsonHelper.extractStringNamed(loanTypeParameterName, element);
final EnumOptionData loanType = AccountEnumerations.loanType(loanTypeStr);
Set<LoanDisbursementDetails> disbursementDetails = null;
BigDecimal fixedEmiAmount = null;
BigDecimal maxOutstandingLoanBalance = null;
if (loanProduct.isMultiDisburseLoan()) {
disbursementDetails = fetchDisbursementData(element.getAsJsonObject());
final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(element.getAsJsonObject());
fixedEmiAmount = this.fromApiJsonHelper.extractBigDecimalNamed(LoanApiConstants.emiAmountParameterName, element, locale);
maxOutstandingLoanBalance = this.fromApiJsonHelper.extractBigDecimalNamed(LoanApiConstants.maxOutstandingBalanceParameterName,
element, locale);
if (disbursementDetails.isEmpty()) {
final String errorMessage = "For this loan product, disbursement details must be provided";
throw new MultiDisbursementDataRequiredException(LoanApiConstants.disbursementDataParameterName, errorMessage);
}
if (disbursementDetails.size() > loanProduct.maxTrancheCount()) {
final String errorMessage = "Number of tranche shouldn't be greter than " + loanProduct.maxTrancheCount();
throw new ExceedingTrancheCountException(LoanApiConstants.disbursementDataParameterName, errorMessage,
loanProduct.maxTrancheCount(), disbursementDetails.size());
}
}
if (clientId != null) {
client = this.clientRepository.findOneWithNotFoundDetection(clientId);
if (client.isNotActive()) { throw new ClientNotActiveException(clientId); }
}
if (groupId != null) {
group = this.groupRepository.findOne(groupId);
if (group == null) { throw new GroupNotFoundException(groupId); }
if (group.isNotActive()) { throw new GroupNotActiveException(groupId); }
}
if (client != null && group != null) {
if (!group.hasClientAsMember(client)) { throw new ClientNotInGroupException(clientId, groupId); }
loanApplication = Loan.newIndividualLoanApplicationFromGroup(accountNo, client, group, loanType.getId().intValue(),
loanProduct, fund, loanOfficer, loanPurpose, loanTransactionProcessingStrategy, loanProductRelatedDetail, loanCharges,
collateral, syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance);
} else if (group != null) {
loanApplication = Loan.newGroupLoanApplication(accountNo, group, loanType.getId().intValue(), loanProduct, fund, loanOfficer,
loanPurpose, loanTransactionProcessingStrategy, loanProductRelatedDetail, loanCharges, collateral,
syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance);
} else if (client != null) {
loanApplication = Loan.newIndividualLoanApplication(accountNo, client, loanType.getId().intValue(), loanProduct, fund,
loanOfficer, loanPurpose, loanTransactionProcessingStrategy, loanProductRelatedDetail, loanCharges, collateral,
fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance);
}
final String externalId = this.fromApiJsonHelper.extractStringNamed("externalId", element);
final LocalDate submittedOnDate = this.fromApiJsonHelper.extractLocalDateNamed("submittedOnDate", element);
if (loanApplication == null) { throw new IllegalStateException("No loan application exists for either a client or group (or both)."); }
loanApplication.setHelpers(defaultLoanLifecycleStateMachine(), this.loanSummaryWrapper,
this.loanRepaymentScheduleTransactionProcessorFactory);
if (loanProduct.isMultiDisburseLoan()) {
for (final LoanDisbursementDetails loanDisbursementDetails : loanApplication.getDisbursementDetails()) {
loanDisbursementDetails.updateLoan(loanApplication);
}
}