MIFOSX-37: support ability to update account no for loan accounts, also support ability to update external id (MIFOSX-46).
This commit is contained in:
@@ -0,0 +1,13 @@
|
|||||||
|
ALTER TABLE `m_loan`
|
||||||
|
ADD COLUMN `account_no` VARCHAR(20) NOT NULL AFTER `id`;
|
||||||
|
|
||||||
|
UPDATE `m_loan`
|
||||||
|
SET
|
||||||
|
`account_no` = `id`
|
||||||
|
WHERE `id` > 0;
|
||||||
|
|
||||||
|
ALTER TABLE `m_loan` ADD UNIQUE INDEX `loan_account_no_UNIQUE` (`account_no` ASC);
|
||||||
|
|
||||||
|
|
||||||
|
ALTER TABLE `m_loan` DROP INDEX `org_id`;
|
||||||
|
ALTER TABLE `m_loan` ADD UNIQUE INDEX `loan_externalid_UNIQUE` (`external_id` ASC);
|
||||||
+1
-2
@@ -265,7 +265,7 @@ public class ClientsApiResource {
|
|||||||
@Path("{clientId}/loans")
|
@Path("{clientId}/loans")
|
||||||
@Consumes({ MediaType.APPLICATION_JSON })
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
@Produces({ MediaType.APPLICATION_JSON })
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
public String retrieveClientAccount(@PathParam("clientId") final Long clientId, @Context final UriInfo uriInfo) {
|
public String retrieveClientAccounts(@PathParam("clientId") final Long clientId, @Context final UriInfo uriInfo) {
|
||||||
|
|
||||||
context.authenticatedUser().validateHasReadPermission("CLIENT");
|
context.authenticatedUser().validateHasReadPermission("CLIENT");
|
||||||
|
|
||||||
@@ -278,7 +278,6 @@ public class ClientsApiResource {
|
|||||||
"withdrawnByClientDepositAccountsCount", "withdrawnByClientDepositAccounts", "closedDepositAccountsCount",
|
"withdrawnByClientDepositAccountsCount", "withdrawnByClientDepositAccounts", "closedDepositAccountsCount",
|
||||||
"closedDepositAccounts", "maturedDepositAccountsCount", "maturedDepositAccounts", "rejectedDepositAccountsCount",
|
"closedDepositAccounts", "maturedDepositAccountsCount", "maturedDepositAccounts", "rejectedDepositAccountsCount",
|
||||||
"rejectedDepositAccounts", "preclosedDepositAccountsCount", "preclosedDepositAccounts",
|
"rejectedDepositAccounts", "preclosedDepositAccountsCount", "preclosedDepositAccounts",
|
||||||
|
|
||||||
"pendingApprovalSavingAccountsCount", "pendingApprovalSavingAccounts", "approvedSavingAccountsCount",
|
"pendingApprovalSavingAccountsCount", "pendingApprovalSavingAccounts", "approvedSavingAccountsCount",
|
||||||
"approvedSavingAccounts", "withdrawnByClientSavingAccountsCount", "withdrawnByClientSavingAccounts",
|
"approvedSavingAccounts", "withdrawnByClientSavingAccountsCount", "withdrawnByClientSavingAccounts",
|
||||||
"rejectedSavingAccountsCount", "rejectedSavingAccounts", "closedSavingAccountsCount", "closedSavingAccounts"));
|
"rejectedSavingAccountsCount", "rejectedSavingAccounts", "closedSavingAccountsCount", "closedSavingAccounts"));
|
||||||
|
|||||||
+5
-5
@@ -10,6 +10,8 @@ public class ClientAccountSummaryData {
|
|||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private final Long id;
|
private final Long id;
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
|
private final String accountNo;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
private final String externalId;
|
private final String externalId;
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private final Long productId;
|
private final Long productId;
|
||||||
@@ -22,6 +24,7 @@ public class ClientAccountSummaryData {
|
|||||||
public ClientAccountSummaryData(final Long id, final String externalId, final Long productId, final String loanProductName,
|
public ClientAccountSummaryData(final Long id, final String externalId, final Long productId, final String loanProductName,
|
||||||
final Integer loanStatusId) {
|
final Integer loanStatusId) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
this.accountNo = null;
|
||||||
this.externalId = externalId;
|
this.externalId = externalId;
|
||||||
this.productId = productId;
|
this.productId = productId;
|
||||||
this.productName = loanProductName;
|
this.productName = loanProductName;
|
||||||
@@ -29,13 +32,10 @@ public class ClientAccountSummaryData {
|
|||||||
this.status = null;
|
this.status = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public ClientAccountSummaryData(final Long id, final String accountNo, final String externalId, final Long productId, final String loanProductName,
|
||||||
* Rather than use id, just be consistent and use EnumOptionData for the
|
|
||||||
* status of an account.
|
|
||||||
*/
|
|
||||||
public ClientAccountSummaryData(final Long id, final String externalId, final Long productId, final String loanProductName,
|
|
||||||
final EnumOptionData loanStatus) {
|
final EnumOptionData loanStatus) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
this.accountNo = accountNo;
|
||||||
this.externalId = externalId;
|
this.externalId = externalId;
|
||||||
this.productId = productId;
|
this.productId = productId;
|
||||||
this.productName = loanProductName;
|
this.productName = loanProductName;
|
||||||
|
|||||||
-12
@@ -1,12 +0,0 @@
|
|||||||
package org.mifosplatform.portfolio.client.domain;
|
|
||||||
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
public class AccountIdentifierGeneratorFactory {
|
|
||||||
|
|
||||||
public AccountNumberGenerator determineClientAccountNoGenerator(final Long clientId) {
|
|
||||||
return new ClientAccountNumberGenerator(clientId, 9);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
+1
-1
@@ -3,7 +3,7 @@ package org.mifosplatform.portfolio.client.domain;
|
|||||||
/**
|
/**
|
||||||
* Responsible for generating unique account number based on some rules or patterns.
|
* Responsible for generating unique account number based on some rules or patterns.
|
||||||
*
|
*
|
||||||
* @see ClientAccountNumberGenerator
|
* @see ZeroPaddedAccountNumberGenerator
|
||||||
*/
|
*/
|
||||||
public interface AccountNumberGenerator {
|
public interface AccountNumberGenerator {
|
||||||
|
|
||||||
|
|||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
package org.mifosplatform.portfolio.client.domain;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class AccountNumberGeneratorFactory {
|
||||||
|
|
||||||
|
public AccountNumberGenerator determineClientAccountNoGenerator(final Long clientId) {
|
||||||
|
return new ZeroPaddedAccountNumberGenerator(clientId, 9);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccountNumberGenerator determineLoanAccountNoGenerator(final Long loanId) {
|
||||||
|
return new ZeroPaddedAccountNumberGenerator(loanId, 9);
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-2
@@ -29,7 +29,7 @@ import org.springframework.data.jpa.domain.AbstractPersistable;
|
|||||||
@Table(name = "m_client")
|
@Table(name = "m_client")
|
||||||
public class Client extends AbstractPersistable<Long> {
|
public class Client extends AbstractPersistable<Long> {
|
||||||
|
|
||||||
@Column(name = "account_no", length = 40, unique = true, nullable = false)
|
@Column(name = "account_no", length = 20, unique = true, nullable = false)
|
||||||
private String accountNumber;
|
private String accountNumber;
|
||||||
|
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
@@ -148,8 +148,9 @@ public class Client extends AbstractPersistable<Long> {
|
|||||||
this.office = newOffice;
|
this.office = newOffice;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateAccountIdentifier(final String accountIdentifier) {
|
public void updateAccountNo(final String accountIdentifier) {
|
||||||
this.accountNumber = accountIdentifier;
|
this.accountNumber = accountIdentifier;
|
||||||
|
this.accountNumberRequiresAutoGeneration = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Object> update(final JsonCommand command) {
|
public Map<String, Object> update(final JsonCommand command) {
|
||||||
|
|||||||
-21
@@ -1,21 +0,0 @@
|
|||||||
package org.mifosplatform.portfolio.client.domain;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Example {@link AccountNumberGenerator} for clients that takes clients
|
|
||||||
* auto generated database id and zero fills it ensuring the identifier is
|
|
||||||
* always of a given <code>maxLength</code>.
|
|
||||||
*/
|
|
||||||
public class ClientAccountNumberGenerator implements AccountNumberGenerator {
|
|
||||||
|
|
||||||
private final Long clientId;
|
|
||||||
private final int maxLength;
|
|
||||||
|
|
||||||
public ClientAccountNumberGenerator(final Long clientId, int maxLength) {
|
|
||||||
this.clientId = clientId;
|
|
||||||
this.maxLength = maxLength;}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String generate() {
|
|
||||||
return String.format("%0" + maxLength + "d", clientId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
package org.mifosplatform.portfolio.client.domain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example {@link AccountNumberGenerator} for clients that takes an entities
|
||||||
|
* auto generated database id and zero fills it ensuring the identifier is
|
||||||
|
* always of a given <code>maxLength</code>.
|
||||||
|
*/
|
||||||
|
public class ZeroPaddedAccountNumberGenerator implements AccountNumberGenerator {
|
||||||
|
|
||||||
|
private final Long id;
|
||||||
|
private final int maxLength;
|
||||||
|
|
||||||
|
public ZeroPaddedAccountNumberGenerator(final Long id, int maxLength) {
|
||||||
|
this.id = id;
|
||||||
|
this.maxLength = maxLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String generate() {
|
||||||
|
return String.format("%0" + maxLength + "d", id);
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-2
@@ -308,7 +308,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
|
|||||||
|
|
||||||
public String loanAccountSummarySchema() {
|
public String loanAccountSummarySchema() {
|
||||||
|
|
||||||
StringBuilder accountsSummary = new StringBuilder("l.id as id, l.external_id as externalId,");
|
StringBuilder accountsSummary = new StringBuilder("l.id as id, l.account_no as accountNo, l.external_id as externalId,");
|
||||||
accountsSummary.append("l.product_id as productId, lp.name as productName,").append("l.loan_status_id as statusId ")
|
accountsSummary.append("l.product_id as productId, lp.name as productName,").append("l.loan_status_id as statusId ")
|
||||||
.append("from m_loan l ").append("LEFT JOIN m_product_loan AS lp ON lp.id = l.product_id ");
|
.append("from m_loan l ").append("LEFT JOIN m_product_loan AS lp ON lp.id = l.product_id ");
|
||||||
|
|
||||||
@@ -319,13 +319,14 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
|
|||||||
public ClientAccountSummaryData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
public ClientAccountSummaryData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||||
|
|
||||||
final Long id = JdbcSupport.getLong(rs, "id");
|
final Long id = JdbcSupport.getLong(rs, "id");
|
||||||
|
final String accountNo = rs.getString("accountNo");
|
||||||
final String externalId = rs.getString("externalId");
|
final String externalId = rs.getString("externalId");
|
||||||
final Long productId = JdbcSupport.getLong(rs, "productId");
|
final Long productId = JdbcSupport.getLong(rs, "productId");
|
||||||
final String loanProductName = rs.getString("productName");
|
final String loanProductName = rs.getString("productName");
|
||||||
final Integer loanStatusId = JdbcSupport.getInteger(rs, "statusId");
|
final Integer loanStatusId = JdbcSupport.getInteger(rs, "statusId");
|
||||||
final EnumOptionData loanStatus = LoanEnumerations.status(loanStatusId);
|
final EnumOptionData loanStatus = LoanEnumerations.status(loanStatusId);
|
||||||
|
|
||||||
return new ClientAccountSummaryData(id, externalId, productId, loanProductName, loanStatus);
|
return new ClientAccountSummaryData(id, accountNo, externalId, productId, loanProductName, loanStatus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-6
@@ -22,7 +22,7 @@ import org.mifosplatform.organisation.office.domain.OfficeRepository;
|
|||||||
import org.mifosplatform.organisation.office.exception.OfficeNotFoundException;
|
import org.mifosplatform.organisation.office.exception.OfficeNotFoundException;
|
||||||
import org.mifosplatform.portfolio.client.command.ClientIdentifierCommand;
|
import org.mifosplatform.portfolio.client.command.ClientIdentifierCommand;
|
||||||
import org.mifosplatform.portfolio.client.command.ClientNoteCommand;
|
import org.mifosplatform.portfolio.client.command.ClientNoteCommand;
|
||||||
import org.mifosplatform.portfolio.client.domain.AccountIdentifierGeneratorFactory;
|
import org.mifosplatform.portfolio.client.domain.AccountNumberGeneratorFactory;
|
||||||
import org.mifosplatform.portfolio.client.domain.AccountNumberGenerator;
|
import org.mifosplatform.portfolio.client.domain.AccountNumberGenerator;
|
||||||
import org.mifosplatform.portfolio.client.domain.Client;
|
import org.mifosplatform.portfolio.client.domain.Client;
|
||||||
import org.mifosplatform.portfolio.client.domain.ClientIdentifier;
|
import org.mifosplatform.portfolio.client.domain.ClientIdentifier;
|
||||||
@@ -58,7 +58,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
|||||||
private final ClientCommandFromApiJsonDeserializer fromApiJsonDeserializer;
|
private final ClientCommandFromApiJsonDeserializer fromApiJsonDeserializer;
|
||||||
private final ClientNoteCommandFromApiJsonDeserializer clientNoteFromApiJsonDeserializer;
|
private final ClientNoteCommandFromApiJsonDeserializer clientNoteFromApiJsonDeserializer;
|
||||||
private final ClientIdentifierCommandFromApiJsonDeserializer clientIdentifierCommandFromApiJsonDeserializer;
|
private final ClientIdentifierCommandFromApiJsonDeserializer clientIdentifierCommandFromApiJsonDeserializer;
|
||||||
private final AccountIdentifierGeneratorFactory accountIdentifierGeneratorFactory;
|
private final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ClientWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final ClientRepository clientRepository,
|
public ClientWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final ClientRepository clientRepository,
|
||||||
@@ -67,7 +67,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
|||||||
final ClientCommandFromApiJsonDeserializer fromApiJsonDeserializer,
|
final ClientCommandFromApiJsonDeserializer fromApiJsonDeserializer,
|
||||||
final ClientNoteCommandFromApiJsonDeserializer clientNoteFromApiJsonDeserializer,
|
final ClientNoteCommandFromApiJsonDeserializer clientNoteFromApiJsonDeserializer,
|
||||||
final ClientIdentifierCommandFromApiJsonDeserializer clientIdentifierCommandFromApiJsonDeserializer,
|
final ClientIdentifierCommandFromApiJsonDeserializer clientIdentifierCommandFromApiJsonDeserializer,
|
||||||
final AccountIdentifierGeneratorFactory accountIdentifierGeneratorFactory) {
|
final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.clientRepository = clientRepository;
|
this.clientRepository = clientRepository;
|
||||||
this.clientIdentifierRepository = clientIdentifierRepository;
|
this.clientIdentifierRepository = clientIdentifierRepository;
|
||||||
@@ -123,8 +123,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
|||||||
|
|
||||||
this.fromApiJsonDeserializer.validateForCreate(command.json());
|
this.fromApiJsonDeserializer.validateForCreate(command.json());
|
||||||
|
|
||||||
final String officeIdParamName = "officeId";
|
final Long officeId = command.longValueOfParameterNamed("officeId");
|
||||||
final Long officeId = command.longValueOfParameterNamed(officeIdParamName);
|
|
||||||
|
|
||||||
final Office clientOffice = this.officeRepository.findOne(officeId);
|
final Office clientOffice = this.officeRepository.findOne(officeId);
|
||||||
if (clientOffice == null) { throw new OfficeNotFoundException(officeId); }
|
if (clientOffice == null) { throw new OfficeNotFoundException(officeId); }
|
||||||
@@ -135,7 +134,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
|||||||
if (newClient.isAccountNumberRequiresAutoGeneration()) {
|
if (newClient.isAccountNumberRequiresAutoGeneration()) {
|
||||||
final AccountNumberGenerator accountNoGenerator = this.accountIdentifierGeneratorFactory
|
final AccountNumberGenerator accountNoGenerator = this.accountIdentifierGeneratorFactory
|
||||||
.determineClientAccountNoGenerator(newClient.getId());
|
.determineClientAccountNoGenerator(newClient.getId());
|
||||||
newClient.updateAccountIdentifier(accountNoGenerator.generate());
|
newClient.updateAccountNo(accountNoGenerator.generate());
|
||||||
this.clientRepository.save(newClient);
|
this.clientRepository.save(newClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-8
@@ -69,14 +69,14 @@ import com.google.gson.JsonElement;
|
|||||||
@Scope("singleton")
|
@Scope("singleton")
|
||||||
public class LoansApiResource {
|
public class LoansApiResource {
|
||||||
|
|
||||||
private final Set<String> LOAN_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "externalId", "clientId", "groupId",
|
private final Set<String> LOAN_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "accountNo", "externalId", "clientId",
|
||||||
"clientName", "groupName", "fundId", "fundName", "loanProductId", "loanProductName", "loanProductDescription", "currency",
|
"groupId", "clientName", "groupName", "fundId", "fundName", "loanProductId", "loanProductName", "loanProductDescription",
|
||||||
"principal", "inArrearsTolerance", "numberOfRepayments", "repaymentEvery", "interestRatePerPeriod", "annualInterestRate",
|
"currency", "principal", "inArrearsTolerance", "numberOfRepayments", "repaymentEvery", "interestRatePerPeriod",
|
||||||
"repaymentFrequencyType", "interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType",
|
"annualInterestRate", "repaymentFrequencyType", "interestRateFrequencyType", "amortizationType", "interestType",
|
||||||
"submittedOnDate", "approvedOnDate", "expectedDisbursementDate", "actualDisbursementDate", "expectedFirstRepaymentOnDate",
|
"interestCalculationPeriodType", "submittedOnDate", "approvedOnDate", "expectedDisbursementDate", "actualDisbursementDate",
|
||||||
"interestChargedFromDate", "closedOnDate", "expectedMaturityDate", "status", "lifeCycleStatusDate", "repaymentSchedule",
|
"expectedFirstRepaymentOnDate", "interestChargedFromDate", "closedOnDate", "expectedMaturityDate", "status",
|
||||||
"transactions", "permissions", "convenienceData", "charges", "productOptions", "amortizationTypeOptions",
|
"lifeCycleStatusDate", "repaymentSchedule", "transactions", "permissions", "convenienceData", "charges", "productOptions",
|
||||||
"interestTypeOptions", "interestCalculationPeriodTypeOptions", "repaymentFrequencyTypeOptions",
|
"amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions", "repaymentFrequencyTypeOptions",
|
||||||
"interestRateFrequencyTypeOptions", "fundOptions", "repaymentStrategyOptions", "chargeOptions", "loanOfficerId",
|
"interestRateFrequencyTypeOptions", "fundOptions", "repaymentStrategyOptions", "chargeOptions", "loanOfficerId",
|
||||||
"loanOfficerName", "loanOfficerOptions", "chargeTemplate"));
|
"loanOfficerName", "loanOfficerOptions", "chargeTemplate"));
|
||||||
|
|
||||||
|
|||||||
-155
@@ -1,155 +0,0 @@
|
|||||||
package org.mifosplatform.portfolio.loanaccount.command;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.joda.time.LocalDate;
|
|
||||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
|
||||||
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
|
||||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.query.CalculateLoanScheduleQuery;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Immutable command for submitting new loan application.
|
|
||||||
*/
|
|
||||||
public class LoanApplicationCommand {
|
|
||||||
|
|
||||||
private final Long clientId;
|
|
||||||
private final Long groupId;
|
|
||||||
private final Long productId;
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private final String externalId;
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private final Long fundId;
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private final Long loanOfficerId;
|
|
||||||
private final Long transactionProcessingStrategyId;
|
|
||||||
|
|
||||||
private final BigDecimal principal;
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private final BigDecimal inArrearsTolerance;
|
|
||||||
|
|
||||||
private final Integer loanTermFrequency;
|
|
||||||
private final Integer loanTermFrequencyType;
|
|
||||||
|
|
||||||
private final Integer numberOfRepayments;
|
|
||||||
private final Integer repaymentEvery;
|
|
||||||
|
|
||||||
private final BigDecimal interestRatePerPeriod;
|
|
||||||
private final Integer repaymentFrequencyType;
|
|
||||||
private final Integer interestRateFrequencyType;
|
|
||||||
private final Integer amortizationType;
|
|
||||||
private final Integer interestType;
|
|
||||||
private final Integer interestCalculationPeriodType;
|
|
||||||
|
|
||||||
private final LocalDate expectedDisbursementDate;
|
|
||||||
private final LocalDate repaymentsStartingFromDate;
|
|
||||||
private final LocalDate interestChargedFromDate;
|
|
||||||
private final LocalDate submittedOnDate;
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private final String submittedOnNote;
|
|
||||||
|
|
||||||
private final LoanChargeCommand[] charges;
|
|
||||||
|
|
||||||
public LoanApplicationCommand(final Long clientId, final Long groupId, final Long productId, final String externalId,
|
|
||||||
final Long fundId, final Long transactionProcessingStrategyId, final LocalDate submittedOnDate, final String submittedOnNote,
|
|
||||||
final LocalDate expectedDisbursementDate, final LocalDate repaymentsStartingFromDate,
|
|
||||||
final LocalDate interestChargedFromLocalDate, final BigDecimal principal, final BigDecimal interestRatePerPeriod,
|
|
||||||
final Integer interestRateFrequencyMethod, final Integer interestMethod, final Integer interestCalculationPeriodMethod,
|
|
||||||
final Integer repaymentEvery, final Integer repaymentFrequency, final Integer numberOfRepayments, Integer amortizationMethod,
|
|
||||||
final Integer loanTermFrequency, final Integer loanTermFrequencyType, final BigDecimal toleranceAmount,
|
|
||||||
final LoanChargeCommand[] charges, final Long loanOfficerId) {
|
|
||||||
this.clientId = clientId;
|
|
||||||
this.groupId = groupId;
|
|
||||||
this.productId = productId;
|
|
||||||
this.externalId = externalId;
|
|
||||||
this.fundId = fundId;
|
|
||||||
this.loanOfficerId = loanOfficerId;
|
|
||||||
this.transactionProcessingStrategyId = transactionProcessingStrategyId;
|
|
||||||
|
|
||||||
this.submittedOnDate = submittedOnDate;
|
|
||||||
this.submittedOnNote = submittedOnNote;
|
|
||||||
this.expectedDisbursementDate = expectedDisbursementDate;
|
|
||||||
this.repaymentsStartingFromDate = repaymentsStartingFromDate;
|
|
||||||
this.interestChargedFromDate = interestChargedFromLocalDate;
|
|
||||||
|
|
||||||
this.principal = principal;
|
|
||||||
this.loanTermFrequency = loanTermFrequency;
|
|
||||||
this.loanTermFrequencyType = loanTermFrequencyType;
|
|
||||||
this.inArrearsTolerance = toleranceAmount;
|
|
||||||
|
|
||||||
this.interestRatePerPeriod = interestRatePerPeriod;
|
|
||||||
this.interestRateFrequencyType = interestRateFrequencyMethod;
|
|
||||||
this.interestType = interestMethod;
|
|
||||||
this.interestCalculationPeriodType = interestCalculationPeriodMethod;
|
|
||||||
this.repaymentEvery = repaymentEvery;
|
|
||||||
this.repaymentFrequencyType = repaymentFrequency;
|
|
||||||
this.numberOfRepayments = numberOfRepayments;
|
|
||||||
this.amortizationType = amortizationMethod;
|
|
||||||
|
|
||||||
this.charges = charges;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CalculateLoanScheduleQuery toCalculateLoanScheduleCommand() {
|
|
||||||
return new CalculateLoanScheduleQuery(this.productId, this.principal, this.interestRatePerPeriod, this.interestRateFrequencyType,
|
|
||||||
this.interestType, this.interestCalculationPeriodType, this.repaymentEvery, this.repaymentFrequencyType,
|
|
||||||
this.numberOfRepayments, this.amortizationType, this.loanTermFrequency, this.loanTermFrequencyType,
|
|
||||||
this.expectedDisbursementDate, this.repaymentsStartingFromDate, this.interestChargedFromDate, this.charges);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LoanChargeCommand[] getCharges() {
|
|
||||||
return charges;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ApiParameterError> validate() {
|
|
||||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
|
||||||
|
|
||||||
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan");
|
|
||||||
|
|
||||||
if (this.clientId != null) {
|
|
||||||
baseDataValidator.reset().parameter("clientId").value(this.clientId).longGreaterThanZero();
|
|
||||||
}
|
|
||||||
if (this.groupId != null) {
|
|
||||||
baseDataValidator.reset().parameter("groupId").value(this.groupId).longGreaterThanZero();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.clientId == null && this.groupId == null) {
|
|
||||||
baseDataValidator.reset().parameter("clientId").value(this.clientId).notNull().integerGreaterThanZero();
|
|
||||||
}
|
|
||||||
|
|
||||||
baseDataValidator.reset().parameter("productId").value(this.productId).notNull().integerGreaterThanZero();
|
|
||||||
|
|
||||||
if (this.submittedOnDate == null) {
|
|
||||||
ApiParameterError error = ApiParameterError.parameterError("validation.msg.loan.submitted.on.date.cannot.be.blank",
|
|
||||||
"The parameter submittedOnDate cannot be empty.", "submittedOnDate");
|
|
||||||
dataValidationErrors.add(error);
|
|
||||||
} else {
|
|
||||||
if (this.submittedOnDate.isAfter(this.expectedDisbursementDate)) {
|
|
||||||
ApiParameterError error = ApiParameterError.parameterError(
|
|
||||||
"validation.msg.loan.submitted.on.date.cannot.be.after.expectedDisbursementDate",
|
|
||||||
"The date of parameter submittedOnDate cannot fall after the date given for expectedDisbursementDate.",
|
|
||||||
"submittedOnDate", this.submittedOnDate, this.expectedDisbursementDate);
|
|
||||||
dataValidationErrors.add(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.transactionProcessingStrategyId == null) {
|
|
||||||
baseDataValidator.reset().parameter("transactionProcessingStrategyId").value(this.transactionProcessingStrategyId).notNull()
|
|
||||||
.inMinMaxRange(2, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.charges != null) {
|
|
||||||
for (LoanChargeCommand loanChargeCommand : this.charges) {
|
|
||||||
try {
|
|
||||||
loanChargeCommand.validateForCreate();
|
|
||||||
} catch (PlatformApiDataValidationException e) {
|
|
||||||
dataValidationErrors.addAll(e.getErrors());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return dataValidationErrors;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+2
@@ -22,6 +22,7 @@ public class LoanAccountData {
|
|||||||
|
|
||||||
// basic loan details
|
// basic loan details
|
||||||
private final Long id;
|
private final Long id;
|
||||||
|
private final String accountNo;
|
||||||
private final String externalId;
|
private final String externalId;
|
||||||
private final Long clientId;
|
private final Long clientId;
|
||||||
private final String clientName;
|
private final String clientName;
|
||||||
@@ -129,6 +130,7 @@ public class LoanAccountData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.id = basicDetails.getId();
|
this.id = basicDetails.getId();
|
||||||
|
this.accountNo = basicDetails.getAccountNo();
|
||||||
this.externalId = basicDetails.getExternalId();
|
this.externalId = basicDetails.getExternalId();
|
||||||
this.clientId = basicDetails.getClientId();
|
this.clientId = basicDetails.getClientId();
|
||||||
this.clientName = basicDetails.getClientName();
|
this.clientName = basicDetails.getClientName();
|
||||||
|
|||||||
+12
-4
@@ -20,6 +20,7 @@ import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
|
|||||||
public class LoanBasicDetailsData {
|
public class LoanBasicDetailsData {
|
||||||
|
|
||||||
private final Long id;
|
private final Long id;
|
||||||
|
private final String accountNo;
|
||||||
private final String externalId;
|
private final String externalId;
|
||||||
private final Long clientId;
|
private final Long clientId;
|
||||||
private final Long clientOfficeId;
|
private final Long clientOfficeId;
|
||||||
@@ -105,6 +106,7 @@ public class LoanBasicDetailsData {
|
|||||||
final EnumOptionData interestCalculationPeriodType, final LocalDate expectedDisbursementDate,
|
final EnumOptionData interestCalculationPeriodType, final LocalDate expectedDisbursementDate,
|
||||||
final Collection<LoanChargeData> charges) {
|
final Collection<LoanChargeData> charges) {
|
||||||
this.id = null;
|
this.id = null;
|
||||||
|
this.accountNo = null;
|
||||||
this.externalId = null;
|
this.externalId = null;
|
||||||
this.clientId = clientId;
|
this.clientId = clientId;
|
||||||
this.clientName = clientName;
|
this.clientName = clientName;
|
||||||
@@ -163,6 +165,7 @@ public class LoanBasicDetailsData {
|
|||||||
private LoanBasicDetailsData(final Long clientId, final String clientName, final Long clientOfficeId, final Long groupId,
|
private LoanBasicDetailsData(final Long clientId, final String clientName, final Long clientOfficeId, final Long groupId,
|
||||||
final String groupName, final Long groupOfficeId, final LocalDate expectedDisbursementDate) {
|
final String groupName, final Long groupOfficeId, final LocalDate expectedDisbursementDate) {
|
||||||
this.id = null;
|
this.id = null;
|
||||||
|
this.accountNo = null;
|
||||||
this.externalId = null;
|
this.externalId = null;
|
||||||
this.clientId = clientId;
|
this.clientId = clientId;
|
||||||
this.clientName = clientName;
|
this.clientName = clientName;
|
||||||
@@ -210,10 +213,10 @@ public class LoanBasicDetailsData {
|
|||||||
this.totalDisbursementCharges = BigDecimal.ZERO;
|
this.totalDisbursementCharges = BigDecimal.ZERO;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoanBasicDetailsData(final Long id, final String externalId, final Long clientId, final String clientName,
|
public LoanBasicDetailsData(final Long id, final String accountNo, final String externalId, final Long clientId,
|
||||||
final Long clientOfficeId, final Long groupId, final String groupName, final Long groupOfficeId, final Long loanProductId,
|
final String clientName, final Long clientOfficeId, final Long groupId, final String groupName, final Long groupOfficeId,
|
||||||
final String loanProductName, final String loanProductDescription, final Long fundId, String fundName,
|
final Long loanProductId, final String loanProductName, final String loanProductDescription, final Long fundId,
|
||||||
final LocalDate closedOnDate, final LocalDate submittedOnDate, final LocalDate approvedOnDate,
|
String fundName, final LocalDate closedOnDate, final LocalDate submittedOnDate, final LocalDate approvedOnDate,
|
||||||
final LocalDate expectedDisbursementDate, final LocalDate actualDisbursementDate, final LocalDate expectedMaturityDate,
|
final LocalDate expectedDisbursementDate, final LocalDate actualDisbursementDate, final LocalDate expectedMaturityDate,
|
||||||
final LocalDate repaymentsStartingFromDate, final LocalDate interestChargedFromDate, final CurrencyData currency,
|
final LocalDate repaymentsStartingFromDate, final LocalDate interestChargedFromDate, final CurrencyData currency,
|
||||||
final BigDecimal principal, final BigDecimal inArrearsTolerance, final Integer numberOfRepayments,
|
final BigDecimal principal, final BigDecimal inArrearsTolerance, final Integer numberOfRepayments,
|
||||||
@@ -224,6 +227,7 @@ public class LoanBasicDetailsData {
|
|||||||
final EnumOptionData termPeriodFrequencyType, final Integer transactionStrategyId, final Collection<LoanChargeData> charges,
|
final EnumOptionData termPeriodFrequencyType, final Integer transactionStrategyId, final Collection<LoanChargeData> charges,
|
||||||
final Long loanOfficerId, String loanOfficerName, final BigDecimal totalDisbursementCharges) {
|
final Long loanOfficerId, String loanOfficerName, final BigDecimal totalDisbursementCharges) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
this.accountNo = accountNo;
|
||||||
this.externalId = externalId;
|
this.externalId = externalId;
|
||||||
this.clientId = clientId;
|
this.clientId = clientId;
|
||||||
this.clientName = clientName;
|
this.clientName = clientName;
|
||||||
@@ -349,6 +353,10 @@ public class LoanBasicDetailsData {
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getAccountNo() {
|
||||||
|
return this.accountNo;
|
||||||
|
}
|
||||||
|
|
||||||
public String getExternalId() {
|
public String getExternalId() {
|
||||||
return externalId;
|
return externalId;
|
||||||
}
|
}
|
||||||
|
|||||||
+96
-46
@@ -35,6 +35,7 @@ import org.joda.time.format.DateTimeFormat;
|
|||||||
import org.joda.time.format.DateTimeFormatter;
|
import org.joda.time.format.DateTimeFormatter;
|
||||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||||
import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom;
|
import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom;
|
||||||
|
import org.mifosplatform.infrastructure.security.service.RandomPasswordGenerator;
|
||||||
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;
|
||||||
@@ -64,9 +65,17 @@ import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations;
|
|||||||
import org.mifosplatform.useradministration.domain.AppUser;
|
import org.mifosplatform.useradministration.domain.AppUser;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "m_loan", uniqueConstraints = @UniqueConstraint(columnNames = { "external_id" }))
|
@Table(name = "m_loan", uniqueConstraints = {
|
||||||
|
@UniqueConstraint(columnNames = { "account_no" }, name = "loan_account_no_UNIQUE"),
|
||||||
|
@UniqueConstraint(columnNames = { "external_id" }, name = "loan_externalid_UNIQUE") })
|
||||||
public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||||
|
|
||||||
|
@Column(name = "account_no", length = 20, unique = true, nullable = false)
|
||||||
|
private String accountNumber;
|
||||||
|
|
||||||
|
@Column(name = "external_id")
|
||||||
|
private String externalId;
|
||||||
|
|
||||||
@ManyToOne(optional = true)
|
@ManyToOne(optional = true)
|
||||||
@JoinColumn(name = "client_id")
|
@JoinColumn(name = "client_id")
|
||||||
private Client client;
|
private Client client;
|
||||||
@@ -95,9 +104,6 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
@JoinColumn(name = "loan_transaction_strategy_id", nullable = true)
|
@JoinColumn(name = "loan_transaction_strategy_id", nullable = true)
|
||||||
private LoanTransactionProcessingStrategy transactionProcessingStrategy;
|
private LoanTransactionProcessingStrategy transactionProcessingStrategy;
|
||||||
|
|
||||||
@Column(name = "external_id")
|
|
||||||
private String externalId;
|
|
||||||
|
|
||||||
@Embedded
|
@Embedded
|
||||||
private LoanProductRelatedDetail loanRepaymentScheduleDetail;
|
private LoanProductRelatedDetail loanRepaymentScheduleDetail;
|
||||||
|
|
||||||
@@ -187,59 +193,54 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
@Column(name = "total_charges_due_at_disbursement_derived", scale = 6, precision = 19)
|
@Column(name = "total_charges_due_at_disbursement_derived", scale = 6, precision = 19)
|
||||||
private BigDecimal totalChargesDueAtDisbursement;
|
private BigDecimal totalChargesDueAtDisbursement;
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
private boolean accountNumberRequiresAutoGeneration = false;
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
private final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessor = new LoanRepaymentScheduleTransactionProcessorFactory();
|
private final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessor = new LoanRepaymentScheduleTransactionProcessorFactory();
|
||||||
|
|
||||||
@Deprecated
|
public static Loan newIndividualLoanApplication(final String accountNo, final Client client, final LoanProduct loanProduct,
|
||||||
public static Loan createNew(final Fund fund, final Staff loanOfficer,
|
|
||||||
final LoanTransactionProcessingStrategy transactionProcessingStrategy, final LoanProduct loanProduct, final Client client,
|
|
||||||
final LoanProductRelatedDetail loanRepaymentScheduleDetail, final Set<LoanCharge> loanCharges) {
|
|
||||||
return new Loan(client, null, fund, loanOfficer, transactionProcessingStrategy, loanProduct, loanRepaymentScheduleDetail, null,
|
|
||||||
loanCharges);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public static Loan createNew(final Fund fund, final Staff loanOfficer,
|
|
||||||
final LoanTransactionProcessingStrategy transactionProcessingStrategy, final LoanProduct loanProduct, final Group group,
|
|
||||||
final LoanProductRelatedDetail loanRepaymentScheduleDetail, final Set<LoanCharge> loanCharges) {
|
|
||||||
return new Loan(null, group, fund, loanOfficer, transactionProcessingStrategy, loanProduct, loanRepaymentScheduleDetail, null,
|
|
||||||
loanCharges);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Loan newIndividualLoanApplication(final Client client, final LoanProduct loanProduct, final Fund fund,
|
|
||||||
final Staff officer, final LoanTransactionProcessingStrategy transactionProcessingStrategy, final LoanSchedule loanSchedule,
|
|
||||||
final Set<LoanCharge> loanCharges) {
|
|
||||||
final LoanStatus status = null;
|
|
||||||
LoanProductRelatedDetail loanRepaymentScheduleDetail = loanSchedule.loanProductRelatedDetail();
|
|
||||||
return new Loan(client, null, fund, officer, transactionProcessingStrategy, loanProduct, loanRepaymentScheduleDetail, status,
|
|
||||||
loanCharges);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Loan newGroupLoanApplication(final Group group, final LoanProduct loanProduct, final Fund fund, final Staff officer,
|
|
||||||
final LoanTransactionProcessingStrategy transactionProcessingStrategy, final LoanSchedule loanSchedule,
|
|
||||||
final Set<LoanCharge> loanCharges) {
|
|
||||||
final LoanStatus status = null;
|
|
||||||
LoanProductRelatedDetail loanRepaymentScheduleDetail = loanSchedule.loanProductRelatedDetail();
|
|
||||||
return new Loan(null, group, fund, officer, transactionProcessingStrategy, loanProduct, loanRepaymentScheduleDetail, status,
|
|
||||||
loanCharges);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Loan newIndividualLoanApplicationFromGroup(final Client client, final Group group, final LoanProduct loanProduct,
|
|
||||||
final Fund fund, final Staff officer, final LoanTransactionProcessingStrategy transactionProcessingStrategy,
|
final Fund fund, final Staff officer, final LoanTransactionProcessingStrategy transactionProcessingStrategy,
|
||||||
final LoanSchedule loanSchedule, final Set<LoanCharge> loanCharges) {
|
final LoanSchedule loanSchedule, final Set<LoanCharge> loanCharges) {
|
||||||
final LoanStatus status = null;
|
final LoanStatus status = null;
|
||||||
LoanProductRelatedDetail loanRepaymentScheduleDetail = loanSchedule.loanProductRelatedDetail();
|
LoanProductRelatedDetail loanRepaymentScheduleDetail = loanSchedule.loanProductRelatedDetail();
|
||||||
return new Loan(client, group, fund, officer, transactionProcessingStrategy, loanProduct, loanRepaymentScheduleDetail, status,
|
return new Loan(accountNo, client, null, fund, officer, transactionProcessingStrategy, loanProduct, loanRepaymentScheduleDetail,
|
||||||
loanCharges);
|
status, loanCharges);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Loan newGroupLoanApplication(final String accountNo, final Group group, final LoanProduct loanProduct, final Fund fund,
|
||||||
|
final Staff officer, final LoanTransactionProcessingStrategy transactionProcessingStrategy, final LoanSchedule loanSchedule,
|
||||||
|
final Set<LoanCharge> loanCharges) {
|
||||||
|
final LoanStatus status = null;
|
||||||
|
LoanProductRelatedDetail loanRepaymentScheduleDetail = loanSchedule.loanProductRelatedDetail();
|
||||||
|
return new Loan(accountNo, null, group, fund, officer, transactionProcessingStrategy, loanProduct, loanRepaymentScheduleDetail,
|
||||||
|
status, loanCharges);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Loan newIndividualLoanApplicationFromGroup(final String accountNo, final Client client, final Group group,
|
||||||
|
final LoanProduct loanProduct, final Fund fund, final Staff officer,
|
||||||
|
final LoanTransactionProcessingStrategy transactionProcessingStrategy, final LoanSchedule loanSchedule,
|
||||||
|
final Set<LoanCharge> loanCharges) {
|
||||||
|
final LoanStatus status = null;
|
||||||
|
LoanProductRelatedDetail loanRepaymentScheduleDetail = loanSchedule.loanProductRelatedDetail();
|
||||||
|
return new Loan(accountNo, client, group, fund, officer, transactionProcessingStrategy, loanProduct, loanRepaymentScheduleDetail,
|
||||||
|
status, loanCharges);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Loan() {
|
protected Loan() {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
private Loan(final Client client, final Group group, Fund fund, Staff loanOfficer,
|
private Loan(final String accountNo, final Client client, final Group group, Fund fund, Staff loanOfficer,
|
||||||
final LoanTransactionProcessingStrategy transactionProcessingStrategy, final LoanProduct loanProduct,
|
final LoanTransactionProcessingStrategy transactionProcessingStrategy, final LoanProduct loanProduct,
|
||||||
final LoanProductRelatedDetail loanRepaymentScheduleDetail, final LoanStatus loanStatus, final Set<LoanCharge> loanCharges) {
|
final LoanProductRelatedDetail loanRepaymentScheduleDetail, final LoanStatus loanStatus, final Set<LoanCharge> loanCharges) {
|
||||||
|
|
||||||
|
if (StringUtils.isBlank(accountNo)) {
|
||||||
|
this.accountNumber = new RandomPasswordGenerator(19).generate();
|
||||||
|
this.accountNumberRequiresAutoGeneration = true;
|
||||||
|
} else {
|
||||||
|
this.accountNumber = accountNo;
|
||||||
|
}
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.group = group;
|
this.group = group;
|
||||||
this.fund = fund;
|
this.fund = fund;
|
||||||
@@ -285,6 +286,14 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
this.totalChargesDueAtDisbursement = deriveSumTotalOfChargesDueAtDisbursement();
|
this.totalChargesDueAtDisbursement = deriveSumTotalOfChargesDueAtDisbursement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isAccountNumberRequiresAutoGeneration() {
|
||||||
|
return this.accountNumberRequiresAutoGeneration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAccountNumberRequiresAutoGeneration(boolean accountNumberRequiresAutoGeneration) {
|
||||||
|
this.accountNumberRequiresAutoGeneration = accountNumberRequiresAutoGeneration;
|
||||||
|
}
|
||||||
|
|
||||||
public void addLoanCharge(final LoanCharge loanCharge) {
|
public void addLoanCharge(final LoanCharge loanCharge) {
|
||||||
|
|
||||||
validateLoanIsNotClosed(loanCharge);
|
validateLoanIsNotClosed(loanCharge);
|
||||||
@@ -545,7 +554,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
this.expectedMaturityDate = determineExpectedMaturityDate().toDate();
|
this.expectedMaturityDate = determineExpectedMaturityDate().toDate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Object> modifyLoanApplication(final JsonCommand command, final LoanChargeCommand[] loanChargeCommands,
|
public Map<String, Object> loanApplicationModification(final JsonCommand command, final LoanChargeCommand[] loanChargeCommands,
|
||||||
final AprCalculator aprCalculator) {
|
final AprCalculator aprCalculator) {
|
||||||
|
|
||||||
final Map<String, Object> actualChanges = this.loanRepaymentScheduleDetail.updateLoanApplicationAttributes(command, aprCalculator);
|
final Map<String, Object> actualChanges = this.loanRepaymentScheduleDetail.updateLoanApplicationAttributes(command, aprCalculator);
|
||||||
@@ -557,6 +566,13 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
final String dateFormatAsInput = command.dateFormat();
|
final String dateFormatAsInput = command.dateFormat();
|
||||||
final String localeAsInput = command.locale();
|
final String localeAsInput = command.locale();
|
||||||
|
|
||||||
|
final String accountNoParamName = "accountNo";
|
||||||
|
if (command.isChangeInStringParameterNamed(accountNoParamName, this.accountNumber)) {
|
||||||
|
final String newValue = command.stringValueOfParameterNamed(accountNoParamName);
|
||||||
|
actualChanges.put(accountNoParamName, newValue);
|
||||||
|
this.accountNumber = StringUtils.defaultIfEmpty(newValue, null);
|
||||||
|
}
|
||||||
|
|
||||||
final String externalIdParamName = "externalId";
|
final String externalIdParamName = "externalId";
|
||||||
if (command.isChangeInStringParameterNamed(externalIdParamName, this.externalId)) {
|
if (command.isChangeInStringParameterNamed(externalIdParamName, this.externalId)) {
|
||||||
final String newValue = command.stringValueOfParameterNamed(externalIdParamName);
|
final String newValue = command.stringValueOfParameterNamed(externalIdParamName);
|
||||||
@@ -659,6 +675,35 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (getSubmittedOnDate().isAfter(new LocalDate())) {
|
||||||
|
final String errorMessage = "The date on which a loan is submitted cannot be in the future.";
|
||||||
|
throw new InvalidLoanStateTransitionException("submittal", "cannot.be.a.future.date", errorMessage, getSubmittedOnDate());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getSubmittedOnDate().isAfter(getExpectedDisbursedOnLocalDate())) {
|
||||||
|
final String errorMessage = "The date on which a loan is submitted cannot be after its expected disbursement date: "
|
||||||
|
+ getExpectedDisbursedOnLocalDate().toString();
|
||||||
|
throw new InvalidLoanStateTransitionException("submittal", "cannot.be.after.expected.disbursement.date", errorMessage,
|
||||||
|
getSubmittedOnDate(), getExpectedDisbursedOnLocalDate());
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME - this constraint doesnt really need to be here. should be
|
||||||
|
// possible to express loan term as say 12 months whilst also saying
|
||||||
|
// - that the repayment structure is 6 repayments every bi-monthly.
|
||||||
|
// validateSelectedPeriodFrequencyTypeIsTheSame(dataValidationErrors, loanTermFrequency, loanTermFrequencyType, numberOfRepayments,
|
||||||
|
// repaymentEvery, repaymentEveryType);
|
||||||
|
//
|
||||||
|
// validateRepaymentsStartingFromDateIsAfterDisbursementDate(dataValidationErrors, expectedDisbursementDate,
|
||||||
|
// repaymentsStartingFromDate);
|
||||||
|
//
|
||||||
|
// validateRepaymentsStartingFromDateAndInterestChargedFromDate(dataValidationErrors, expectedDisbursementDate,
|
||||||
|
// repaymentsStartingFromDate, interestChargedFromDate);
|
||||||
|
|
||||||
|
// charges are optional
|
||||||
|
for (LoanCharge loanCharge : getNullPointerSafeLoanCharges()) {
|
||||||
|
validateChargeHasValidSpecifiedDateIfApplicable(loanCharge, getDisbursementDate(), getLastRepaymentPeriodDueDate());
|
||||||
|
}
|
||||||
|
|
||||||
return actualChanges;
|
return actualChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -715,6 +760,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
LoanStatus statusEnum = lifecycleStateMachine.transition(LoanEvent.LOAN_CREATED, from);
|
LoanStatus statusEnum = lifecycleStateMachine.transition(LoanEvent.LOAN_CREATED, from);
|
||||||
this.loanStatus = statusEnum.getValue();
|
this.loanStatus = statusEnum.getValue();
|
||||||
|
|
||||||
|
this.externalId = externalId;
|
||||||
|
|
||||||
this.termFrequency = loanSchedule.getLoanTermFrequency();
|
this.termFrequency = loanSchedule.getLoanTermFrequency();
|
||||||
this.termPeriodFrequencyType = loanSchedule.getLoanTermPeriodFrequencyType().getValue();
|
this.termPeriodFrequencyType = loanSchedule.getLoanTermPeriodFrequencyType().getValue();
|
||||||
|
|
||||||
@@ -749,8 +796,6 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
for (LoanCharge loanCharge : getNullPointerSafeLoanCharges()) {
|
for (LoanCharge loanCharge : getNullPointerSafeLoanCharges()) {
|
||||||
validateChargeHasValidSpecifiedDateIfApplicable(loanCharge, getDisbursementDate(), getLastRepaymentPeriodDueDate());
|
validateChargeHasValidSpecifiedDateIfApplicable(loanCharge, getDisbursementDate(), getLastRepaymentPeriodDueDate());
|
||||||
}
|
}
|
||||||
|
|
||||||
this.externalId = externalId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private LocalDate determineExpectedMaturityDate() {
|
private LocalDate determineExpectedMaturityDate() {
|
||||||
@@ -1946,8 +1991,13 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
if (this.client != null) {
|
if (this.client != null) {
|
||||||
officeId = this.client.getOffice().getId();
|
officeId = this.client.getOffice().getId();
|
||||||
} else {
|
} else {
|
||||||
// officeId = this.group.getOffice().getId();
|
// officeId = this.group.getOffice().getId();
|
||||||
}
|
}
|
||||||
return officeId;
|
return officeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateAccountNo(final String newAccountNo) {
|
||||||
|
this.accountNumber = newAccountNo;
|
||||||
|
this.accountNumberRequiresAutoGeneration=false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -22,6 +22,6 @@ public class LoanApplicationModificationCommandHandler implements NewCommandSour
|
|||||||
@Override
|
@Override
|
||||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||||
|
|
||||||
return this.writePlatformService.modifyLoanApplication(command.entityId(), command);
|
return this.writePlatformService.modifyLoanApplication(command.getLoanId(), command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
-205
@@ -1,205 +0,0 @@
|
|||||||
package org.mifosplatform.portfolio.loanaccount.loanschedule.query;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.joda.time.LocalDate;
|
|
||||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
|
||||||
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
|
||||||
import org.mifosplatform.portfolio.loanaccount.command.LoanChargeCommand;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Immutable query used when auto-calculating loan schedules based on loan
|
|
||||||
* terms.
|
|
||||||
*/
|
|
||||||
public class CalculateLoanScheduleQuery {
|
|
||||||
|
|
||||||
private final Long productId;
|
|
||||||
private final BigDecimal principal;
|
|
||||||
private final Integer loanTermFrequency;
|
|
||||||
private final Integer loanTermFrequencyType;
|
|
||||||
private final Integer repaymentEvery;
|
|
||||||
private final Integer repaymentFrequencyType;
|
|
||||||
private final Integer numberOfRepayments;
|
|
||||||
private final BigDecimal interestRatePerPeriod;
|
|
||||||
private final Integer interestRateFrequencyType;
|
|
||||||
private final Integer amortizationType;
|
|
||||||
private final Integer interestType;
|
|
||||||
private final Integer interestCalculationPeriodType;
|
|
||||||
private final LocalDate expectedDisbursementDate;
|
|
||||||
private final LocalDate repaymentsStartingFromDate;
|
|
||||||
private final LocalDate interestChargedFromDate;
|
|
||||||
private final LoanChargeCommand[] charges;
|
|
||||||
|
|
||||||
public CalculateLoanScheduleQuery(final Long productId, final BigDecimal principal, final BigDecimal interestRatePerPeriod,
|
|
||||||
Integer interestRateFrequencyMethod, final Integer interestMethod, final Integer interestCalculationPeriodMethod,
|
|
||||||
final Integer repaymentEvery, final Integer repaymentFrequency, final Integer numberOfRepayments, Integer amortizationMethod,
|
|
||||||
final Integer loanTermFrequency, final Integer loanTermFrequencyType, final LocalDate expectedDisbursementDate,
|
|
||||||
final LocalDate repaymentsStartingFromDate, final LocalDate interestCalculatedFromDate, final LoanChargeCommand[] charges) {
|
|
||||||
|
|
||||||
this.productId = productId;
|
|
||||||
this.principal = principal;
|
|
||||||
this.interestRatePerPeriod = interestRatePerPeriod;
|
|
||||||
this.interestRateFrequencyType = interestRateFrequencyMethod;
|
|
||||||
this.interestType = interestMethod;
|
|
||||||
this.interestCalculationPeriodType = interestCalculationPeriodMethod;
|
|
||||||
this.repaymentEvery = repaymentEvery;
|
|
||||||
this.repaymentFrequencyType = repaymentFrequency;
|
|
||||||
this.numberOfRepayments = numberOfRepayments;
|
|
||||||
this.amortizationType = amortizationMethod;
|
|
||||||
this.loanTermFrequency = loanTermFrequency;
|
|
||||||
this.loanTermFrequencyType = loanTermFrequencyType;
|
|
||||||
|
|
||||||
this.expectedDisbursementDate = expectedDisbursementDate;
|
|
||||||
this.repaymentsStartingFromDate = repaymentsStartingFromDate;
|
|
||||||
this.interestChargedFromDate = interestCalculatedFromDate;
|
|
||||||
this.charges = charges;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getProductId() {
|
|
||||||
return productId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigDecimal getPrincipal() {
|
|
||||||
return principal;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getLoanTermFrequency() {
|
|
||||||
return loanTermFrequency;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getLoanTermFrequencyType() {
|
|
||||||
return loanTermFrequencyType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getRepaymentEvery() {
|
|
||||||
return repaymentEvery;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getRepaymentFrequencyType() {
|
|
||||||
return repaymentFrequencyType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getNumberOfRepayments() {
|
|
||||||
return numberOfRepayments;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigDecimal getInterestRatePerPeriod() {
|
|
||||||
return interestRatePerPeriod;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getInterestRateFrequencyType() {
|
|
||||||
return interestRateFrequencyType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getAmortizationType() {
|
|
||||||
return amortizationType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getInterestType() {
|
|
||||||
return interestType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getInterestCalculationPeriodType() {
|
|
||||||
return interestCalculationPeriodType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LocalDate getExpectedDisbursementDate() {
|
|
||||||
return expectedDisbursementDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LocalDate getRepaymentsStartingFromDate() {
|
|
||||||
return repaymentsStartingFromDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LocalDate getInterestChargedFromDate() {
|
|
||||||
return interestChargedFromDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LoanChargeCommand[] getCharges() {
|
|
||||||
return charges;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ApiParameterError> validate() {
|
|
||||||
|
|
||||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
|
||||||
|
|
||||||
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan");
|
|
||||||
|
|
||||||
baseDataValidator.reset().parameter("principal").value(this.principal).notNull().positiveAmount();
|
|
||||||
|
|
||||||
baseDataValidator.reset().parameter("loanTermFrequency").value(this.loanTermFrequency).notNull().integerGreaterThanZero();
|
|
||||||
baseDataValidator.reset().parameter("loanTermFrequencyType").value(this.loanTermFrequencyType).notNull().inMinMaxRange(0, 4);
|
|
||||||
|
|
||||||
baseDataValidator.reset().parameter("numberOfRepayments").value(this.numberOfRepayments).notNull().integerGreaterThanZero();
|
|
||||||
baseDataValidator.reset().parameter("repaymentEvery").value(this.repaymentEvery).notNull().integerGreaterThanZero();
|
|
||||||
baseDataValidator.reset().parameter("repaymentFrequencyType").value(this.repaymentFrequencyType).notNull().inMinMaxRange(0, 3);
|
|
||||||
|
|
||||||
// FIXME - this constraint doesnt really need to be here. should be
|
|
||||||
// possible to express loan term as say 12 months whilst also saying
|
|
||||||
// - that the repayment structure is 6 repayments every bi-monthly.
|
|
||||||
if (this.loanTermFrequencyType != null && !this.loanTermFrequencyType.equals(this.repaymentFrequencyType)) {
|
|
||||||
ApiParameterError error = ApiParameterError.parameterError(
|
|
||||||
"validation.msg.loan.loanTermFrequencyType.not.the.same.as.repaymentFrequencyType",
|
|
||||||
"The parameters loanTermFrequencyType and repaymentFrequencyType must be the same.", "loanTermFrequencyType",
|
|
||||||
this.loanTermFrequencyType, this.repaymentFrequencyType);
|
|
||||||
dataValidationErrors.add(error);
|
|
||||||
} else {
|
|
||||||
if (this.loanTermFrequency != null && this.repaymentEvery != null && this.numberOfRepayments != null) {
|
|
||||||
int suggestsedLoanTerm = this.repaymentEvery * this.numberOfRepayments;
|
|
||||||
if (this.loanTermFrequency.intValue() < suggestsedLoanTerm) {
|
|
||||||
ApiParameterError error = ApiParameterError
|
|
||||||
.parameterError(
|
|
||||||
"validation.msg.loan.loanTermFrequency.less.than.repayment.structure.suggests",
|
|
||||||
"The parameter loanTermFrequency is less than the suggest loan term as indicated by numberOfRepayments and repaymentEvery.",
|
|
||||||
"loanTermFrequency", this.loanTermFrequency, this.numberOfRepayments, this.repaymentEvery);
|
|
||||||
dataValidationErrors.add(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
baseDataValidator.reset().parameter("interestRatePerPeriod").value(this.interestRatePerPeriod).notNull();
|
|
||||||
baseDataValidator.reset().parameter("interestRateFrequencyType").value(this.interestRateFrequencyType).notNull()
|
|
||||||
.inMinMaxRange(0, 3);
|
|
||||||
baseDataValidator.reset().parameter("amortizationType").value(this.amortizationType).notNull().inMinMaxRange(0, 1);
|
|
||||||
baseDataValidator.reset().parameter("interestType").value(this.interestType).notNull().inMinMaxRange(0, 1);
|
|
||||||
baseDataValidator.reset().parameter("interestCalculationPeriodType").value(this.interestCalculationPeriodType).notNull()
|
|
||||||
.inMinMaxRange(0, 1);
|
|
||||||
|
|
||||||
baseDataValidator.reset().parameter("expectedDisbursementDate").value(this.expectedDisbursementDate).notNull();
|
|
||||||
|
|
||||||
if (this.expectedDisbursementDate != null) {
|
|
||||||
if (this.repaymentsStartingFromDate != null && this.expectedDisbursementDate.isAfter(this.repaymentsStartingFromDate)) {
|
|
||||||
ApiParameterError error = ApiParameterError.parameterError(
|
|
||||||
"validation.msg.loan.expectedDisbursementDate.cannot.be.after.first.repayment.date",
|
|
||||||
"The parameter expectedDisbursementDate has a date which falls after the given first repayment date.",
|
|
||||||
"expectedDisbursementDate", this.expectedDisbursementDate, this.repaymentsStartingFromDate);
|
|
||||||
dataValidationErrors.add(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.repaymentsStartingFromDate != null && this.interestChargedFromDate == null) {
|
|
||||||
|
|
||||||
ApiParameterError error = ApiParameterError.parameterError(
|
|
||||||
"validation.msg.loan.interestCalculatedFromDate.must.be.entered.when.using.repayments.startfrom.field",
|
|
||||||
"The parameter interestCalculatedFromDate cannot be empty when first repayment date is provided.",
|
|
||||||
"interestChargedFromDate", this.repaymentsStartingFromDate);
|
|
||||||
dataValidationErrors.add(error);
|
|
||||||
} else if (this.repaymentsStartingFromDate == null && this.interestChargedFromDate != null) {
|
|
||||||
|
|
||||||
// validate interestCalculatedFromDate is after or on
|
|
||||||
// repaymentsStartingFromDate
|
|
||||||
if (this.expectedDisbursementDate.isAfter(this.interestChargedFromDate)) {
|
|
||||||
ApiParameterError error = ApiParameterError.parameterError(
|
|
||||||
"validation.msg.loan.interestChargedFromDate.cannot.be.before.disbursement.date",
|
|
||||||
"The parameter interestCalculatedFromDate cannot be before the date given for expected disbursement.",
|
|
||||||
"interestChargedFromDate", this.interestChargedFromDate, this.expectedDisbursementDate);
|
|
||||||
dataValidationErrors.add(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return dataValidationErrors;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+4
-14
@@ -1,15 +1,10 @@
|
|||||||
package org.mifosplatform.portfolio.loanaccount.loanschedule.service;
|
package org.mifosplatform.portfolio.loanaccount.loanschedule.service;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.mifosplatform.infrastructure.core.api.JsonQuery;
|
import org.mifosplatform.infrastructure.core.api.JsonQuery;
|
||||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
|
||||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
|
||||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanSchedule;
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanSchedule;
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.query.CalculateLoanScheduleQuery;
|
import org.mifosplatform.portfolio.loanaccount.serialization.CalculateLoanScheduleQueryFromApiJsonHelper;
|
||||||
import org.mifosplatform.portfolio.loanaccount.serialization.CalculateLoanScheduleQueryFromApiJsonDeserializer;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@@ -17,12 +12,12 @@ import org.springframework.stereotype.Service;
|
|||||||
public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleCalculationPlatformService {
|
public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleCalculationPlatformService {
|
||||||
|
|
||||||
private final PlatformSecurityContext context;
|
private final PlatformSecurityContext context;
|
||||||
private final CalculateLoanScheduleQueryFromApiJsonDeserializer fromApiJsonDeserializer;
|
private final CalculateLoanScheduleQueryFromApiJsonHelper fromApiJsonDeserializer;
|
||||||
private final LoanScheduleAssembler loanScheduleAssembler;
|
private final LoanScheduleAssembler loanScheduleAssembler;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LoanScheduleCalculationPlatformServiceImpl(final PlatformSecurityContext context,
|
public LoanScheduleCalculationPlatformServiceImpl(final PlatformSecurityContext context,
|
||||||
final CalculateLoanScheduleQueryFromApiJsonDeserializer fromApiJsonDeserializer,
|
final CalculateLoanScheduleQueryFromApiJsonHelper fromApiJsonDeserializer,
|
||||||
final LoanScheduleAssembler loanScheduleAssembler) {
|
final LoanScheduleAssembler loanScheduleAssembler) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
||||||
@@ -33,12 +28,7 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
|
|||||||
public LoanScheduleData calculateLoanSchedule(final JsonQuery query) {
|
public LoanScheduleData calculateLoanSchedule(final JsonQuery query) {
|
||||||
context.authenticatedUser();
|
context.authenticatedUser();
|
||||||
|
|
||||||
final CalculateLoanScheduleQuery calculateLoanScheduleQuery = this.fromApiJsonDeserializer.commandFromApiJson(query.json());
|
this.fromApiJsonDeserializer.validate(query.json());
|
||||||
final List<ApiParameterError> dataValidationErrors = calculateLoanScheduleQuery.validate();
|
|
||||||
|
|
||||||
if (!dataValidationErrors.isEmpty()) {
|
|
||||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors);
|
|
||||||
}
|
|
||||||
|
|
||||||
final LoanSchedule loanSchedule = this.loanScheduleAssembler.fromJson(query.parsedJson());
|
final LoanSchedule loanSchedule = this.loanScheduleAssembler.fromJson(query.parsedJson());
|
||||||
return loanSchedule.generate();
|
return loanSchedule.generate();
|
||||||
|
|||||||
-113
@@ -1,113 +0,0 @@
|
|||||||
package org.mifosplatform.portfolio.loanaccount.serialization;
|
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
|
||||||
import org.joda.time.LocalDate;
|
|
||||||
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
|
|
||||||
import org.mifosplatform.infrastructure.core.serialization.AbstractFromApiJsonDeserializer;
|
|
||||||
import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer;
|
|
||||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
|
||||||
import org.mifosplatform.portfolio.loanaccount.command.LoanChargeCommand;
|
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.query.CalculateLoanScheduleQuery;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import com.google.gson.JsonArray;
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.gson.reflect.TypeToken;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of {@link FromApiJsonDeserializer} for
|
|
||||||
* {@link CalculateLoanScheduleQuery}'s.
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public final class CalculateLoanScheduleQueryFromApiJsonDeserializer extends AbstractFromApiJsonDeserializer<CalculateLoanScheduleQuery> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The parameters supported for this command.
|
|
||||||
*/
|
|
||||||
final Set<String> supportedParameters = new HashSet<String>(Arrays.asList("clientId", "groupId", "productId", "externalId", "fundId",
|
|
||||||
"transactionProcessingStrategyId", "principal", "inArrearsTolerance", "interestRatePerPeriod", "repaymentEvery",
|
|
||||||
"numberOfRepayments", "loanTermFrequency", "loanTermFrequencyType", "charges", "repaymentFrequencyType",
|
|
||||||
"interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType", "expectedDisbursementDate",
|
|
||||||
"repaymentsStartingFromDate", "interestChargedFromDate", "submittedOnDate", "submittedOnNote", "locale", "dateFormat",
|
|
||||||
"loanOfficerId", "id"));
|
|
||||||
|
|
||||||
private final FromJsonHelper fromApiJsonHelper;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public CalculateLoanScheduleQueryFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) {
|
|
||||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CalculateLoanScheduleQuery commandFromApiJson(final String json) {
|
|
||||||
|
|
||||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
|
||||||
|
|
||||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
|
||||||
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters);
|
|
||||||
|
|
||||||
final JsonElement element = fromApiJsonHelper.parse(json);
|
|
||||||
final Long productId = fromApiJsonHelper.extractLongNamed("productId", element);
|
|
||||||
final BigDecimal principal = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("principal", element);
|
|
||||||
final BigDecimal interestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRatePerPeriod", element);
|
|
||||||
final Integer interestRateFrequencyType = fromApiJsonHelper.extractIntegerWithLocaleNamed("interestRateFrequencyType", element);
|
|
||||||
final Integer interestType = fromApiJsonHelper.extractIntegerWithLocaleNamed("interestType", element);
|
|
||||||
final Integer interestCalculationPeriodType = fromApiJsonHelper.extractIntegerWithLocaleNamed("interestCalculationPeriodType",
|
|
||||||
element);
|
|
||||||
|
|
||||||
final Integer repaymentEvery = fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentEvery", element);
|
|
||||||
final Integer repaymentFrequencyType = fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentFrequencyType", element);
|
|
||||||
final Integer numberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed("numberOfRepayments", element);
|
|
||||||
final Integer amortizationType = fromApiJsonHelper.extractIntegerWithLocaleNamed("amortizationType", element);
|
|
||||||
final Integer loanTermFrequency = fromApiJsonHelper.extractIntegerWithLocaleNamed("loanTermFrequency", element);
|
|
||||||
final Integer loanTermFrequencyType = fromApiJsonHelper.extractIntegerWithLocaleNamed("loanTermFrequencyType", element);
|
|
||||||
final LocalDate expectedDisbursementDate = fromApiJsonHelper.extractLocalDateNamed("expectedDisbursementDate", element);
|
|
||||||
final LocalDate repaymentsStartingFromDate = fromApiJsonHelper.extractLocalDateNamed("repaymentsStartingFromDate", element);
|
|
||||||
final LocalDate interestChargedFromDate = fromApiJsonHelper.extractLocalDateNamed("interestChargedFromDate", element);
|
|
||||||
|
|
||||||
// ///
|
|
||||||
LoanChargeCommand[] charges = null;
|
|
||||||
if (element.isJsonObject()) {
|
|
||||||
final JsonObject topLevelJsonElement = element.getAsJsonObject();
|
|
||||||
final String dateFormat = fromApiJsonHelper.extractDateFormatParameter(topLevelJsonElement);
|
|
||||||
final Locale locale = fromApiJsonHelper.extractLocaleParameter(topLevelJsonElement);
|
|
||||||
if (topLevelJsonElement.has("charges") && topLevelJsonElement.get("charges").isJsonArray()) {
|
|
||||||
|
|
||||||
final JsonArray array = topLevelJsonElement.get("charges").getAsJsonArray();
|
|
||||||
charges = new LoanChargeCommand[array.size()];
|
|
||||||
for (int i = 0; i < array.size(); i++) {
|
|
||||||
|
|
||||||
final JsonObject loanChargeElement = array.get(i).getAsJsonObject();
|
|
||||||
|
|
||||||
// final Long id = fromApiJsonHelper.extractLongNamed("id",
|
|
||||||
// loanChargeElement);
|
|
||||||
final Long chargeId = fromApiJsonHelper.extractLongNamed("chargeId", loanChargeElement);
|
|
||||||
final BigDecimal amount = fromApiJsonHelper.extractBigDecimalNamed("amount", loanChargeElement, locale);
|
|
||||||
final Integer chargeTimeType = fromApiJsonHelper.extractIntegerNamed("chargeTimeType", loanChargeElement, locale);
|
|
||||||
final Integer chargeCalculationType = fromApiJsonHelper.extractIntegerNamed("chargeCalculationType", loanChargeElement,
|
|
||||||
locale);
|
|
||||||
final LocalDate specifiedDueDate = fromApiJsonHelper.extractLocalDateNamed("specifiedDueDate", loanChargeElement,
|
|
||||||
dateFormat, locale);
|
|
||||||
|
|
||||||
charges[i] = new LoanChargeCommand(chargeId, amount, chargeTimeType, chargeCalculationType, specifiedDueDate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// /
|
|
||||||
|
|
||||||
return new CalculateLoanScheduleQuery(productId, principal, interestRatePerPeriod, interestRateFrequencyType, interestType,
|
|
||||||
interestCalculationPeriodType, repaymentEvery, repaymentFrequencyType, numberOfRepayments, amortizationType,
|
|
||||||
loanTermFrequency, loanTermFrequencyType, expectedDisbursementDate, repaymentsStartingFromDate, interestChargedFromDate,
|
|
||||||
charges);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+244
@@ -0,0 +1,244 @@
|
|||||||
|
package org.mifosplatform.portfolio.loanaccount.serialization;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.joda.time.LocalDate;
|
||||||
|
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||||
|
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||||
|
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
|
||||||
|
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||||
|
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.command.LoanChargeCommand;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public final class CalculateLoanScheduleQueryFromApiJsonHelper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The parameters supported for this command.
|
||||||
|
*/
|
||||||
|
final Set<String> supportedParameters = new HashSet<String>(Arrays.asList("clientId", "groupId", "productId", "accountNo",
|
||||||
|
"externalId", "fundId", "transactionProcessingStrategyId", "principal", "inArrearsTolerance", "interestRatePerPeriod",
|
||||||
|
"repaymentEvery", "numberOfRepayments", "loanTermFrequency", "loanTermFrequencyType", "charges", "repaymentFrequencyType",
|
||||||
|
"interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType", "expectedDisbursementDate",
|
||||||
|
"repaymentsStartingFromDate", "interestChargedFromDate", "submittedOnDate", "submittedOnNote", "locale", "dateFormat",
|
||||||
|
"loanOfficerId", "id"));
|
||||||
|
|
||||||
|
private final FromJsonHelper fromApiJsonHelper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public CalculateLoanScheduleQueryFromApiJsonHelper(final FromJsonHelper fromApiJsonHelper) {
|
||||||
|
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validate(final String json) {
|
||||||
|
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||||
|
|
||||||
|
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||||
|
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters);
|
||||||
|
|
||||||
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||||
|
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan");
|
||||||
|
|
||||||
|
final JsonElement element = fromApiJsonHelper.parse(json);
|
||||||
|
|
||||||
|
final Long productId = fromApiJsonHelper.extractLongNamed("productId", element);
|
||||||
|
baseDataValidator.reset().parameter("productId").value(productId).notNull().integerGreaterThanZero();
|
||||||
|
|
||||||
|
final BigDecimal principal = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("principal", element);
|
||||||
|
baseDataValidator.reset().parameter("principal").value(principal).notNull().positiveAmount();
|
||||||
|
|
||||||
|
final String loanTermFrequencyParameterName = "loanTermFrequency";
|
||||||
|
final Integer loanTermFrequency = fromApiJsonHelper.extractIntegerWithLocaleNamed(loanTermFrequencyParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(loanTermFrequencyParameterName).value(loanTermFrequency).notNull().integerGreaterThanZero();
|
||||||
|
|
||||||
|
final String loanTermFrequencyTypeParameterName = "loanTermFrequencyType";
|
||||||
|
final Integer loanTermFrequencyType = fromApiJsonHelper.extractIntegerWithLocaleNamed(loanTermFrequencyTypeParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(loanTermFrequencyTypeParameterName).value(loanTermFrequencyType).notNull().inMinMaxRange(0, 3);
|
||||||
|
|
||||||
|
final String numberOfRepaymentsParameterName = "numberOfRepayments";
|
||||||
|
final Integer numberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed(numberOfRepaymentsParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(numberOfRepaymentsParameterName).value(numberOfRepayments).notNull().integerGreaterThanZero();
|
||||||
|
|
||||||
|
final String repaymentEveryParameterName = "repaymentEvery";
|
||||||
|
final Integer repaymentEvery = fromApiJsonHelper.extractIntegerWithLocaleNamed(repaymentEveryParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(repaymentEveryParameterName).value(repaymentEvery).notNull().integerGreaterThanZero();
|
||||||
|
|
||||||
|
final String repaymentEveryFrequencyTypeParameterName = "repaymentFrequencyType";
|
||||||
|
final Integer repaymentEveryType = fromApiJsonHelper.extractIntegerWithLocaleNamed(repaymentEveryFrequencyTypeParameterName,
|
||||||
|
element);
|
||||||
|
baseDataValidator.reset().parameter(repaymentEveryFrequencyTypeParameterName).value(repaymentEveryType).notNull()
|
||||||
|
.inMinMaxRange(0, 3);
|
||||||
|
|
||||||
|
// FIXME - this constraint doesnt really need to be here. should be
|
||||||
|
// possible to express loan term as say 12 months whilst also saying
|
||||||
|
// - that the repayment structure is 6 repayments every bi-monthly.
|
||||||
|
validateSelectedPeriodFrequencyTypeIsTheSame(dataValidationErrors, loanTermFrequency, loanTermFrequencyType, numberOfRepayments,
|
||||||
|
repaymentEvery, repaymentEveryType);
|
||||||
|
|
||||||
|
final String interestRatePerPeriodParameterName = "interestRatePerPeriod";
|
||||||
|
final BigDecimal interestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(interestRatePerPeriodParameterName,
|
||||||
|
element);
|
||||||
|
baseDataValidator.reset().parameter(interestRatePerPeriodParameterName).value(interestRatePerPeriod).notNull().positiveAmount();
|
||||||
|
|
||||||
|
final String interestRateFrequencyTypeParameterName = "interestRateFrequencyType";
|
||||||
|
final Integer interestRateFrequencyType = fromApiJsonHelper.extractIntegerWithLocaleNamed(interestRateFrequencyTypeParameterName,
|
||||||
|
element);
|
||||||
|
baseDataValidator.reset().parameter(interestRateFrequencyTypeParameterName).value(interestRateFrequencyType).notNull()
|
||||||
|
.inMinMaxRange(0, 3);
|
||||||
|
|
||||||
|
final String interestTypeParameterName = "interestType";
|
||||||
|
final Integer interestType = fromApiJsonHelper.extractIntegerWithLocaleNamed(interestTypeParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(interestTypeParameterName).value(interestType).notNull().inMinMaxRange(0, 1);
|
||||||
|
|
||||||
|
final String interestCalculationPeriodTypeParameterName = "interestCalculationPeriodType";
|
||||||
|
final Integer interestCalculationPeriodType = fromApiJsonHelper.extractIntegerWithLocaleNamed(
|
||||||
|
interestCalculationPeriodTypeParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(interestCalculationPeriodTypeParameterName).value(interestCalculationPeriodType).notNull()
|
||||||
|
.inMinMaxRange(0, 1);
|
||||||
|
|
||||||
|
final String amortizationTypeParameterName = "amortizationType";
|
||||||
|
final Integer amortizationType = fromApiJsonHelper.extractIntegerWithLocaleNamed(amortizationTypeParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(amortizationTypeParameterName).value(amortizationType).notNull().inMinMaxRange(0, 1);
|
||||||
|
|
||||||
|
final String expectedDisbursementDateParameterName = "expectedDisbursementDate";
|
||||||
|
final LocalDate expectedDisbursementDate = fromApiJsonHelper.extractLocalDateNamed(expectedDisbursementDateParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(expectedDisbursementDateParameterName).value(expectedDisbursementDate).notNull();
|
||||||
|
|
||||||
|
LocalDate repaymentsStartingFromDate = null;
|
||||||
|
final String repaymentsStartingFromDateParameterName = "repaymentsStartingFromDate";
|
||||||
|
if (fromApiJsonHelper.parameterExists(repaymentsStartingFromDateParameterName, element)) {
|
||||||
|
repaymentsStartingFromDate = fromApiJsonHelper.extractLocalDateNamed(repaymentsStartingFromDateParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(repaymentsStartingFromDateParameterName).value(repaymentsStartingFromDate).ignoreIfNull().notNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalDate interestChargedFromDate = null;
|
||||||
|
final String interestChargedFromDateParameterName = "interestChargedFromDate";
|
||||||
|
if (fromApiJsonHelper.parameterExists(interestChargedFromDateParameterName, element)) {
|
||||||
|
interestChargedFromDate = fromApiJsonHelper.extractLocalDateNamed(interestChargedFromDateParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(interestChargedFromDateParameterName).value(interestChargedFromDate).ignoreIfNull().notNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
validateRepaymentsStartingFromDateIsAfterDisbursementDate(dataValidationErrors, expectedDisbursementDate,
|
||||||
|
repaymentsStartingFromDate);
|
||||||
|
|
||||||
|
validateRepaymentsStartingFromDateAndInterestChargedFromDate(dataValidationErrors, expectedDisbursementDate,
|
||||||
|
repaymentsStartingFromDate, interestChargedFromDate);
|
||||||
|
|
||||||
|
final LoanChargeCommand[] charges = extractInToLoanChargeCommands(element);
|
||||||
|
if (charges != null) {
|
||||||
|
for (LoanChargeCommand loanChargeCommand : charges) {
|
||||||
|
try {
|
||||||
|
loanChargeCommand.validateForCreate();
|
||||||
|
} catch (PlatformApiDataValidationException e) {
|
||||||
|
dataValidationErrors.addAll(e.getErrors());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
|
||||||
|
"Validation errors exist.", dataValidationErrors); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateSelectedPeriodFrequencyTypeIsTheSame(final List<ApiParameterError> dataValidationErrors,
|
||||||
|
final Integer loanTermFrequency, final Integer loanTermFrequencyType, final Integer numberOfRepayments,
|
||||||
|
final Integer repaymentEvery, final Integer repaymentEveryType) {
|
||||||
|
if (loanTermFrequencyType != null && !loanTermFrequencyType.equals(repaymentEveryType)) {
|
||||||
|
ApiParameterError error = ApiParameterError.parameterError(
|
||||||
|
"validation.msg.loan.loanTermFrequencyType.not.the.same.as.repaymentFrequencyType",
|
||||||
|
"The parameters loanTermFrequencyType and repaymentFrequencyType must be the same.", "loanTermFrequencyType",
|
||||||
|
loanTermFrequencyType, repaymentEveryType);
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
} else {
|
||||||
|
if (loanTermFrequency != null && repaymentEvery != null && numberOfRepayments != null) {
|
||||||
|
int suggestsedLoanTerm = repaymentEvery * numberOfRepayments;
|
||||||
|
if (loanTermFrequency.intValue() < suggestsedLoanTerm) {
|
||||||
|
ApiParameterError error = ApiParameterError
|
||||||
|
.parameterError(
|
||||||
|
"validation.msg.loan.loanTermFrequency.less.than.repayment.structure.suggests",
|
||||||
|
"The parameter loanTermFrequency is less than the suggest loan term as indicated by numberOfRepayments and repaymentEvery.",
|
||||||
|
"loanTermFrequency", loanTermFrequency, numberOfRepayments, repaymentEvery);
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateRepaymentsStartingFromDateAndInterestChargedFromDate(final List<ApiParameterError> dataValidationErrors,
|
||||||
|
final LocalDate expectedDisbursementDate, LocalDate repaymentsStartingFromDate, LocalDate interestChargedFromDate) {
|
||||||
|
if (repaymentsStartingFromDate != null && interestChargedFromDate == null) {
|
||||||
|
|
||||||
|
ApiParameterError error = ApiParameterError.parameterError(
|
||||||
|
"validation.msg.loan.interestChargedFromDate.must.be.entered.when.using.repayments.startfrom.field",
|
||||||
|
"The parameter interestChargedFromDate cannot be empty when repaymentsStartingFromDate is provided.",
|
||||||
|
"interestChargedFromDate", repaymentsStartingFromDate);
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
} else if (repaymentsStartingFromDate == null && interestChargedFromDate != null) {
|
||||||
|
|
||||||
|
if (expectedDisbursementDate != null && expectedDisbursementDate.isAfter(interestChargedFromDate)) {
|
||||||
|
ApiParameterError error = ApiParameterError.parameterError(
|
||||||
|
"validation.msg.loan.interestChargedFromDate.cannot.be.before.disbursement.date",
|
||||||
|
"The parameter interestChargedFromDate cannot be before the date given for expectedDisbursementDate.",
|
||||||
|
"interestChargedFromDate", interestChargedFromDate, expectedDisbursementDate);
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateRepaymentsStartingFromDateIsAfterDisbursementDate(final List<ApiParameterError> dataValidationErrors,
|
||||||
|
final LocalDate expectedDisbursementDate, LocalDate repaymentsStartingFromDate) {
|
||||||
|
if (expectedDisbursementDate != null) {
|
||||||
|
if (repaymentsStartingFromDate != null && expectedDisbursementDate.isAfter(repaymentsStartingFromDate)) {
|
||||||
|
ApiParameterError error = ApiParameterError.parameterError(
|
||||||
|
"validation.msg.loan.expectedDisbursementDate.cannot.be.after.first.repayment.date",
|
||||||
|
"The parameter expectedDisbursementDate has a date which falls after the date for repaymentsStartingFromDate.",
|
||||||
|
"expectedDisbursementDate", expectedDisbursementDate, repaymentsStartingFromDate);
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoanChargeCommand[] extractInToLoanChargeCommands(final JsonElement element) {
|
||||||
|
LoanChargeCommand[] charges = null;
|
||||||
|
if (element.isJsonObject()) {
|
||||||
|
final JsonObject topLevelJsonElement = element.getAsJsonObject();
|
||||||
|
final String dateFormat = fromApiJsonHelper.extractDateFormatParameter(topLevelJsonElement);
|
||||||
|
final Locale locale = fromApiJsonHelper.extractLocaleParameter(topLevelJsonElement);
|
||||||
|
if (topLevelJsonElement.has("charges") && topLevelJsonElement.get("charges").isJsonArray()) {
|
||||||
|
|
||||||
|
final JsonArray array = topLevelJsonElement.get("charges").getAsJsonArray();
|
||||||
|
charges = new LoanChargeCommand[array.size()];
|
||||||
|
for (int i = 0; i < array.size(); i++) {
|
||||||
|
|
||||||
|
final JsonObject loanChargeElement = array.get(i).getAsJsonObject();
|
||||||
|
|
||||||
|
final Long chargeId = fromApiJsonHelper.extractLongNamed("chargeId", loanChargeElement);
|
||||||
|
final BigDecimal amount = fromApiJsonHelper.extractBigDecimalNamed("amount", loanChargeElement, locale);
|
||||||
|
final Integer chargeTimeType = fromApiJsonHelper.extractIntegerNamed("chargeTimeType", loanChargeElement, locale);
|
||||||
|
final Integer chargeCalculationType = fromApiJsonHelper.extractIntegerNamed("chargeCalculationType", loanChargeElement,
|
||||||
|
locale);
|
||||||
|
final LocalDate specifiedDueDate = fromApiJsonHelper.extractLocalDateNamed("specifiedDueDate", loanChargeElement,
|
||||||
|
dateFormat, locale);
|
||||||
|
|
||||||
|
charges[i] = new LoanChargeCommand(chargeId, amount, chargeTimeType, chargeCalculationType, specifiedDueDate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return charges;
|
||||||
|
}
|
||||||
|
}
|
||||||
-141
@@ -1,141 +0,0 @@
|
|||||||
package org.mifosplatform.portfolio.loanaccount.serialization;
|
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
|
||||||
import org.joda.time.LocalDate;
|
|
||||||
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
|
|
||||||
import org.mifosplatform.infrastructure.core.serialization.AbstractFromApiJsonDeserializer;
|
|
||||||
import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer;
|
|
||||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
|
||||||
import org.mifosplatform.portfolio.loanaccount.command.LoanApplicationCommand;
|
|
||||||
import org.mifosplatform.portfolio.loanaccount.command.LoanChargeCommand;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import com.google.gson.JsonArray;
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.gson.reflect.TypeToken;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of {@link FromApiJsonDeserializer} for
|
|
||||||
* {@link LoanApplicationCommand}'s.
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public final class LoanApplicationCommandFromApiJsonDeserializer extends AbstractFromApiJsonDeserializer<LoanApplicationCommand> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The parameters supported for this command.
|
|
||||||
*/
|
|
||||||
final Set<String> supportedParameters = new HashSet<String>(Arrays.asList("clientId", "groupId", "productId", "externalId", "fundId",
|
|
||||||
"transactionProcessingStrategyId", "principal", "inArrearsTolerance", "interestRatePerPeriod", "repaymentEvery",
|
|
||||||
"numberOfRepayments", "loanTermFrequency", "loanTermFrequencyType", "charges", "repaymentFrequencyType",
|
|
||||||
"interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType", "expectedDisbursementDate",
|
|
||||||
"repaymentsStartingFromDate", "interestChargedFromDate", "submittedOnDate", "submittedOnNote", "locale", "dateFormat",
|
|
||||||
"loanOfficerId", "id"));
|
|
||||||
|
|
||||||
private final FromJsonHelper fromApiJsonHelper;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public LoanApplicationCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) {
|
|
||||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public LoanApplicationCommand commandFromApiJson(final String json) {
|
|
||||||
|
|
||||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
|
||||||
|
|
||||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
|
||||||
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters);
|
|
||||||
|
|
||||||
final JsonElement element = fromApiJsonHelper.parse(json);
|
|
||||||
final Long clientId = fromApiJsonHelper.extractLongNamed("clientId", element);
|
|
||||||
final Long groupId = fromApiJsonHelper.extractLongNamed("groupId", element);
|
|
||||||
final Long productId = fromApiJsonHelper.extractLongNamed("productId", element);
|
|
||||||
final String externalId = fromApiJsonHelper.extractStringNamed("externalId", element);
|
|
||||||
final Long fundId = fromApiJsonHelper.extractLongNamed("fundId", element);
|
|
||||||
final Long loanOfficerId = fromApiJsonHelper.extractLongNamed("loanOfficerId", element);
|
|
||||||
final Long transactionProcessingStrategyId = fromApiJsonHelper.extractLongNamed("transactionProcessingStrategyId", element);
|
|
||||||
|
|
||||||
final LocalDate submittedOnDate = fromApiJsonHelper.extractLocalDateNamed("submittedOnDate", element);
|
|
||||||
final String submittedOnNote = fromApiJsonHelper.extractStringNamed("submittedOnNote", element);
|
|
||||||
|
|
||||||
final BigDecimal principal = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("principal", element);
|
|
||||||
final BigDecimal interestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRatePerPeriod", element);
|
|
||||||
final Integer interestRateFrequencyType = fromApiJsonHelper.extractIntegerWithLocaleNamed("interestRateFrequencyType", element);
|
|
||||||
final Integer interestType = fromApiJsonHelper.extractIntegerWithLocaleNamed("interestType", element);
|
|
||||||
final Integer interestCalculationPeriodType = fromApiJsonHelper.extractIntegerWithLocaleNamed("interestCalculationPeriodType",
|
|
||||||
element);
|
|
||||||
|
|
||||||
// final InterestMethod interestMethod =
|
|
||||||
// InterestMethod.fromInt(interestType);
|
|
||||||
// final PeriodFrequencyType interestRatePeriodFrequencyType =
|
|
||||||
// PeriodFrequencyType.fromInt(interestRateFrequencyType);
|
|
||||||
// final InterestCalculationPeriodMethod interestCalculationPeriodMethod
|
|
||||||
// = InterestCalculationPeriodMethod
|
|
||||||
// .fromInt(interestCalculationPeriodType);
|
|
||||||
|
|
||||||
final Integer amortizationType = fromApiJsonHelper.extractIntegerWithLocaleNamed("amortizationType", element);
|
|
||||||
final Integer repaymentEvery = fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentEvery", element);
|
|
||||||
final Integer repaymentFrequencyType = fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentFrequencyType", element);
|
|
||||||
final Integer numberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed("numberOfRepayments", element);
|
|
||||||
// final PeriodFrequencyType repaymentPeriodFrequencyType =
|
|
||||||
// PeriodFrequencyType.fromInt(repaymentFrequencyType);
|
|
||||||
// final AmortizationMethod amortizationMethod =
|
|
||||||
// AmortizationMethod.fromInt(amortizationType);
|
|
||||||
|
|
||||||
final Integer loanTermFrequency = fromApiJsonHelper.extractIntegerWithLocaleNamed("loanTermFrequency", element);
|
|
||||||
final Integer loanTermFrequencyType = fromApiJsonHelper.extractIntegerWithLocaleNamed("loanTermFrequencyType", element);
|
|
||||||
// final PeriodFrequencyType loanTermPeriodFrequencyType =
|
|
||||||
// PeriodFrequencyType.fromInt(loanTermFrequencyType);
|
|
||||||
|
|
||||||
final LocalDate expectedDisbursementDate = fromApiJsonHelper.extractLocalDateNamed("expectedDisbursementDate", element);
|
|
||||||
final LocalDate repaymentsStartingFromDate = fromApiJsonHelper.extractLocalDateNamed("repaymentsStartingFromDate", element);
|
|
||||||
final LocalDate interestChargedFromDate = fromApiJsonHelper.extractLocalDateNamed("interestChargedFromDate", element);
|
|
||||||
|
|
||||||
final BigDecimal inArrearsTolerance = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("inArrearsTolerance", element);
|
|
||||||
|
|
||||||
// ///
|
|
||||||
LoanChargeCommand[] charges = null;
|
|
||||||
if (element.isJsonObject()) {
|
|
||||||
final JsonObject topLevelJsonElement = element.getAsJsonObject();
|
|
||||||
final String dateFormat = fromApiJsonHelper.extractDateFormatParameter(topLevelJsonElement);
|
|
||||||
final Locale locale = fromApiJsonHelper.extractLocaleParameter(topLevelJsonElement);
|
|
||||||
if (topLevelJsonElement.has("charges") && topLevelJsonElement.get("charges").isJsonArray()) {
|
|
||||||
|
|
||||||
final JsonArray array = topLevelJsonElement.get("charges").getAsJsonArray();
|
|
||||||
charges = new LoanChargeCommand[array.size()];
|
|
||||||
for (int i = 0; i < array.size(); i++) {
|
|
||||||
|
|
||||||
final JsonObject loanChargeElement = array.get(i).getAsJsonObject();
|
|
||||||
|
|
||||||
// final Long id = fromApiJsonHelper.extractLongNamed("id",
|
|
||||||
// loanChargeElement);
|
|
||||||
final Long chargeId = fromApiJsonHelper.extractLongNamed("chargeId", loanChargeElement);
|
|
||||||
final BigDecimal amount = fromApiJsonHelper.extractBigDecimalNamed("amount", loanChargeElement, locale);
|
|
||||||
final Integer chargeTimeType = fromApiJsonHelper.extractIntegerNamed("chargeTimeType", loanChargeElement, locale);
|
|
||||||
final Integer chargeCalculationType = fromApiJsonHelper.extractIntegerNamed("chargeCalculationType", loanChargeElement,
|
|
||||||
locale);
|
|
||||||
final LocalDate specifiedDueDate = fromApiJsonHelper.extractLocalDateNamed("specifiedDueDate", loanChargeElement,
|
|
||||||
dateFormat, locale);
|
|
||||||
|
|
||||||
charges[i] = new LoanChargeCommand(chargeId, amount, chargeTimeType, chargeCalculationType, specifiedDueDate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new LoanApplicationCommand(clientId, groupId, productId, externalId, fundId, transactionProcessingStrategyId,
|
|
||||||
submittedOnDate, submittedOnNote, expectedDisbursementDate, repaymentsStartingFromDate, interestChargedFromDate, principal,
|
|
||||||
interestRatePerPeriod, interestRateFrequencyType, interestType, interestCalculationPeriodType, repaymentEvery,
|
|
||||||
repaymentFrequencyType, numberOfRepayments, amortizationType, loanTermFrequency, loanTermFrequencyType, inArrearsTolerance,
|
|
||||||
charges, loanOfficerId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+457
@@ -0,0 +1,457 @@
|
|||||||
|
package org.mifosplatform.portfolio.loanaccount.serialization;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.joda.time.LocalDate;
|
||||||
|
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||||
|
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||||
|
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
|
||||||
|
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||||
|
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.command.LoanChargeCommand;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public final class LoanApplicationCommandFromApiJsonHelper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The parameters supported for this command.
|
||||||
|
*/
|
||||||
|
final Set<String> supportedParameters = new HashSet<String>(Arrays.asList("id", "clientId", "groupId", "productId", "accountNo",
|
||||||
|
"externalId", "fundId", "loanOfficerId", "transactionProcessingStrategyId", "principal", "inArrearsTolerance",
|
||||||
|
"repaymentEvery", "numberOfRepayments", "loanTermFrequency", "loanTermFrequencyType", "charges", "repaymentFrequencyType",
|
||||||
|
"interestRatePerPeriod", "interestRateFrequencyType", "interestType", "interestCalculationPeriodType", "amortizationType",
|
||||||
|
"expectedDisbursementDate", "repaymentsStartingFromDate", "interestChargedFromDate", "submittedOnDate", "submittedOnNote",
|
||||||
|
"locale", "dateFormat"));
|
||||||
|
|
||||||
|
private final FromJsonHelper fromApiJsonHelper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public LoanApplicationCommandFromApiJsonHelper(final FromJsonHelper fromApiJsonHelper) {
|
||||||
|
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validateForCreate(final String json) {
|
||||||
|
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||||
|
|
||||||
|
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||||
|
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters);
|
||||||
|
|
||||||
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||||
|
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan");
|
||||||
|
|
||||||
|
final JsonElement element = fromApiJsonHelper.parse(json);
|
||||||
|
final Long clientId = fromApiJsonHelper.extractLongNamed("clientId", element);
|
||||||
|
if (clientId != null) {
|
||||||
|
baseDataValidator.reset().parameter("clientId").value(clientId).longGreaterThanZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
final Long groupId = fromApiJsonHelper.extractLongNamed("groupId", element);
|
||||||
|
if (groupId != null) {
|
||||||
|
baseDataValidator.reset().parameter("groupId").value(groupId).longGreaterThanZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clientId == null && groupId == null) {
|
||||||
|
baseDataValidator.reset().parameter("clientId").value(clientId).notNull().integerGreaterThanZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
final Long productId = fromApiJsonHelper.extractLongNamed("productId", element);
|
||||||
|
baseDataValidator.reset().parameter("productId").value(productId).notNull().integerGreaterThanZero();
|
||||||
|
|
||||||
|
final String accountNoParameterName = "accountNo";
|
||||||
|
if (fromApiJsonHelper.parameterExists(accountNoParameterName, element)) {
|
||||||
|
final String accountNo = fromApiJsonHelper.extractStringNamed(accountNoParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(accountNoParameterName).value(accountNo).ignoreIfNull().notExceedingLengthOf(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String externalIdParameterName = "externalId";
|
||||||
|
if (fromApiJsonHelper.parameterExists(externalIdParameterName, element)) {
|
||||||
|
final String externalId = fromApiJsonHelper.extractStringNamed(externalIdParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(externalIdParameterName).value(externalId).ignoreIfNull().notExceedingLengthOf(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String fundIdParameterName = "fundId";
|
||||||
|
if (fromApiJsonHelper.parameterExists(fundIdParameterName, element)) {
|
||||||
|
final Long fundId = fromApiJsonHelper.extractLongNamed(fundIdParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(fundIdParameterName).value(fundId).ignoreIfNull().integerGreaterThanZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String loanOfficerIdParameterName = "loanOfficerId";
|
||||||
|
if (fromApiJsonHelper.parameterExists(loanOfficerIdParameterName, element)) {
|
||||||
|
final Long loanOfficerId = fromApiJsonHelper.extractLongNamed(loanOfficerIdParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(loanOfficerIdParameterName).value(loanOfficerId).ignoreIfNull().integerGreaterThanZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
final BigDecimal principal = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("principal", element);
|
||||||
|
baseDataValidator.reset().parameter("principal").value(principal).notNull().positiveAmount();
|
||||||
|
|
||||||
|
final String loanTermFrequencyParameterName = "loanTermFrequency";
|
||||||
|
final Integer loanTermFrequency = fromApiJsonHelper.extractIntegerWithLocaleNamed(loanTermFrequencyParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(loanTermFrequencyParameterName).value(loanTermFrequency).notNull().integerGreaterThanZero();
|
||||||
|
|
||||||
|
final String loanTermFrequencyTypeParameterName = "loanTermFrequencyType";
|
||||||
|
final Integer loanTermFrequencyType = fromApiJsonHelper.extractIntegerWithLocaleNamed(loanTermFrequencyTypeParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(loanTermFrequencyTypeParameterName).value(loanTermFrequencyType).notNull().inMinMaxRange(0, 3);
|
||||||
|
|
||||||
|
final String numberOfRepaymentsParameterName = "numberOfRepayments";
|
||||||
|
final Integer numberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed(numberOfRepaymentsParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(numberOfRepaymentsParameterName).value(numberOfRepayments).notNull().integerGreaterThanZero();
|
||||||
|
|
||||||
|
final String repaymentEveryParameterName = "repaymentEvery";
|
||||||
|
final Integer repaymentEvery = fromApiJsonHelper.extractIntegerWithLocaleNamed(repaymentEveryParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(repaymentEveryParameterName).value(repaymentEvery).notNull().integerGreaterThanZero();
|
||||||
|
|
||||||
|
final String repaymentEveryFrequencyTypeParameterName = "repaymentFrequencyType";
|
||||||
|
final Integer repaymentEveryType = fromApiJsonHelper.extractIntegerWithLocaleNamed(repaymentEveryFrequencyTypeParameterName,
|
||||||
|
element);
|
||||||
|
baseDataValidator.reset().parameter(repaymentEveryFrequencyTypeParameterName).value(repaymentEveryType).notNull()
|
||||||
|
.inMinMaxRange(0, 3);
|
||||||
|
|
||||||
|
final String interestRatePerPeriodParameterName = "interestRatePerPeriod";
|
||||||
|
final BigDecimal interestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(interestRatePerPeriodParameterName,
|
||||||
|
element);
|
||||||
|
baseDataValidator.reset().parameter(interestRatePerPeriodParameterName).value(interestRatePerPeriod).notNull().positiveAmount();
|
||||||
|
|
||||||
|
final String interestRateFrequencyTypeParameterName = "interestRateFrequencyType";
|
||||||
|
final Integer interestRateFrequencyType = fromApiJsonHelper.extractIntegerWithLocaleNamed(interestRateFrequencyTypeParameterName,
|
||||||
|
element);
|
||||||
|
baseDataValidator.reset().parameter(interestRateFrequencyTypeParameterName).value(interestRateFrequencyType).notNull()
|
||||||
|
.inMinMaxRange(0, 3);
|
||||||
|
|
||||||
|
final String interestTypeParameterName = "interestType";
|
||||||
|
final Integer interestType = fromApiJsonHelper.extractIntegerWithLocaleNamed(interestTypeParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(interestTypeParameterName).value(interestType).notNull().inMinMaxRange(0, 1);
|
||||||
|
|
||||||
|
final String interestCalculationPeriodTypeParameterName = "interestCalculationPeriodType";
|
||||||
|
final Integer interestCalculationPeriodType = fromApiJsonHelper.extractIntegerWithLocaleNamed(
|
||||||
|
interestCalculationPeriodTypeParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(interestCalculationPeriodTypeParameterName).value(interestCalculationPeriodType).notNull()
|
||||||
|
.inMinMaxRange(0, 1);
|
||||||
|
|
||||||
|
final String amortizationTypeParameterName = "amortizationType";
|
||||||
|
final Integer amortizationType = fromApiJsonHelper.extractIntegerWithLocaleNamed(amortizationTypeParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(amortizationTypeParameterName).value(amortizationType).notNull().inMinMaxRange(0, 1);
|
||||||
|
|
||||||
|
final String expectedDisbursementDateParameterName = "expectedDisbursementDate";
|
||||||
|
final LocalDate expectedDisbursementDate = fromApiJsonHelper.extractLocalDateNamed(expectedDisbursementDateParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(expectedDisbursementDateParameterName).value(expectedDisbursementDate).notNull();
|
||||||
|
|
||||||
|
final String repaymentsStartingFromDateParameterName = "repaymentsStartingFromDate";
|
||||||
|
if (fromApiJsonHelper.parameterExists(repaymentsStartingFromDateParameterName, element)) {
|
||||||
|
final LocalDate repaymentsStartingFromDate = fromApiJsonHelper.extractLocalDateNamed(repaymentsStartingFromDateParameterName,
|
||||||
|
element);
|
||||||
|
baseDataValidator.reset().parameter(repaymentsStartingFromDateParameterName).value(repaymentsStartingFromDate).ignoreIfNull().notNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String interestChargedFromDateParameterName = "interestChargedFromDate";
|
||||||
|
if (fromApiJsonHelper.parameterExists(interestChargedFromDateParameterName, element)) {
|
||||||
|
final LocalDate interestChargedFromDate = fromApiJsonHelper
|
||||||
|
.extractLocalDateNamed(interestChargedFromDateParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(interestChargedFromDateParameterName).value(interestChargedFromDate).ignoreIfNull().notNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String inArrearsToleranceParameterName = "inArrearsTolerance";
|
||||||
|
if (fromApiJsonHelper.parameterExists(inArrearsToleranceParameterName, element)) {
|
||||||
|
final BigDecimal inArrearsTolerance = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(inArrearsToleranceParameterName,
|
||||||
|
element);
|
||||||
|
baseDataValidator.reset().parameter(inArrearsToleranceParameterName).value(inArrearsTolerance).ignoreIfNull().positiveAmount();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String submittedOnDateParameterName = "submittedOnDate";
|
||||||
|
final LocalDate submittedOnDate = fromApiJsonHelper.extractLocalDateNamed(submittedOnDateParameterName, element);
|
||||||
|
if (submittedOnDate == null) {
|
||||||
|
baseDataValidator.reset().parameter(submittedOnDateParameterName).value(submittedOnDate).notNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String submittedOnNoteParameterName = "submittedOnNote";
|
||||||
|
if (fromApiJsonHelper.parameterExists(submittedOnNoteParameterName, element)) {
|
||||||
|
final String submittedOnNote = fromApiJsonHelper.extractStringNamed(submittedOnNoteParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(submittedOnNoteParameterName).value(submittedOnNote).ignoreIfNull().notExceedingLengthOf(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
// not optional at present but might make it so to allow it to pick up
|
||||||
|
// on only available strategy
|
||||||
|
// by default which would probably be the norm.
|
||||||
|
final String transactionProcessingStrategyIdParameterName = "transactionProcessingStrategyId";
|
||||||
|
final Long transactionProcessingStrategyId = fromApiJsonHelper.extractLongNamed(transactionProcessingStrategyIdParameterName,
|
||||||
|
element);
|
||||||
|
baseDataValidator.reset().parameter(transactionProcessingStrategyIdParameterName).value(transactionProcessingStrategyId).notNull()
|
||||||
|
.integerGreaterThanZero();
|
||||||
|
|
||||||
|
final LoanChargeCommand[] charges = extractInToLoanChargeCommands(element);
|
||||||
|
if (charges != null) {
|
||||||
|
for (LoanChargeCommand loanChargeCommand : charges) {
|
||||||
|
try {
|
||||||
|
loanChargeCommand.validateForCreate();
|
||||||
|
} catch (PlatformApiDataValidationException e) {
|
||||||
|
dataValidationErrors.addAll(e.getErrors());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
|
||||||
|
"Validation errors exist.", dataValidationErrors); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validateForModify(final String json) {
|
||||||
|
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||||
|
|
||||||
|
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||||
|
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters);
|
||||||
|
|
||||||
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||||
|
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan");
|
||||||
|
final JsonElement element = fromApiJsonHelper.parse(json);
|
||||||
|
boolean atLeastOneParameterPassedForUpdate = false;
|
||||||
|
|
||||||
|
final String clientIdParameterName = "clientId";
|
||||||
|
if (fromApiJsonHelper.parameterExists(clientIdParameterName, element)) {
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
final Long clientId = fromApiJsonHelper.extractLongNamed(clientIdParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(clientIdParameterName).value(clientId).notNull().integerGreaterThanZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String groupIdParameterName = "groupId";
|
||||||
|
if (fromApiJsonHelper.parameterExists(groupIdParameterName, element)) {
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
final Long groupId = fromApiJsonHelper.extractLongNamed(groupIdParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(groupIdParameterName).value(groupId).notNull().integerGreaterThanZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String productIdParameterName = "productId";
|
||||||
|
if (fromApiJsonHelper.parameterExists(productIdParameterName, element)) {
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
final Long productId = fromApiJsonHelper.extractLongNamed(productIdParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(productIdParameterName).value(productId).notNull().integerGreaterThanZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String accountNoParameterName = "accountNo";
|
||||||
|
if (fromApiJsonHelper.parameterExists(accountNoParameterName, element)) {
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
final String accountNo = fromApiJsonHelper.extractStringNamed(accountNoParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(accountNoParameterName).value(accountNo).notBlank().notExceedingLengthOf(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String externalIdParameterName = "externalId";
|
||||||
|
if (fromApiJsonHelper.parameterExists(externalIdParameterName, element)) {
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
final String externalId = fromApiJsonHelper.extractStringNamed(externalIdParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(externalIdParameterName).value(externalId).ignoreIfNull().notExceedingLengthOf(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String fundIdParameterName = "fundId";
|
||||||
|
if (fromApiJsonHelper.parameterExists(fundIdParameterName, element)) {
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
final Long fundId = fromApiJsonHelper.extractLongNamed(fundIdParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(fundIdParameterName).value(fundId).ignoreIfNull().integerGreaterThanZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String loanOfficerIdParameterName = "loanOfficerId";
|
||||||
|
if (fromApiJsonHelper.parameterExists(loanOfficerIdParameterName, element)) {
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
final Long loanOfficerId = fromApiJsonHelper.extractLongNamed(loanOfficerIdParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(loanOfficerIdParameterName).value(loanOfficerId).ignoreIfNull().integerGreaterThanZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String transactionProcessingStrategyIdParameterName = "transactionProcessingStrategyId";
|
||||||
|
if (fromApiJsonHelper.parameterExists(transactionProcessingStrategyIdParameterName, element)) {
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
final Long transactionProcessingStrategyId = fromApiJsonHelper.extractLongNamed(transactionProcessingStrategyIdParameterName,
|
||||||
|
element);
|
||||||
|
baseDataValidator.reset().parameter(transactionProcessingStrategyIdParameterName).value(transactionProcessingStrategyId)
|
||||||
|
.notNull().integerGreaterThanZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String principalParameterName = "principal";
|
||||||
|
if (fromApiJsonHelper.parameterExists(principalParameterName, element)) {
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
final BigDecimal principal = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(principalParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(principalParameterName).value(principal).notNull().positiveAmount();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String inArrearsToleranceParameterName = "inArrearsTolerance";
|
||||||
|
if (fromApiJsonHelper.parameterExists(inArrearsToleranceParameterName, element)) {
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
final BigDecimal principal = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(inArrearsToleranceParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(inArrearsToleranceParameterName).value(principal).ignoreIfNull().positiveAmount();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String loanTermFrequencyParameterName = "loanTermFrequency";
|
||||||
|
if (fromApiJsonHelper.parameterExists(loanTermFrequencyParameterName, element)) {
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
final Integer loanTermFrequency = fromApiJsonHelper.extractIntegerWithLocaleNamed(loanTermFrequencyParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(loanTermFrequencyParameterName).value(loanTermFrequency).notNull().integerGreaterThanZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String loanTermFrequencyTypeParameterName = "loanTermFrequencyType";
|
||||||
|
if (fromApiJsonHelper.parameterExists(loanTermFrequencyTypeParameterName, element)) {
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
final Integer loanTermFrequencyType = fromApiJsonHelper.extractIntegerWithLocaleNamed(loanTermFrequencyTypeParameterName,
|
||||||
|
element);
|
||||||
|
baseDataValidator.reset().parameter(loanTermFrequencyTypeParameterName).value(loanTermFrequencyType).notNull()
|
||||||
|
.inMinMaxRange(0, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String numberOfRepaymentsParameterName = "numberOfRepayments";
|
||||||
|
if (fromApiJsonHelper.parameterExists(numberOfRepaymentsParameterName, element)) {
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
final Integer numberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed(numberOfRepaymentsParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(numberOfRepaymentsParameterName).value(numberOfRepayments).notNull()
|
||||||
|
.integerGreaterThanZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String repaymentEveryParameterName = "repaymentEvery";
|
||||||
|
if (fromApiJsonHelper.parameterExists(repaymentEveryParameterName, element)) {
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
final Integer repaymentEvery = fromApiJsonHelper.extractIntegerWithLocaleNamed(repaymentEveryParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(repaymentEveryParameterName).value(repaymentEvery).notNull().integerGreaterThanZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String repaymentEveryTypeParameterName = "repaymentFrequencyType";
|
||||||
|
if (fromApiJsonHelper.parameterExists(repaymentEveryTypeParameterName, element)) {
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
final Integer repaymentEveryType = fromApiJsonHelper.extractIntegerWithLocaleNamed(repaymentEveryTypeParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(repaymentEveryTypeParameterName).value(repaymentEveryType).notNull().inMinMaxRange(0, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String interestRatePerPeriodParameterName = "interestRatePerPeriod";
|
||||||
|
if (fromApiJsonHelper.parameterExists(interestRatePerPeriodParameterName, element)) {
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
final BigDecimal interestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(interestRatePerPeriodParameterName,
|
||||||
|
element);
|
||||||
|
baseDataValidator.reset().parameter(interestRatePerPeriodParameterName).value(interestRatePerPeriod).notNull().positiveAmount();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String interestRateFrequencyTypeParameterName = "interestRateFrequencyType";
|
||||||
|
if (fromApiJsonHelper.parameterExists(interestRateFrequencyTypeParameterName, element)) {
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
final Integer interestRateFrequencyType = fromApiJsonHelper.extractIntegerWithLocaleNamed(
|
||||||
|
interestRateFrequencyTypeParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(interestRateFrequencyTypeParameterName).value(interestRateFrequencyType).notNull()
|
||||||
|
.inMinMaxRange(0, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String interestTypeParameterName = "interestType";
|
||||||
|
if (fromApiJsonHelper.parameterExists(interestTypeParameterName, element)) {
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
final Integer interestType = fromApiJsonHelper.extractIntegerWithLocaleNamed(interestTypeParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(interestTypeParameterName).value(interestType).notNull().inMinMaxRange(0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String interestCalculationPeriodTypeParameterName = "interestCalculationPeriodType";
|
||||||
|
if (fromApiJsonHelper.parameterExists(interestCalculationPeriodTypeParameterName, element)) {
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
final Integer interestCalculationPeriodType = fromApiJsonHelper.extractIntegerWithLocaleNamed(
|
||||||
|
interestCalculationPeriodTypeParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(interestCalculationPeriodTypeParameterName).value(interestCalculationPeriodType).notNull()
|
||||||
|
.inMinMaxRange(0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String amortizationTypeParameterName = "amortizationType";
|
||||||
|
if (fromApiJsonHelper.parameterExists(amortizationTypeParameterName, element)) {
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
final Integer amortizationType = fromApiJsonHelper.extractIntegerWithLocaleNamed(amortizationTypeParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(amortizationTypeParameterName).value(amortizationType).notNull().inMinMaxRange(0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String expectedDisbursementDateParameterName = "expectedDisbursementDate";
|
||||||
|
if (fromApiJsonHelper.parameterExists(expectedDisbursementDateParameterName, element)) {
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
|
||||||
|
final String expectedDisbursementDateStr = fromApiJsonHelper.extractStringNamed(expectedDisbursementDateParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(expectedDisbursementDateParameterName).value(expectedDisbursementDateStr).notBlank();
|
||||||
|
|
||||||
|
final LocalDate expectedDisbursementDate = fromApiJsonHelper.extractLocalDateNamed(expectedDisbursementDateParameterName,
|
||||||
|
element);
|
||||||
|
baseDataValidator.reset().parameter(expectedDisbursementDateParameterName).value(expectedDisbursementDate).notNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String repaymentsStartingFromDateParameterName = "repaymentsStartingFromDate";
|
||||||
|
if (fromApiJsonHelper.parameterExists(repaymentsStartingFromDateParameterName, element)) {
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
final LocalDate repaymentsStartingFromDate = fromApiJsonHelper.extractLocalDateNamed(repaymentsStartingFromDateParameterName,
|
||||||
|
element);
|
||||||
|
baseDataValidator.reset().parameter(repaymentsStartingFromDateParameterName).value(repaymentsStartingFromDate).ignoreIfNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String interestChargedFromDateParameterName = "interestChargedFromDate";
|
||||||
|
if (fromApiJsonHelper.parameterExists(interestChargedFromDateParameterName, element)) {
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
final LocalDate interestChargedFromDate = fromApiJsonHelper
|
||||||
|
.extractLocalDateNamed(interestChargedFromDateParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(interestChargedFromDateParameterName).value(interestChargedFromDate).ignoreIfNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String submittedOnDateParameterName = "submittedOnDate";
|
||||||
|
if (fromApiJsonHelper.parameterExists(submittedOnDateParameterName, element)) {
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
final LocalDate submittedOnDate = fromApiJsonHelper.extractLocalDateNamed(submittedOnDateParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(submittedOnDateParameterName).value(submittedOnDate).notNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String submittedOnNoteParameterName = "submittedOnNote";
|
||||||
|
if (fromApiJsonHelper.parameterExists(submittedOnNoteParameterName, element)) {
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
final String submittedOnNote = fromApiJsonHelper.extractStringNamed(submittedOnNoteParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(submittedOnNoteParameterName).value(submittedOnNote).ignoreIfNull()
|
||||||
|
.notExceedingLengthOf(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!atLeastOneParameterPassedForUpdate) {
|
||||||
|
final Object forceError = null;
|
||||||
|
baseDataValidator.reset().anyOfNotNull(forceError);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
|
||||||
|
"Validation errors exist.", dataValidationErrors); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoanChargeCommand[] extractLoanCharges(final String json) {
|
||||||
|
final JsonElement element = fromApiJsonHelper.parse(json);
|
||||||
|
return extractInToLoanChargeCommands(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoanChargeCommand[] extractInToLoanChargeCommands(final JsonElement element) {
|
||||||
|
LoanChargeCommand[] charges = null;
|
||||||
|
if (element.isJsonObject()) {
|
||||||
|
final JsonObject topLevelJsonElement = element.getAsJsonObject();
|
||||||
|
final String dateFormat = fromApiJsonHelper.extractDateFormatParameter(topLevelJsonElement);
|
||||||
|
final Locale locale = fromApiJsonHelper.extractLocaleParameter(topLevelJsonElement);
|
||||||
|
if (topLevelJsonElement.has("charges") && topLevelJsonElement.get("charges").isJsonArray()) {
|
||||||
|
|
||||||
|
final JsonArray array = topLevelJsonElement.get("charges").getAsJsonArray();
|
||||||
|
charges = new LoanChargeCommand[array.size()];
|
||||||
|
for (int i = 0; i < array.size(); i++) {
|
||||||
|
|
||||||
|
final JsonObject loanChargeElement = array.get(i).getAsJsonObject();
|
||||||
|
|
||||||
|
final Long chargeId = fromApiJsonHelper.extractLongNamed("chargeId", loanChargeElement);
|
||||||
|
final BigDecimal amount = fromApiJsonHelper.extractBigDecimalNamed("amount", loanChargeElement, locale);
|
||||||
|
final Integer chargeTimeType = fromApiJsonHelper.extractIntegerNamed("chargeTimeType", loanChargeElement, locale);
|
||||||
|
final Integer chargeCalculationType = fromApiJsonHelper.extractIntegerNamed("chargeCalculationType", loanChargeElement,
|
||||||
|
locale);
|
||||||
|
final LocalDate specifiedDueDate = fromApiJsonHelper.extractLocalDateNamed("specifiedDueDate", loanChargeElement,
|
||||||
|
dateFormat, locale);
|
||||||
|
|
||||||
|
charges[i] = new LoanChargeCommand(chargeId, amount, chargeTimeType, chargeCalculationType, specifiedDueDate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return charges;
|
||||||
|
}
|
||||||
|
}
|
||||||
+121
-100
@@ -1,6 +1,5 @@
|
|||||||
package org.mifosplatform.portfolio.loanaccount.service;
|
package org.mifosplatform.portfolio.loanaccount.service;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -10,20 +9,21 @@ import org.apache.commons.lang.StringUtils;
|
|||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||||
import org.mifosplatform.infrastructure.core.api.JsonQuery;
|
import org.mifosplatform.infrastructure.core.api.JsonQuery;
|
||||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
|
||||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||||
import org.mifosplatform.infrastructure.security.exception.NoAuthorizationException;
|
import org.mifosplatform.infrastructure.security.exception.NoAuthorizationException;
|
||||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||||
|
import org.mifosplatform.portfolio.client.domain.AccountNumberGenerator;
|
||||||
|
import org.mifosplatform.portfolio.client.domain.AccountNumberGeneratorFactory;
|
||||||
import org.mifosplatform.portfolio.client.domain.Client;
|
import org.mifosplatform.portfolio.client.domain.Client;
|
||||||
import org.mifosplatform.portfolio.client.domain.ClientRepository;
|
import org.mifosplatform.portfolio.client.domain.ClientRepository;
|
||||||
import org.mifosplatform.portfolio.client.domain.Note;
|
import org.mifosplatform.portfolio.client.domain.Note;
|
||||||
import org.mifosplatform.portfolio.client.domain.NoteRepository;
|
import org.mifosplatform.portfolio.client.domain.NoteRepository;
|
||||||
import org.mifosplatform.portfolio.client.exception.ClientNotFoundException;
|
import org.mifosplatform.portfolio.client.exception.ClientNotFoundException;
|
||||||
import org.mifosplatform.portfolio.fund.domain.Fund;
|
import org.mifosplatform.portfolio.fund.domain.Fund;
|
||||||
import org.mifosplatform.portfolio.loanaccount.command.LoanApplicationCommand;
|
import org.mifosplatform.portfolio.loanaccount.command.LoanChargeCommand;
|
||||||
import org.mifosplatform.portfolio.loanaccount.command.LoanStateTransitionCommand;
|
import org.mifosplatform.portfolio.loanaccount.command.LoanStateTransitionCommand;
|
||||||
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;
|
||||||
@@ -35,17 +35,18 @@ import org.mifosplatform.portfolio.loanaccount.exception.LoanNotFoundException;
|
|||||||
import org.mifosplatform.portfolio.loanaccount.exception.LoanNotInSubmittedAndPendingApprovalStateCannotBeDeleted;
|
import org.mifosplatform.portfolio.loanaccount.exception.LoanNotInSubmittedAndPendingApprovalStateCannotBeDeleted;
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.AprCalculator;
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.AprCalculator;
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.query.CalculateLoanScheduleQuery;
|
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.service.LoanScheduleCalculationPlatformService;
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.service.LoanScheduleCalculationPlatformService;
|
||||||
import org.mifosplatform.portfolio.loanaccount.serialization.CalculateLoanScheduleQueryFromApiJsonDeserializer;
|
import org.mifosplatform.portfolio.loanaccount.serialization.LoanApplicationCommandFromApiJsonHelper;
|
||||||
import org.mifosplatform.portfolio.loanaccount.serialization.LoanApplicationCommandFromApiJsonDeserializer;
|
|
||||||
import org.mifosplatform.portfolio.loanaccount.serialization.LoanStateTransitionCommandFromApiJsonDeserializer;
|
import org.mifosplatform.portfolio.loanaccount.serialization.LoanStateTransitionCommandFromApiJsonDeserializer;
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
|
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository;
|
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository;
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
|
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
|
||||||
import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException;
|
import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException;
|
||||||
import org.mifosplatform.useradministration.domain.AppUser;
|
import org.mifosplatform.useradministration.domain.AppUser;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.dao.DataIntegrityViolationException;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
@@ -54,10 +55,11 @@ import com.google.gson.JsonElement;
|
|||||||
@Service
|
@Service
|
||||||
public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements LoanApplicationWritePlatformService {
|
public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements LoanApplicationWritePlatformService {
|
||||||
|
|
||||||
|
private final static Logger logger = LoggerFactory.getLogger(LoanApplicationWritePlatformServiceJpaRepositoryImpl.class);
|
||||||
|
|
||||||
private final PlatformSecurityContext context;
|
private final PlatformSecurityContext context;
|
||||||
private final FromJsonHelper fromJsonHelper;
|
private final FromJsonHelper fromJsonHelper;
|
||||||
private final LoanApplicationCommandFromApiJsonDeserializer fromApiJsonDeserializer;
|
private final LoanApplicationCommandFromApiJsonHelper fromApiJsonDeserializer;
|
||||||
private final CalculateLoanScheduleQueryFromApiJsonDeserializer calculateLoanScheduleQueryFromApiJsonDeserializer;
|
|
||||||
private final LoanStateTransitionCommandFromApiJsonDeserializer loanStateTransitionCommandFromApiJsonDeserializer;
|
private final LoanStateTransitionCommandFromApiJsonDeserializer loanStateTransitionCommandFromApiJsonDeserializer;
|
||||||
private final LoanRepository loanRepository;
|
private final LoanRepository loanRepository;
|
||||||
private final NoteRepository noteRepository;
|
private final NoteRepository noteRepository;
|
||||||
@@ -67,21 +69,20 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
private final LoanProductRepository loanProductRepository;
|
private final LoanProductRepository loanProductRepository;
|
||||||
private final LoanChargeAssembler loanChargeAssembler;
|
private final LoanChargeAssembler loanChargeAssembler;
|
||||||
private final AprCalculator aprCalculator;
|
private final AprCalculator aprCalculator;
|
||||||
|
private final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LoanApplicationWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final FromJsonHelper fromJsonHelper,
|
public LoanApplicationWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final FromJsonHelper fromJsonHelper,
|
||||||
final LoanApplicationCommandFromApiJsonDeserializer fromApiJsonDeserializer,
|
final LoanApplicationCommandFromApiJsonHelper fromApiJsonDeserializer,
|
||||||
final LoanStateTransitionCommandFromApiJsonDeserializer loanStateTransitionCommandFromApiJsonDeserializer,
|
final LoanStateTransitionCommandFromApiJsonDeserializer loanStateTransitionCommandFromApiJsonDeserializer,
|
||||||
final CalculateLoanScheduleQueryFromApiJsonDeserializer calculateLoanScheduleQueryFromApiJsonDeserializer,
|
|
||||||
final AprCalculator aprCalculator, final LoanAssembler loanAssembler, final LoanChargeAssembler loanChargeAssembler,
|
final AprCalculator aprCalculator, final LoanAssembler loanAssembler, final LoanChargeAssembler loanChargeAssembler,
|
||||||
final LoanRepository loanRepository, final NoteRepository noteRepository,
|
final LoanRepository loanRepository, final NoteRepository noteRepository,
|
||||||
final LoanScheduleCalculationPlatformService calculationPlatformService, final ClientRepository clientRepository,
|
final LoanScheduleCalculationPlatformService calculationPlatformService, final ClientRepository clientRepository,
|
||||||
final LoanProductRepository loanProductRepository) {
|
final LoanProductRepository loanProductRepository, final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.fromJsonHelper = fromJsonHelper;
|
this.fromJsonHelper = fromJsonHelper;
|
||||||
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
||||||
this.loanStateTransitionCommandFromApiJsonDeserializer = loanStateTransitionCommandFromApiJsonDeserializer;
|
this.loanStateTransitionCommandFromApiJsonDeserializer = loanStateTransitionCommandFromApiJsonDeserializer;
|
||||||
this.calculateLoanScheduleQueryFromApiJsonDeserializer = calculateLoanScheduleQueryFromApiJsonDeserializer;
|
|
||||||
this.aprCalculator = aprCalculator;
|
this.aprCalculator = aprCalculator;
|
||||||
this.loanAssembler = loanAssembler;
|
this.loanAssembler = loanAssembler;
|
||||||
this.loanChargeAssembler = loanChargeAssembler;
|
this.loanChargeAssembler = loanChargeAssembler;
|
||||||
@@ -90,6 +91,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
this.calculationPlatformService = calculationPlatformService;
|
this.calculationPlatformService = calculationPlatformService;
|
||||||
this.clientRepository = clientRepository;
|
this.clientRepository = clientRepository;
|
||||||
this.loanProductRepository = loanProductRepository;
|
this.loanProductRepository = loanProductRepository;
|
||||||
|
this.accountIdentifierGeneratorFactory = accountIdentifierGeneratorFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isBeforeToday(final LocalDate date) {
|
private boolean isBeforeToday(final LocalDate date) {
|
||||||
@@ -107,23 +109,19 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
|
|
||||||
context.authenticatedUser();
|
context.authenticatedUser();
|
||||||
|
|
||||||
final CalculateLoanScheduleQuery calculateLoanScheduleQuery = this.calculateLoanScheduleQueryFromApiJsonDeserializer
|
this.fromApiJsonDeserializer.validateForCreate(command.json());
|
||||||
.commandFromApiJson(command.json());
|
|
||||||
final List<ApiParameterError> loanScheduleErrors = calculateLoanScheduleQuery.validate();
|
|
||||||
|
|
||||||
final LoanApplicationCommand loanApplicationCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json());
|
|
||||||
final List<ApiParameterError> loanApplicationErrors = loanApplicationCommand.validate();
|
|
||||||
|
|
||||||
final List<ApiParameterError> combinedErrors = new ArrayList<ApiParameterError>(loanScheduleErrors);
|
|
||||||
combinedErrors.addAll(loanApplicationErrors);
|
|
||||||
|
|
||||||
if (!combinedErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
|
|
||||||
"Validation errors exist.", combinedErrors); }
|
|
||||||
|
|
||||||
final Loan newLoanApplication = loanAssembler.assembleFrom(command);
|
final Loan newLoanApplication = loanAssembler.assembleFrom(command);
|
||||||
|
|
||||||
this.loanRepository.save(newLoanApplication);
|
this.loanRepository.save(newLoanApplication);
|
||||||
|
|
||||||
|
if (newLoanApplication.isAccountNumberRequiresAutoGeneration()) {
|
||||||
|
final AccountNumberGenerator accountNoGenerator = this.accountIdentifierGeneratorFactory
|
||||||
|
.determineLoanAccountNoGenerator(newLoanApplication.getId());
|
||||||
|
newLoanApplication.updateAccountNo(accountNoGenerator.generate());
|
||||||
|
this.loanRepository.save(newLoanApplication);
|
||||||
|
}
|
||||||
|
|
||||||
final String submittedOnNote = command.stringValueOfParameterNamed("submittedOnNote");
|
final String submittedOnNote = command.stringValueOfParameterNamed("submittedOnNote");
|
||||||
if (StringUtils.isNotBlank(submittedOnNote)) {
|
if (StringUtils.isNotBlank(submittedOnNote)) {
|
||||||
Note note = Note.loanNote(newLoanApplication, submittedOnNote);
|
Note note = Note.loanNote(newLoanApplication, submittedOnNote);
|
||||||
@@ -144,92 +142,115 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
@Override
|
@Override
|
||||||
public CommandProcessingResult modifyLoanApplication(final Long loanId, final JsonCommand command) {
|
public CommandProcessingResult modifyLoanApplication(final Long loanId, final JsonCommand command) {
|
||||||
|
|
||||||
context.authenticatedUser();
|
try {
|
||||||
|
context.authenticatedUser();
|
||||||
|
|
||||||
final CalculateLoanScheduleQuery calculateLoanScheduleQuery = this.calculateLoanScheduleQueryFromApiJsonDeserializer
|
this.fromApiJsonDeserializer.validateForModify(command.json());
|
||||||
.commandFromApiJson(command.json());
|
|
||||||
final List<ApiParameterError> loanScheduleErrors = calculateLoanScheduleQuery.validate();
|
|
||||||
|
|
||||||
final LoanApplicationCommand loanApplicationCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json());
|
final Loan existingLoanApplication = retrieveLoanBy(loanId);
|
||||||
final List<ApiParameterError> loanApplicationErrors = loanApplicationCommand.validate();
|
|
||||||
|
|
||||||
final List<ApiParameterError> combinedErrors = new ArrayList<ApiParameterError>(loanScheduleErrors);
|
final LoanChargeCommand[] charges = this.fromApiJsonDeserializer.extractLoanCharges(command.json());
|
||||||
combinedErrors.addAll(loanApplicationErrors);
|
|
||||||
|
|
||||||
if (!combinedErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
|
final Map<String, Object> changes = existingLoanApplication.loanApplicationModification(command, charges, this.aprCalculator);
|
||||||
"Validation errors exist.", combinedErrors); }
|
|
||||||
|
|
||||||
final Loan existingLoanApplication = retrieveLoanBy(loanId);
|
final String clientIdParamName = "clientId";
|
||||||
|
if (changes.containsKey(clientIdParamName)) {
|
||||||
|
final Long clientId = command.longValueOfParameterNamed(clientIdParamName);
|
||||||
|
final Client client = this.clientRepository.findOne(clientId);
|
||||||
|
if (client == null || client.isDeleted()) { throw new ClientNotFoundException(clientId); }
|
||||||
|
|
||||||
final Map<String, Object> changes = existingLoanApplication.modifyLoanApplication(command, loanApplicationCommand.getCharges(),
|
existingLoanApplication.updateClient(client);
|
||||||
this.aprCalculator);
|
}
|
||||||
|
|
||||||
final String clientIdParamName = "clientId";
|
final String productIdParamName = "productId";
|
||||||
if (changes.containsKey(clientIdParamName)) {
|
if (changes.containsKey(productIdParamName)) {
|
||||||
final Long clientId = command.longValueOfParameterNamed(clientIdParamName);
|
final Long productId = command.longValueOfParameterNamed(productIdParamName);
|
||||||
final Client client = this.clientRepository.findOne(clientId);
|
final LoanProduct loanProduct = this.loanProductRepository.findOne(productId);
|
||||||
if (client == null || client.isDeleted()) { throw new ClientNotFoundException(clientId); }
|
if (loanProduct == null) { throw new LoanProductNotFoundException(productId); }
|
||||||
|
|
||||||
existingLoanApplication.updateClient(client);
|
existingLoanApplication.updateLoanProduct(loanProduct);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 strategyIdParamName = "transactionProcessingStrategyId";
|
||||||
|
if (changes.containsKey(strategyIdParamName)) {
|
||||||
|
final Long strategyId = command.longValueOfParameterNamed(strategyIdParamName);
|
||||||
|
final LoanTransactionProcessingStrategy strategy = this.loanAssembler.findStrategyByIdIfProvided(strategyId);
|
||||||
|
|
||||||
|
existingLoanApplication.updateTransactionProcessingStrategy(strategy);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String chargesParamName = "charges";
|
||||||
|
if (changes.containsKey(chargesParamName)) {
|
||||||
|
final Set<LoanCharge> loanCharges = this.loanChargeAssembler.fromParsedJson(command.parsedJson());
|
||||||
|
existingLoanApplication.updateLoanCharges(loanCharges);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 LoanScheduleData loanSchedule = this.calculationPlatformService.calculateLoanSchedule(query);
|
||||||
|
existingLoanApplication.updateLoanSchedule(loanSchedule);
|
||||||
|
existingLoanApplication.updateLoanScheduleDependentDerivedFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loanRepository.saveAndFlush(existingLoanApplication);
|
||||||
|
|
||||||
|
final String submittedOnNote = command.stringValueOfParameterNamed("submittedOnNote");
|
||||||
|
if (StringUtils.isNotBlank(submittedOnNote)) {
|
||||||
|
Note note = Note.loanNote(existingLoanApplication, submittedOnNote);
|
||||||
|
this.noteRepository.save(note);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CommandProcessingResultBuilder() //
|
||||||
|
.withEntityId(loanId) //
|
||||||
|
.withOfficeId(existingLoanApplication.getOfficeId()) //
|
||||||
|
.withClientId(existingLoanApplication.getClientId()) //
|
||||||
|
.withGroupId(existingLoanApplication.getGroupId()) //
|
||||||
|
.withLoanId(existingLoanApplication.getId()) //
|
||||||
|
.with(changes).build();
|
||||||
|
} catch (DataIntegrityViolationException dve) {
|
||||||
|
handleDataIntegrityIssues(command, dve);
|
||||||
|
return CommandProcessingResult.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Guaranteed to throw an exception no matter what the data integrity issue
|
||||||
|
* is.
|
||||||
|
*/
|
||||||
|
private void handleDataIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) {
|
||||||
|
|
||||||
|
Throwable realCause = dve.getMostSpecificCause();
|
||||||
|
if (realCause.getMessage().contains("loan_account_no_UNIQUE")) {
|
||||||
|
|
||||||
|
final String accountNo = command.stringValueOfParameterNamed("accountNo");
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.loan.duplicate.accountNo", "Loan with accountNo `" + accountNo
|
||||||
|
+ "` already exists", "accountNo", accountNo);
|
||||||
|
} else if (realCause.getMessage().contains("loan_externalid_UNIQUE")) {
|
||||||
|
|
||||||
|
final String externalId = command.stringValueOfParameterNamed("externalId");
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.loan.duplicate.externalId", "Loan with externalId `" + externalId
|
||||||
|
+ "` already exists", "externalId", externalId);
|
||||||
}
|
}
|
||||||
|
|
||||||
final String productIdParamName = "productId";
|
logAsErrorUnexpectedDataIntegrityException(dve);
|
||||||
if (changes.containsKey(productIdParamName)) {
|
throw new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue",
|
||||||
final Long productId = command.longValueOfParameterNamed(productIdParamName);
|
"Unknown data integrity issue with resource.");
|
||||||
final LoanProduct loanProduct = this.loanProductRepository.findOne(productId);
|
}
|
||||||
if (loanProduct == null) { throw new LoanProductNotFoundException(productId); }
|
|
||||||
|
|
||||||
existingLoanApplication.updateLoanProduct(loanProduct);
|
private void logAsErrorUnexpectedDataIntegrityException(final DataIntegrityViolationException dve) {
|
||||||
}
|
logger.error(dve.getMessage(), dve);
|
||||||
|
|
||||||
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 strategyIdParamName = "transactionProcessingStrategyId";
|
|
||||||
if (changes.containsKey(strategyIdParamName)) {
|
|
||||||
final Long strategyId = command.longValueOfParameterNamed(strategyIdParamName);
|
|
||||||
final LoanTransactionProcessingStrategy strategy = this.loanAssembler.findStrategyByIdIfProvided(strategyId);
|
|
||||||
|
|
||||||
existingLoanApplication.updateTransactionProcessingStrategy(strategy);
|
|
||||||
}
|
|
||||||
|
|
||||||
final String chargesParamName = "charges";
|
|
||||||
if (changes.containsKey(chargesParamName)) {
|
|
||||||
final Set<LoanCharge> loanCharges = this.loanChargeAssembler.fromParsedJson(command.parsedJson());
|
|
||||||
existingLoanApplication.updateLoanCharges(loanCharges);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 LoanScheduleData loanSchedule = this.calculationPlatformService.calculateLoanSchedule(query);
|
|
||||||
existingLoanApplication.updateLoanSchedule(loanSchedule);
|
|
||||||
existingLoanApplication.updateLoanScheduleDependentDerivedFields();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.loanRepository.save(existingLoanApplication);
|
|
||||||
|
|
||||||
final String submittedOnNote = command.stringValueOfParameterNamed("submittedOnNote");
|
|
||||||
if (StringUtils.isNotBlank(submittedOnNote)) {
|
|
||||||
Note note = Note.loanNote(existingLoanApplication, submittedOnNote);
|
|
||||||
this.noteRepository.save(note);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new CommandProcessingResultBuilder() //
|
|
||||||
.withEntityId(loanId) //
|
|
||||||
.withOfficeId(existingLoanApplication.getOfficeId()) //
|
|
||||||
.withClientId(existingLoanApplication.getClientId()) //
|
|
||||||
.withGroupId(existingLoanApplication.getGroupId()) //
|
|
||||||
.withLoanId(existingLoanApplication.getId()) //
|
|
||||||
.with(changes).build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
|
|||||||
+5
-4
@@ -81,6 +81,7 @@ public class LoanAssembler {
|
|||||||
|
|
||||||
private Loan assembleApplication(final JsonElement element, final Long clientId, final Long groupId) {
|
private Loan assembleApplication(final JsonElement element, final Long clientId, final Long groupId) {
|
||||||
|
|
||||||
|
final String accountNo = fromApiJsonHelper.extractStringNamed("accountNo", element);
|
||||||
final Long productId = fromApiJsonHelper.extractLongNamed("productId", element);
|
final Long productId = fromApiJsonHelper.extractLongNamed("productId", element);
|
||||||
final Long fundId = fromApiJsonHelper.extractLongNamed("fundId", element);
|
final Long fundId = fromApiJsonHelper.extractLongNamed("fundId", element);
|
||||||
final Long loanOfficerId = fromApiJsonHelper.extractLongNamed("loanOfficerId", element);
|
final Long loanOfficerId = fromApiJsonHelper.extractLongNamed("loanOfficerId", element);
|
||||||
@@ -96,7 +97,7 @@ public class LoanAssembler {
|
|||||||
final Set<LoanCharge> loanCharges = this.loanChargeAssembler.fromParsedJson(element);
|
final Set<LoanCharge> loanCharges = this.loanChargeAssembler.fromParsedJson(element);
|
||||||
|
|
||||||
final BigDecimal inArrearsTolerance = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("inArrearsTolerance", element);
|
final BigDecimal inArrearsTolerance = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("inArrearsTolerance", element);
|
||||||
LoanSchedule loanSchedule = this.loanScheduleAssembler.fromJson(element, inArrearsTolerance);
|
final LoanSchedule loanSchedule = this.loanScheduleAssembler.fromJson(element, inArrearsTolerance);
|
||||||
|
|
||||||
Loan loanApplication = null;
|
Loan loanApplication = null;
|
||||||
Client client = null;
|
Client client = null;
|
||||||
@@ -105,7 +106,7 @@ public class LoanAssembler {
|
|||||||
client = this.clientRepository.findOne(clientId);
|
client = this.clientRepository.findOne(clientId);
|
||||||
if (client == null || client.isDeleted()) { throw new ClientNotFoundException(clientId); }
|
if (client == null || client.isDeleted()) { throw new ClientNotFoundException(clientId); }
|
||||||
|
|
||||||
loanApplication = Loan.newIndividualLoanApplication(client, loanProduct, fund, loanOfficer, loanTransactionProcessingStrategy,
|
loanApplication = Loan.newIndividualLoanApplication(accountNo, client, loanProduct, fund, loanOfficer, loanTransactionProcessingStrategy,
|
||||||
loanSchedule, loanCharges);
|
loanSchedule, loanCharges);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,7 +114,7 @@ public class LoanAssembler {
|
|||||||
group = this.groupRepository.findOne(groupId);
|
group = this.groupRepository.findOne(groupId);
|
||||||
if (group == null || group.isDeleted()) { throw new GroupNotFoundException(groupId); }
|
if (group == null || group.isDeleted()) { throw new GroupNotFoundException(groupId); }
|
||||||
|
|
||||||
loanApplication = Loan.newGroupLoanApplication(group, loanProduct, fund, loanOfficer, loanTransactionProcessingStrategy,
|
loanApplication = Loan.newGroupLoanApplication(accountNo, group, loanProduct, fund, loanOfficer, loanTransactionProcessingStrategy,
|
||||||
loanSchedule, loanCharges);
|
loanSchedule, loanCharges);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,7 +122,7 @@ public class LoanAssembler {
|
|||||||
|
|
||||||
if (!group.hasClientAsMember(client)) { throw new ClientNotInGroupException(clientId, groupId); }
|
if (!group.hasClientAsMember(client)) { throw new ClientNotInGroupException(clientId, groupId); }
|
||||||
|
|
||||||
loanApplication = Loan.newIndividualLoanApplicationFromGroup(client, group, loanProduct, fund, loanOfficer, loanTransactionProcessingStrategy,
|
loanApplication = Loan.newIndividualLoanApplicationFromGroup(accountNo, client, group, loanProduct, fund, loanOfficer, loanTransactionProcessingStrategy,
|
||||||
loanSchedule, loanCharges);
|
loanSchedule, loanCharges);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
-62
@@ -1,62 +0,0 @@
|
|||||||
package org.mifosplatform.portfolio.loanaccount.service;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
|
|
||||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.AprCalculator;
|
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.query.CalculateLoanScheduleQuery;
|
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
|
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
|
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
|
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
|
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository;
|
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
|
|
||||||
import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class LoanProductRelatedDetailAssembler {
|
|
||||||
|
|
||||||
private final LoanProductRepository loanProductRepository;
|
|
||||||
private final AprCalculator aprCalculator;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public LoanProductRelatedDetailAssembler(final LoanProductRepository loanProductRepository, final AprCalculator aprCalculator) {
|
|
||||||
this.loanProductRepository = loanProductRepository;
|
|
||||||
this.aprCalculator = aprCalculator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LoanProductRelatedDetail assembleFrom(final CalculateLoanScheduleQuery command) {
|
|
||||||
|
|
||||||
final BigDecimal principalAmount = command.getPrincipal();
|
|
||||||
final BigDecimal defaultNominalInterestRatePerPeriod = command.getInterestRatePerPeriod();
|
|
||||||
final PeriodFrequencyType interestPeriodFrequencyType = PeriodFrequencyType.fromInt(command.getInterestRateFrequencyType());
|
|
||||||
final InterestMethod interestMethod = InterestMethod.fromInt(command.getInterestType());
|
|
||||||
final InterestCalculationPeriodMethod interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(command
|
|
||||||
.getInterestCalculationPeriodType());
|
|
||||||
|
|
||||||
final Integer defaultNumberOfInstallments = command.getNumberOfRepayments();
|
|
||||||
final Integer repayEvery = command.getRepaymentEvery();
|
|
||||||
final PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.fromInt(command.getRepaymentFrequencyType());
|
|
||||||
|
|
||||||
final AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.getAmortizationType());
|
|
||||||
|
|
||||||
final BigDecimal defaultAnnualNominalInterestRate = this.aprCalculator.calculateFrom(interestPeriodFrequencyType,
|
|
||||||
defaultNominalInterestRatePerPeriod);
|
|
||||||
|
|
||||||
final LoanProduct loanProduct = this.loanProductRepository.findOne(command.getProductId());
|
|
||||||
if (loanProduct == null) { throw new LoanProductNotFoundException(command.getProductId()); }
|
|
||||||
|
|
||||||
final MonetaryCurrency currency = loanProduct.getCurrency();
|
|
||||||
|
|
||||||
// in arrerars tolerance isnt relevant when auto-calculating a loan
|
|
||||||
// schedule
|
|
||||||
final BigDecimal inArrearsTolerance = BigDecimal.ZERO;
|
|
||||||
|
|
||||||
return new LoanProductRelatedDetail(currency, principalAmount, defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType,
|
|
||||||
defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery, repaymentFrequencyType,
|
|
||||||
defaultNumberOfInstallments, amortizationMethod, inArrearsTolerance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+57
-57
@@ -368,7 +368,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
private static final class LoanMapper implements RowMapper<LoanBasicDetailsData> {
|
private static final class LoanMapper implements RowMapper<LoanBasicDetailsData> {
|
||||||
|
|
||||||
public String loanSchema() {
|
public String loanSchema() {
|
||||||
return "l.id as id, l.external_id as externalId, l.fund_id as fundId, f.name as fundName, "
|
return "l.id as id, l.account_no as accountNo, l.external_id as externalId, l.fund_id as fundId, f.name as fundName, "
|
||||||
+ " lp.id as loanProductId, lp.name as loanProductName, lp.description as loanProductDescription, c.id as clientId, c.display_name as clientName, "
|
+ " lp.id as loanProductId, lp.name as loanProductName, lp.description as loanProductDescription, c.id as clientId, c.display_name as clientName, "
|
||||||
+ " c.office_id as clientOfficeId, g.id as groupId, g.name as groupName, g.office_id as groupOfficeId,"
|
+ " c.office_id as clientOfficeId, g.id as groupId, g.name as groupName, g.office_id as groupOfficeId,"
|
||||||
+ " l.submittedon_date as submittedOnDate,"
|
+ " l.submittedon_date as submittedOnDate,"
|
||||||
@@ -391,75 +391,75 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
@Override
|
@Override
|
||||||
public LoanBasicDetailsData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
public LoanBasicDetailsData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||||
|
|
||||||
String currencyCode = rs.getString("currencyCode");
|
final String currencyCode = rs.getString("currencyCode");
|
||||||
String currencyName = rs.getString("currencyName");
|
final String currencyName = rs.getString("currencyName");
|
||||||
String currencyNameCode = rs.getString("currencyNameCode");
|
final String currencyNameCode = rs.getString("currencyNameCode");
|
||||||
String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol");
|
final String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol");
|
||||||
Integer currencyDigits = JdbcSupport.getInteger(rs, "currencyDigits");
|
final Integer currencyDigits = JdbcSupport.getInteger(rs, "currencyDigits");
|
||||||
CurrencyData currencyData = new CurrencyData(currencyCode, currencyName, currencyDigits, currencyDisplaySymbol,
|
final CurrencyData currencyData = new CurrencyData(currencyCode, currencyName, currencyDigits, currencyDisplaySymbol,
|
||||||
currencyNameCode);
|
currencyNameCode);
|
||||||
|
|
||||||
Long id = rs.getLong("id");
|
final Long id = rs.getLong("id");
|
||||||
String externalId = rs.getString("externalId");
|
final String accountNo = rs.getString("accountNo");
|
||||||
|
final String externalId = rs.getString("externalId");
|
||||||
|
|
||||||
Long clientId = JdbcSupport.getLong(rs, "clientId");
|
final Long clientId = JdbcSupport.getLong(rs, "clientId");
|
||||||
Long clientOfficeId = JdbcSupport.getLong(rs, "clientOfficeId");
|
final Long clientOfficeId = JdbcSupport.getLong(rs, "clientOfficeId");
|
||||||
;
|
final String clientName = rs.getString("clientName");
|
||||||
String clientName = rs.getString("clientName");
|
|
||||||
|
|
||||||
Long groupId = JdbcSupport.getLong(rs, "groupId");
|
final Long groupId = JdbcSupport.getLong(rs, "groupId");
|
||||||
Long groupOfficeId = JdbcSupport.getLong(rs, "groupOfficeId");
|
final Long groupOfficeId = JdbcSupport.getLong(rs, "groupOfficeId");
|
||||||
;
|
final String groupName = rs.getString("groupName");
|
||||||
String groupName = rs.getString("groupName");
|
|
||||||
|
|
||||||
Long fundId = JdbcSupport.getLong(rs, "fundId");
|
final Long fundId = JdbcSupport.getLong(rs, "fundId");
|
||||||
String fundName = rs.getString("fundName");
|
final String fundName = rs.getString("fundName");
|
||||||
Long loanOfficerId = JdbcSupport.getLong(rs, "loanOfficerId");
|
final Long loanOfficerId = JdbcSupport.getLong(rs, "loanOfficerId");
|
||||||
String loanOfficerName = rs.getString("loanOfficerName");
|
final String loanOfficerName = rs.getString("loanOfficerName");
|
||||||
Long loanProductId = JdbcSupport.getLong(rs, "loanProductId");
|
final Long loanProductId = JdbcSupport.getLong(rs, "loanProductId");
|
||||||
String loanProductName = rs.getString("loanProductName");
|
final String loanProductName = rs.getString("loanProductName");
|
||||||
String loanProductDescription = rs.getString("loanProductDescription");
|
final String loanProductDescription = rs.getString("loanProductDescription");
|
||||||
|
|
||||||
LocalDate submittedOnDate = JdbcSupport.getLocalDate(rs, "submittedOnDate");
|
final LocalDate submittedOnDate = JdbcSupport.getLocalDate(rs, "submittedOnDate");
|
||||||
LocalDate approvedOnDate = JdbcSupport.getLocalDate(rs, "approvedOnDate");
|
final LocalDate approvedOnDate = JdbcSupport.getLocalDate(rs, "approvedOnDate");
|
||||||
LocalDate expectedDisbursementDate = JdbcSupport.getLocalDate(rs, "expectedDisbursementDate");
|
final LocalDate expectedDisbursementDate = JdbcSupport.getLocalDate(rs, "expectedDisbursementDate");
|
||||||
LocalDate actualDisbursementDate = JdbcSupport.getLocalDate(rs, "actualDisbursementDate");
|
final LocalDate actualDisbursementDate = JdbcSupport.getLocalDate(rs, "actualDisbursementDate");
|
||||||
LocalDate expectedFirstRepaymentOnDate = JdbcSupport.getLocalDate(rs, "expectedFirstRepaymentOnDate");
|
final LocalDate expectedFirstRepaymentOnDate = JdbcSupport.getLocalDate(rs, "expectedFirstRepaymentOnDate");
|
||||||
LocalDate interestChargedFromDate = JdbcSupport.getLocalDate(rs, "interestChargedFromDate");
|
final LocalDate interestChargedFromDate = JdbcSupport.getLocalDate(rs, "interestChargedFromDate");
|
||||||
LocalDate closedOnDate = JdbcSupport.getLocalDate(rs, "closedOnDate");
|
final LocalDate closedOnDate = JdbcSupport.getLocalDate(rs, "closedOnDate");
|
||||||
LocalDate expectedMaturityDate = JdbcSupport.getLocalDate(rs, "expectedMaturityDate");
|
final LocalDate expectedMaturityDate = JdbcSupport.getLocalDate(rs, "expectedMaturityDate");
|
||||||
|
|
||||||
BigDecimal principal = rs.getBigDecimal("principal");
|
final BigDecimal principal = rs.getBigDecimal("principal");
|
||||||
BigDecimal inArrearsTolerance = rs.getBigDecimal("inArrearsTolerance");
|
final BigDecimal inArrearsTolerance = rs.getBigDecimal("inArrearsTolerance");
|
||||||
BigDecimal totalDisbursementCharges = rs.getBigDecimal("totalDisbursementCharges");
|
final BigDecimal totalDisbursementCharges = rs.getBigDecimal("totalDisbursementCharges");
|
||||||
|
|
||||||
Integer numberOfRepayments = JdbcSupport.getInteger(rs, "numberOfRepayments");
|
final Integer numberOfRepayments = JdbcSupport.getInteger(rs, "numberOfRepayments");
|
||||||
Integer repaymentEvery = JdbcSupport.getInteger(rs, "repaymentEvery");
|
final Integer repaymentEvery = JdbcSupport.getInteger(rs, "repaymentEvery");
|
||||||
BigDecimal interestRatePerPeriod = rs.getBigDecimal("interestRatePerPeriod");
|
final BigDecimal interestRatePerPeriod = rs.getBigDecimal("interestRatePerPeriod");
|
||||||
BigDecimal annualInterestRate = rs.getBigDecimal("annualInterestRate");
|
final BigDecimal annualInterestRate = rs.getBigDecimal("annualInterestRate");
|
||||||
|
|
||||||
Integer termFrequency = JdbcSupport.getInteger(rs, "termFrequency");
|
final Integer termFrequency = JdbcSupport.getInteger(rs, "termFrequency");
|
||||||
Integer termPeriodFrequencyTypeInt = JdbcSupport.getInteger(rs, "termPeriodFrequencyType");
|
final Integer termPeriodFrequencyTypeInt = JdbcSupport.getInteger(rs, "termPeriodFrequencyType");
|
||||||
EnumOptionData termPeriodFrequencyType = LoanEnumerations.termFrequencyType(termPeriodFrequencyTypeInt);
|
final EnumOptionData termPeriodFrequencyType = LoanEnumerations.termFrequencyType(termPeriodFrequencyTypeInt);
|
||||||
|
|
||||||
int repaymentFrequencyTypeInt = JdbcSupport.getInteger(rs, "repaymentFrequencyType");
|
final int repaymentFrequencyTypeInt = JdbcSupport.getInteger(rs, "repaymentFrequencyType");
|
||||||
EnumOptionData repaymentFrequencyType = LoanEnumerations.repaymentFrequencyType(repaymentFrequencyTypeInt);
|
final EnumOptionData repaymentFrequencyType = LoanEnumerations.repaymentFrequencyType(repaymentFrequencyTypeInt);
|
||||||
|
|
||||||
int interestRateFrequencyTypeInt = JdbcSupport.getInteger(rs, "interestRateFrequencyType");
|
final int interestRateFrequencyTypeInt = JdbcSupport.getInteger(rs, "interestRateFrequencyType");
|
||||||
EnumOptionData interestRateFrequencyType = LoanEnumerations.interestRateFrequencyType(interestRateFrequencyTypeInt);
|
final EnumOptionData interestRateFrequencyType = LoanEnumerations.interestRateFrequencyType(interestRateFrequencyTypeInt);
|
||||||
|
|
||||||
Integer transactionStrategyId = JdbcSupport.getInteger(rs, "transactionStrategyId");
|
final Integer transactionStrategyId = JdbcSupport.getInteger(rs, "transactionStrategyId");
|
||||||
|
|
||||||
int amortizationTypeInt = JdbcSupport.getInteger(rs, "amortizationType");
|
final int amortizationTypeInt = JdbcSupport.getInteger(rs, "amortizationType");
|
||||||
int interestTypeInt = JdbcSupport.getInteger(rs, "interestType");
|
final int interestTypeInt = JdbcSupport.getInteger(rs, "interestType");
|
||||||
int interestCalculationPeriodTypeInt = JdbcSupport.getInteger(rs, "interestCalculationPeriodType");
|
final int interestCalculationPeriodTypeInt = JdbcSupport.getInteger(rs, "interestCalculationPeriodType");
|
||||||
|
|
||||||
EnumOptionData amortizationType = LoanEnumerations.amortizationType(amortizationTypeInt);
|
final EnumOptionData amortizationType = LoanEnumerations.amortizationType(amortizationTypeInt);
|
||||||
EnumOptionData interestType = LoanEnumerations.interestType(interestTypeInt);
|
final EnumOptionData interestType = LoanEnumerations.interestType(interestTypeInt);
|
||||||
EnumOptionData interestCalculationPeriodType = LoanEnumerations.interestCalculationPeriodType(interestCalculationPeriodTypeInt);
|
final EnumOptionData interestCalculationPeriodType = LoanEnumerations
|
||||||
|
.interestCalculationPeriodType(interestCalculationPeriodTypeInt);
|
||||||
|
|
||||||
Integer lifeCycleStatusId = JdbcSupport.getInteger(rs, "lifeCycleStatusId");
|
final Integer lifeCycleStatusId = JdbcSupport.getInteger(rs, "lifeCycleStatusId");
|
||||||
EnumOptionData status = LoanEnumerations.status(lifeCycleStatusId);
|
final EnumOptionData status = LoanEnumerations.status(lifeCycleStatusId);
|
||||||
|
|
||||||
LocalDate lifeCycleStatusDate = submittedOnDate;
|
LocalDate lifeCycleStatusDate = submittedOnDate;
|
||||||
if (approvedOnDate != null) {
|
if (approvedOnDate != null) {
|
||||||
@@ -473,8 +473,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Collection<LoanChargeData> charges = null;
|
Collection<LoanChargeData> charges = null;
|
||||||
return new LoanBasicDetailsData(id, externalId, clientId, clientName, clientOfficeId, groupId, groupName, groupOfficeId,
|
return new LoanBasicDetailsData(id, accountNo, externalId, clientId, clientName, clientOfficeId, groupId, groupName,
|
||||||
loanProductId, loanProductName, loanProductDescription, fundId, fundName, closedOnDate, submittedOnDate,
|
groupOfficeId, loanProductId, loanProductName, loanProductDescription, fundId, fundName, closedOnDate, submittedOnDate,
|
||||||
approvedOnDate, expectedDisbursementDate, actualDisbursementDate, expectedMaturityDate, expectedFirstRepaymentOnDate,
|
approvedOnDate, expectedDisbursementDate, actualDisbursementDate, expectedMaturityDate, expectedFirstRepaymentOnDate,
|
||||||
interestChargedFromDate, currencyData, principal, inArrearsTolerance, numberOfRepayments, repaymentEvery,
|
interestChargedFromDate, currencyData, principal, inArrearsTolerance, numberOfRepayments, repaymentEvery,
|
||||||
interestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType,
|
interestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType,
|
||||||
|
|||||||
Reference in New Issue
Block a user