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")
|
||||
@Consumes({ 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");
|
||||
|
||||
@@ -278,7 +278,6 @@ public class ClientsApiResource {
|
||||
"withdrawnByClientDepositAccountsCount", "withdrawnByClientDepositAccounts", "closedDepositAccountsCount",
|
||||
"closedDepositAccounts", "maturedDepositAccountsCount", "maturedDepositAccounts", "rejectedDepositAccountsCount",
|
||||
"rejectedDepositAccounts", "preclosedDepositAccountsCount", "preclosedDepositAccounts",
|
||||
|
||||
"pendingApprovalSavingAccountsCount", "pendingApprovalSavingAccounts", "approvedSavingAccountsCount",
|
||||
"approvedSavingAccounts", "withdrawnByClientSavingAccountsCount", "withdrawnByClientSavingAccounts",
|
||||
"rejectedSavingAccountsCount", "rejectedSavingAccounts", "closedSavingAccountsCount", "closedSavingAccounts"));
|
||||
|
||||
+5
-5
@@ -10,6 +10,8 @@ public class ClientAccountSummaryData {
|
||||
@SuppressWarnings("unused")
|
||||
private final Long id;
|
||||
@SuppressWarnings("unused")
|
||||
private final String accountNo;
|
||||
@SuppressWarnings("unused")
|
||||
private final String externalId;
|
||||
@SuppressWarnings("unused")
|
||||
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,
|
||||
final Integer loanStatusId) {
|
||||
this.id = id;
|
||||
this.accountNo = null;
|
||||
this.externalId = externalId;
|
||||
this.productId = productId;
|
||||
this.productName = loanProductName;
|
||||
@@ -29,13 +32,10 @@ public class ClientAccountSummaryData {
|
||||
this.status = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
public ClientAccountSummaryData(final Long id, final String accountNo, final String externalId, final Long productId, final String loanProductName,
|
||||
final EnumOptionData loanStatus) {
|
||||
this.id = id;
|
||||
this.accountNo = accountNo;
|
||||
this.externalId = externalId;
|
||||
this.productId = productId;
|
||||
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.
|
||||
*
|
||||
* @see ClientAccountNumberGenerator
|
||||
* @see ZeroPaddedAccountNumberGenerator
|
||||
*/
|
||||
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")
|
||||
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;
|
||||
|
||||
@ManyToOne
|
||||
@@ -148,8 +148,9 @@ public class Client extends AbstractPersistable<Long> {
|
||||
this.office = newOffice;
|
||||
}
|
||||
|
||||
public void updateAccountIdentifier(final String accountIdentifier) {
|
||||
public void updateAccountNo(final String accountIdentifier) {
|
||||
this.accountNumber = accountIdentifier;
|
||||
this.accountNumberRequiresAutoGeneration = false;
|
||||
}
|
||||
|
||||
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() {
|
||||
|
||||
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 ")
|
||||
.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 {
|
||||
|
||||
final Long id = JdbcSupport.getLong(rs, "id");
|
||||
final String accountNo = rs.getString("accountNo");
|
||||
final String externalId = rs.getString("externalId");
|
||||
final Long productId = JdbcSupport.getLong(rs, "productId");
|
||||
final String loanProductName = rs.getString("productName");
|
||||
final Integer loanStatusId = JdbcSupport.getInteger(rs, "statusId");
|
||||
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.portfolio.client.command.ClientIdentifierCommand;
|
||||
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.Client;
|
||||
import org.mifosplatform.portfolio.client.domain.ClientIdentifier;
|
||||
@@ -58,7 +58,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
private final ClientCommandFromApiJsonDeserializer fromApiJsonDeserializer;
|
||||
private final ClientNoteCommandFromApiJsonDeserializer clientNoteFromApiJsonDeserializer;
|
||||
private final ClientIdentifierCommandFromApiJsonDeserializer clientIdentifierCommandFromApiJsonDeserializer;
|
||||
private final AccountIdentifierGeneratorFactory accountIdentifierGeneratorFactory;
|
||||
private final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory;
|
||||
|
||||
@Autowired
|
||||
public ClientWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final ClientRepository clientRepository,
|
||||
@@ -67,7 +67,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
final ClientCommandFromApiJsonDeserializer fromApiJsonDeserializer,
|
||||
final ClientNoteCommandFromApiJsonDeserializer clientNoteFromApiJsonDeserializer,
|
||||
final ClientIdentifierCommandFromApiJsonDeserializer clientIdentifierCommandFromApiJsonDeserializer,
|
||||
final AccountIdentifierGeneratorFactory accountIdentifierGeneratorFactory) {
|
||||
final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory) {
|
||||
this.context = context;
|
||||
this.clientRepository = clientRepository;
|
||||
this.clientIdentifierRepository = clientIdentifierRepository;
|
||||
@@ -123,8 +123,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
|
||||
this.fromApiJsonDeserializer.validateForCreate(command.json());
|
||||
|
||||
final String officeIdParamName = "officeId";
|
||||
final Long officeId = command.longValueOfParameterNamed(officeIdParamName);
|
||||
final Long officeId = command.longValueOfParameterNamed("officeId");
|
||||
|
||||
final Office clientOffice = this.officeRepository.findOne(officeId);
|
||||
if (clientOffice == null) { throw new OfficeNotFoundException(officeId); }
|
||||
@@ -135,7 +134,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
if (newClient.isAccountNumberRequiresAutoGeneration()) {
|
||||
final AccountNumberGenerator accountNoGenerator = this.accountIdentifierGeneratorFactory
|
||||
.determineClientAccountNoGenerator(newClient.getId());
|
||||
newClient.updateAccountIdentifier(accountNoGenerator.generate());
|
||||
newClient.updateAccountNo(accountNoGenerator.generate());
|
||||
this.clientRepository.save(newClient);
|
||||
}
|
||||
|
||||
|
||||
+8
-8
@@ -69,14 +69,14 @@ import com.google.gson.JsonElement;
|
||||
@Scope("singleton")
|
||||
public class LoansApiResource {
|
||||
|
||||
private final Set<String> LOAN_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "externalId", "clientId", "groupId",
|
||||
"clientName", "groupName", "fundId", "fundName", "loanProductId", "loanProductName", "loanProductDescription", "currency",
|
||||
"principal", "inArrearsTolerance", "numberOfRepayments", "repaymentEvery", "interestRatePerPeriod", "annualInterestRate",
|
||||
"repaymentFrequencyType", "interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType",
|
||||
"submittedOnDate", "approvedOnDate", "expectedDisbursementDate", "actualDisbursementDate", "expectedFirstRepaymentOnDate",
|
||||
"interestChargedFromDate", "closedOnDate", "expectedMaturityDate", "status", "lifeCycleStatusDate", "repaymentSchedule",
|
||||
"transactions", "permissions", "convenienceData", "charges", "productOptions", "amortizationTypeOptions",
|
||||
"interestTypeOptions", "interestCalculationPeriodTypeOptions", "repaymentFrequencyTypeOptions",
|
||||
private final Set<String> LOAN_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "accountNo", "externalId", "clientId",
|
||||
"groupId", "clientName", "groupName", "fundId", "fundName", "loanProductId", "loanProductName", "loanProductDescription",
|
||||
"currency", "principal", "inArrearsTolerance", "numberOfRepayments", "repaymentEvery", "interestRatePerPeriod",
|
||||
"annualInterestRate", "repaymentFrequencyType", "interestRateFrequencyType", "amortizationType", "interestType",
|
||||
"interestCalculationPeriodType", "submittedOnDate", "approvedOnDate", "expectedDisbursementDate", "actualDisbursementDate",
|
||||
"expectedFirstRepaymentOnDate", "interestChargedFromDate", "closedOnDate", "expectedMaturityDate", "status",
|
||||
"lifeCycleStatusDate", "repaymentSchedule", "transactions", "permissions", "convenienceData", "charges", "productOptions",
|
||||
"amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions", "repaymentFrequencyTypeOptions",
|
||||
"interestRateFrequencyTypeOptions", "fundOptions", "repaymentStrategyOptions", "chargeOptions", "loanOfficerId",
|
||||
"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
|
||||
private final Long id;
|
||||
private final String accountNo;
|
||||
private final String externalId;
|
||||
private final Long clientId;
|
||||
private final String clientName;
|
||||
@@ -129,6 +130,7 @@ public class LoanAccountData {
|
||||
}
|
||||
|
||||
this.id = basicDetails.getId();
|
||||
this.accountNo = basicDetails.getAccountNo();
|
||||
this.externalId = basicDetails.getExternalId();
|
||||
this.clientId = basicDetails.getClientId();
|
||||
this.clientName = basicDetails.getClientName();
|
||||
|
||||
+12
-4
@@ -20,6 +20,7 @@ import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
|
||||
public class LoanBasicDetailsData {
|
||||
|
||||
private final Long id;
|
||||
private final String accountNo;
|
||||
private final String externalId;
|
||||
private final Long clientId;
|
||||
private final Long clientOfficeId;
|
||||
@@ -105,6 +106,7 @@ public class LoanBasicDetailsData {
|
||||
final EnumOptionData interestCalculationPeriodType, final LocalDate expectedDisbursementDate,
|
||||
final Collection<LoanChargeData> charges) {
|
||||
this.id = null;
|
||||
this.accountNo = null;
|
||||
this.externalId = null;
|
||||
this.clientId = clientId;
|
||||
this.clientName = clientName;
|
||||
@@ -163,6 +165,7 @@ public class LoanBasicDetailsData {
|
||||
private LoanBasicDetailsData(final Long clientId, final String clientName, final Long clientOfficeId, final Long groupId,
|
||||
final String groupName, final Long groupOfficeId, final LocalDate expectedDisbursementDate) {
|
||||
this.id = null;
|
||||
this.accountNo = null;
|
||||
this.externalId = null;
|
||||
this.clientId = clientId;
|
||||
this.clientName = clientName;
|
||||
@@ -210,10 +213,10 @@ public class LoanBasicDetailsData {
|
||||
this.totalDisbursementCharges = BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
public LoanBasicDetailsData(final Long id, final String externalId, final Long clientId, final String clientName,
|
||||
final Long clientOfficeId, final Long groupId, final String groupName, final Long groupOfficeId, final Long loanProductId,
|
||||
final String loanProductName, final String loanProductDescription, final Long fundId, String fundName,
|
||||
final LocalDate closedOnDate, final LocalDate submittedOnDate, final LocalDate approvedOnDate,
|
||||
public LoanBasicDetailsData(final Long id, final String accountNo, final String externalId, final Long clientId,
|
||||
final String clientName, final Long clientOfficeId, final Long groupId, final String groupName, final Long groupOfficeId,
|
||||
final Long loanProductId, final String loanProductName, final String loanProductDescription, final Long fundId,
|
||||
String fundName, final LocalDate closedOnDate, final LocalDate submittedOnDate, final LocalDate approvedOnDate,
|
||||
final LocalDate expectedDisbursementDate, final LocalDate actualDisbursementDate, final LocalDate expectedMaturityDate,
|
||||
final LocalDate repaymentsStartingFromDate, final LocalDate interestChargedFromDate, final CurrencyData currency,
|
||||
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 Long loanOfficerId, String loanOfficerName, final BigDecimal totalDisbursementCharges) {
|
||||
this.id = id;
|
||||
this.accountNo = accountNo;
|
||||
this.externalId = externalId;
|
||||
this.clientId = clientId;
|
||||
this.clientName = clientName;
|
||||
@@ -349,6 +353,10 @@ public class LoanBasicDetailsData {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getAccountNo() {
|
||||
return this.accountNo;
|
||||
}
|
||||
|
||||
public String getExternalId() {
|
||||
return externalId;
|
||||
}
|
||||
|
||||
+96
-46
@@ -35,6 +35,7 @@ import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
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.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
@@ -64,9 +65,17 @@ import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
|
||||
@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> {
|
||||
|
||||
@Column(name = "account_no", length = 20, unique = true, nullable = false)
|
||||
private String accountNumber;
|
||||
|
||||
@Column(name = "external_id")
|
||||
private String externalId;
|
||||
|
||||
@ManyToOne(optional = true)
|
||||
@JoinColumn(name = "client_id")
|
||||
private Client client;
|
||||
@@ -95,9 +104,6 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
@JoinColumn(name = "loan_transaction_strategy_id", nullable = true)
|
||||
private LoanTransactionProcessingStrategy transactionProcessingStrategy;
|
||||
|
||||
@Column(name = "external_id")
|
||||
private String externalId;
|
||||
|
||||
@Embedded
|
||||
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)
|
||||
private BigDecimal totalChargesDueAtDisbursement;
|
||||
|
||||
@Transient
|
||||
private boolean accountNumberRequiresAutoGeneration = false;
|
||||
|
||||
@Transient
|
||||
private final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessor = new LoanRepaymentScheduleTransactionProcessorFactory();
|
||||
|
||||
@Deprecated
|
||||
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,
|
||||
public static Loan newIndividualLoanApplication(final String accountNo, 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, group, fund, officer, transactionProcessingStrategy, loanProduct, loanRepaymentScheduleDetail, status,
|
||||
loanCharges);
|
||||
return new Loan(accountNo, client, null, fund, officer, transactionProcessingStrategy, loanProduct, loanRepaymentScheduleDetail,
|
||||
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() {
|
||||
//
|
||||
}
|
||||
|
||||
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 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.group = group;
|
||||
this.fund = fund;
|
||||
@@ -284,6 +285,14 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
private void updateTotalChargesDueAtDisbursement() {
|
||||
this.totalChargesDueAtDisbursement = deriveSumTotalOfChargesDueAtDisbursement();
|
||||
}
|
||||
|
||||
public boolean isAccountNumberRequiresAutoGeneration() {
|
||||
return this.accountNumberRequiresAutoGeneration;
|
||||
}
|
||||
|
||||
public void setAccountNumberRequiresAutoGeneration(boolean accountNumberRequiresAutoGeneration) {
|
||||
this.accountNumberRequiresAutoGeneration = accountNumberRequiresAutoGeneration;
|
||||
}
|
||||
|
||||
public void addLoanCharge(final LoanCharge loanCharge) {
|
||||
|
||||
@@ -545,7 +554,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
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 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 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";
|
||||
if (command.isChangeInStringParameterNamed(externalIdParamName, this.externalId)) {
|
||||
final String newValue = command.stringValueOfParameterNamed(externalIdParamName);
|
||||
@@ -658,6 +674,35 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
this.interestChargedFromDate = null;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -715,6 +760,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
LoanStatus statusEnum = lifecycleStateMachine.transition(LoanEvent.LOAN_CREATED, from);
|
||||
this.loanStatus = statusEnum.getValue();
|
||||
|
||||
this.externalId = externalId;
|
||||
|
||||
this.termFrequency = loanSchedule.getLoanTermFrequency();
|
||||
this.termPeriodFrequencyType = loanSchedule.getLoanTermPeriodFrequencyType().getValue();
|
||||
|
||||
@@ -749,8 +796,6 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
for (LoanCharge loanCharge : getNullPointerSafeLoanCharges()) {
|
||||
validateChargeHasValidSpecifiedDateIfApplicable(loanCharge, getDisbursementDate(), getLastRepaymentPeriodDueDate());
|
||||
}
|
||||
|
||||
this.externalId = externalId;
|
||||
}
|
||||
|
||||
private LocalDate determineExpectedMaturityDate() {
|
||||
@@ -1946,8 +1991,13 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
if (this.client != null) {
|
||||
officeId = this.client.getOffice().getId();
|
||||
} else {
|
||||
// officeId = this.group.getOffice().getId();
|
||||
// officeId = this.group.getOffice().getId();
|
||||
}
|
||||
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
|
||||
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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
|
||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanSchedule;
|
||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.query.CalculateLoanScheduleQuery;
|
||||
import org.mifosplatform.portfolio.loanaccount.serialization.CalculateLoanScheduleQueryFromApiJsonDeserializer;
|
||||
import org.mifosplatform.portfolio.loanaccount.serialization.CalculateLoanScheduleQueryFromApiJsonHelper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -17,12 +12,12 @@ import org.springframework.stereotype.Service;
|
||||
public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleCalculationPlatformService {
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final CalculateLoanScheduleQueryFromApiJsonDeserializer fromApiJsonDeserializer;
|
||||
private final CalculateLoanScheduleQueryFromApiJsonHelper fromApiJsonDeserializer;
|
||||
private final LoanScheduleAssembler loanScheduleAssembler;
|
||||
|
||||
@Autowired
|
||||
public LoanScheduleCalculationPlatformServiceImpl(final PlatformSecurityContext context,
|
||||
final CalculateLoanScheduleQueryFromApiJsonDeserializer fromApiJsonDeserializer,
|
||||
final CalculateLoanScheduleQueryFromApiJsonHelper fromApiJsonDeserializer,
|
||||
final LoanScheduleAssembler loanScheduleAssembler) {
|
||||
this.context = context;
|
||||
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
||||
@@ -33,12 +28,7 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
|
||||
public LoanScheduleData calculateLoanSchedule(final JsonQuery query) {
|
||||
context.authenticatedUser();
|
||||
|
||||
final CalculateLoanScheduleQuery calculateLoanScheduleQuery = this.fromApiJsonDeserializer.commandFromApiJson(query.json());
|
||||
final List<ApiParameterError> dataValidationErrors = calculateLoanScheduleQuery.validate();
|
||||
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors);
|
||||
}
|
||||
this.fromApiJsonDeserializer.validate(query.json());
|
||||
|
||||
final LoanSchedule loanSchedule = this.loanScheduleAssembler.fromJson(query.parsedJson());
|
||||
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;
|
||||
}
|
||||
}
|
||||
+122
-101
@@ -1,6 +1,5 @@
|
||||
package org.mifosplatform.portfolio.loanaccount.service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -10,20 +9,21 @@ import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
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.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.security.exception.NoAuthorizationException;
|
||||
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.ClientRepository;
|
||||
import org.mifosplatform.portfolio.client.domain.Note;
|
||||
import org.mifosplatform.portfolio.client.domain.NoteRepository;
|
||||
import org.mifosplatform.portfolio.client.exception.ClientNotFoundException;
|
||||
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.domain.DefaultLoanLifecycleStateMachine;
|
||||
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.loanschedule.data.LoanScheduleData;
|
||||
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.serialization.CalculateLoanScheduleQueryFromApiJsonDeserializer;
|
||||
import org.mifosplatform.portfolio.loanaccount.serialization.LoanApplicationCommandFromApiJsonDeserializer;
|
||||
import org.mifosplatform.portfolio.loanaccount.serialization.LoanApplicationCommandFromApiJsonHelper;
|
||||
import org.mifosplatform.portfolio.loanaccount.serialization.LoanStateTransitionCommandFromApiJsonDeserializer;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
|
||||
import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -54,10 +55,11 @@ import com.google.gson.JsonElement;
|
||||
@Service
|
||||
public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements LoanApplicationWritePlatformService {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(LoanApplicationWritePlatformServiceJpaRepositoryImpl.class);
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final FromJsonHelper fromJsonHelper;
|
||||
private final LoanApplicationCommandFromApiJsonDeserializer fromApiJsonDeserializer;
|
||||
private final CalculateLoanScheduleQueryFromApiJsonDeserializer calculateLoanScheduleQueryFromApiJsonDeserializer;
|
||||
private final LoanApplicationCommandFromApiJsonHelper fromApiJsonDeserializer;
|
||||
private final LoanStateTransitionCommandFromApiJsonDeserializer loanStateTransitionCommandFromApiJsonDeserializer;
|
||||
private final LoanRepository loanRepository;
|
||||
private final NoteRepository noteRepository;
|
||||
@@ -67,21 +69,20 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
private final LoanProductRepository loanProductRepository;
|
||||
private final LoanChargeAssembler loanChargeAssembler;
|
||||
private final AprCalculator aprCalculator;
|
||||
private final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory;
|
||||
|
||||
@Autowired
|
||||
public LoanApplicationWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final FromJsonHelper fromJsonHelper,
|
||||
final LoanApplicationCommandFromApiJsonDeserializer fromApiJsonDeserializer,
|
||||
final LoanApplicationCommandFromApiJsonHelper fromApiJsonDeserializer,
|
||||
final LoanStateTransitionCommandFromApiJsonDeserializer loanStateTransitionCommandFromApiJsonDeserializer,
|
||||
final CalculateLoanScheduleQueryFromApiJsonDeserializer calculateLoanScheduleQueryFromApiJsonDeserializer,
|
||||
final AprCalculator aprCalculator, final LoanAssembler loanAssembler, final LoanChargeAssembler loanChargeAssembler,
|
||||
final LoanRepository loanRepository, final NoteRepository noteRepository,
|
||||
final LoanScheduleCalculationPlatformService calculationPlatformService, final ClientRepository clientRepository,
|
||||
final LoanProductRepository loanProductRepository) {
|
||||
final LoanProductRepository loanProductRepository, final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory) {
|
||||
this.context = context;
|
||||
this.fromJsonHelper = fromJsonHelper;
|
||||
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
||||
this.loanStateTransitionCommandFromApiJsonDeserializer = loanStateTransitionCommandFromApiJsonDeserializer;
|
||||
this.calculateLoanScheduleQueryFromApiJsonDeserializer = calculateLoanScheduleQueryFromApiJsonDeserializer;
|
||||
this.aprCalculator = aprCalculator;
|
||||
this.loanAssembler = loanAssembler;
|
||||
this.loanChargeAssembler = loanChargeAssembler;
|
||||
@@ -90,6 +91,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
this.calculationPlatformService = calculationPlatformService;
|
||||
this.clientRepository = clientRepository;
|
||||
this.loanProductRepository = loanProductRepository;
|
||||
this.accountIdentifierGeneratorFactory = accountIdentifierGeneratorFactory;
|
||||
}
|
||||
|
||||
private boolean isBeforeToday(final LocalDate date) {
|
||||
@@ -107,23 +109,19 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
|
||||
context.authenticatedUser();
|
||||
|
||||
final CalculateLoanScheduleQuery calculateLoanScheduleQuery = this.calculateLoanScheduleQueryFromApiJsonDeserializer
|
||||
.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); }
|
||||
this.fromApiJsonDeserializer.validateForCreate(command.json());
|
||||
|
||||
final Loan newLoanApplication = loanAssembler.assembleFrom(command);
|
||||
|
||||
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");
|
||||
if (StringUtils.isNotBlank(submittedOnNote)) {
|
||||
Note note = Note.loanNote(newLoanApplication, submittedOnNote);
|
||||
@@ -144,92 +142,115 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
@Override
|
||||
public CommandProcessingResult modifyLoanApplication(final Long loanId, final JsonCommand command) {
|
||||
|
||||
context.authenticatedUser();
|
||||
try {
|
||||
context.authenticatedUser();
|
||||
|
||||
final CalculateLoanScheduleQuery calculateLoanScheduleQuery = this.calculateLoanScheduleQueryFromApiJsonDeserializer
|
||||
.commandFromApiJson(command.json());
|
||||
final List<ApiParameterError> loanScheduleErrors = calculateLoanScheduleQuery.validate();
|
||||
this.fromApiJsonDeserializer.validateForModify(command.json());
|
||||
|
||||
final LoanApplicationCommand loanApplicationCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json());
|
||||
final List<ApiParameterError> loanApplicationErrors = loanApplicationCommand.validate();
|
||||
final Loan existingLoanApplication = retrieveLoanBy(loanId);
|
||||
|
||||
final List<ApiParameterError> combinedErrors = new ArrayList<ApiParameterError>(loanScheduleErrors);
|
||||
combinedErrors.addAll(loanApplicationErrors);
|
||||
final LoanChargeCommand[] charges = this.fromApiJsonDeserializer.extractLoanCharges(command.json());
|
||||
|
||||
if (!combinedErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
|
||||
"Validation errors exist.", combinedErrors); }
|
||||
final Map<String, Object> changes = existingLoanApplication.loanApplicationModification(command, charges, this.aprCalculator);
|
||||
|
||||
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(),
|
||||
this.aprCalculator);
|
||||
existingLoanApplication.updateClient(client);
|
||||
}
|
||||
|
||||
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 String productIdParamName = "productId";
|
||||
if (changes.containsKey(productIdParamName)) {
|
||||
final Long productId = command.longValueOfParameterNamed(productIdParamName);
|
||||
final LoanProduct loanProduct = this.loanProductRepository.findOne(productId);
|
||||
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";
|
||||
if (changes.containsKey(productIdParamName)) {
|
||||
final Long productId = command.longValueOfParameterNamed(productIdParamName);
|
||||
final LoanProduct loanProduct = this.loanProductRepository.findOne(productId);
|
||||
if (loanProduct == null) { throw new LoanProductNotFoundException(productId); }
|
||||
|
||||
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.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();
|
||||
logAsErrorUnexpectedDataIntegrityException(dve);
|
||||
throw new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue",
|
||||
"Unknown data integrity issue with resource.");
|
||||
}
|
||||
|
||||
private void logAsErrorUnexpectedDataIntegrityException(final DataIntegrityViolationException dve) {
|
||||
logger.error(dve.getMessage(), dve);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
|
||||
+5
-4
@@ -81,6 +81,7 @@ public class LoanAssembler {
|
||||
|
||||
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 fundId = fromApiJsonHelper.extractLongNamed("fundId", element);
|
||||
final Long loanOfficerId = fromApiJsonHelper.extractLongNamed("loanOfficerId", element);
|
||||
@@ -96,7 +97,7 @@ public class LoanAssembler {
|
||||
final Set<LoanCharge> loanCharges = this.loanChargeAssembler.fromParsedJson(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;
|
||||
Client client = null;
|
||||
@@ -105,7 +106,7 @@ public class LoanAssembler {
|
||||
client = this.clientRepository.findOne(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);
|
||||
}
|
||||
|
||||
@@ -113,7 +114,7 @@ public class LoanAssembler {
|
||||
group = this.groupRepository.findOne(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);
|
||||
}
|
||||
|
||||
@@ -121,7 +122,7 @@ public class LoanAssembler {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
-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> {
|
||||
|
||||
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, "
|
||||
+ " c.office_id as clientOfficeId, g.id as groupId, g.name as groupName, g.office_id as groupOfficeId,"
|
||||
+ " l.submittedon_date as submittedOnDate,"
|
||||
@@ -391,75 +391,75 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
@Override
|
||||
public LoanBasicDetailsData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||
|
||||
String currencyCode = rs.getString("currencyCode");
|
||||
String currencyName = rs.getString("currencyName");
|
||||
String currencyNameCode = rs.getString("currencyNameCode");
|
||||
String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol");
|
||||
Integer currencyDigits = JdbcSupport.getInteger(rs, "currencyDigits");
|
||||
CurrencyData currencyData = new CurrencyData(currencyCode, currencyName, currencyDigits, currencyDisplaySymbol,
|
||||
final String currencyCode = rs.getString("currencyCode");
|
||||
final String currencyName = rs.getString("currencyName");
|
||||
final String currencyNameCode = rs.getString("currencyNameCode");
|
||||
final String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol");
|
||||
final Integer currencyDigits = JdbcSupport.getInteger(rs, "currencyDigits");
|
||||
final CurrencyData currencyData = new CurrencyData(currencyCode, currencyName, currencyDigits, currencyDisplaySymbol,
|
||||
currencyNameCode);
|
||||
|
||||
Long id = rs.getLong("id");
|
||||
String externalId = rs.getString("externalId");
|
||||
final Long id = rs.getLong("id");
|
||||
final String accountNo = rs.getString("accountNo");
|
||||
final String externalId = rs.getString("externalId");
|
||||
|
||||
Long clientId = JdbcSupport.getLong(rs, "clientId");
|
||||
Long clientOfficeId = JdbcSupport.getLong(rs, "clientOfficeId");
|
||||
;
|
||||
String clientName = rs.getString("clientName");
|
||||
final Long clientId = JdbcSupport.getLong(rs, "clientId");
|
||||
final Long clientOfficeId = JdbcSupport.getLong(rs, "clientOfficeId");
|
||||
final String clientName = rs.getString("clientName");
|
||||
|
||||
Long groupId = JdbcSupport.getLong(rs, "groupId");
|
||||
Long groupOfficeId = JdbcSupport.getLong(rs, "groupOfficeId");
|
||||
;
|
||||
String groupName = rs.getString("groupName");
|
||||
final Long groupId = JdbcSupport.getLong(rs, "groupId");
|
||||
final Long groupOfficeId = JdbcSupport.getLong(rs, "groupOfficeId");
|
||||
final String groupName = rs.getString("groupName");
|
||||
|
||||
Long fundId = JdbcSupport.getLong(rs, "fundId");
|
||||
String fundName = rs.getString("fundName");
|
||||
Long loanOfficerId = JdbcSupport.getLong(rs, "loanOfficerId");
|
||||
String loanOfficerName = rs.getString("loanOfficerName");
|
||||
Long loanProductId = JdbcSupport.getLong(rs, "loanProductId");
|
||||
String loanProductName = rs.getString("loanProductName");
|
||||
String loanProductDescription = rs.getString("loanProductDescription");
|
||||
final Long fundId = JdbcSupport.getLong(rs, "fundId");
|
||||
final String fundName = rs.getString("fundName");
|
||||
final Long loanOfficerId = JdbcSupport.getLong(rs, "loanOfficerId");
|
||||
final String loanOfficerName = rs.getString("loanOfficerName");
|
||||
final Long loanProductId = JdbcSupport.getLong(rs, "loanProductId");
|
||||
final String loanProductName = rs.getString("loanProductName");
|
||||
final String loanProductDescription = rs.getString("loanProductDescription");
|
||||
|
||||
LocalDate submittedOnDate = JdbcSupport.getLocalDate(rs, "submittedOnDate");
|
||||
LocalDate approvedOnDate = JdbcSupport.getLocalDate(rs, "approvedOnDate");
|
||||
LocalDate expectedDisbursementDate = JdbcSupport.getLocalDate(rs, "expectedDisbursementDate");
|
||||
LocalDate actualDisbursementDate = JdbcSupport.getLocalDate(rs, "actualDisbursementDate");
|
||||
LocalDate expectedFirstRepaymentOnDate = JdbcSupport.getLocalDate(rs, "expectedFirstRepaymentOnDate");
|
||||
LocalDate interestChargedFromDate = JdbcSupport.getLocalDate(rs, "interestChargedFromDate");
|
||||
LocalDate closedOnDate = JdbcSupport.getLocalDate(rs, "closedOnDate");
|
||||
LocalDate expectedMaturityDate = JdbcSupport.getLocalDate(rs, "expectedMaturityDate");
|
||||
final LocalDate submittedOnDate = JdbcSupport.getLocalDate(rs, "submittedOnDate");
|
||||
final LocalDate approvedOnDate = JdbcSupport.getLocalDate(rs, "approvedOnDate");
|
||||
final LocalDate expectedDisbursementDate = JdbcSupport.getLocalDate(rs, "expectedDisbursementDate");
|
||||
final LocalDate actualDisbursementDate = JdbcSupport.getLocalDate(rs, "actualDisbursementDate");
|
||||
final LocalDate expectedFirstRepaymentOnDate = JdbcSupport.getLocalDate(rs, "expectedFirstRepaymentOnDate");
|
||||
final LocalDate interestChargedFromDate = JdbcSupport.getLocalDate(rs, "interestChargedFromDate");
|
||||
final LocalDate closedOnDate = JdbcSupport.getLocalDate(rs, "closedOnDate");
|
||||
final LocalDate expectedMaturityDate = JdbcSupport.getLocalDate(rs, "expectedMaturityDate");
|
||||
|
||||
BigDecimal principal = rs.getBigDecimal("principal");
|
||||
BigDecimal inArrearsTolerance = rs.getBigDecimal("inArrearsTolerance");
|
||||
BigDecimal totalDisbursementCharges = rs.getBigDecimal("totalDisbursementCharges");
|
||||
final BigDecimal principal = rs.getBigDecimal("principal");
|
||||
final BigDecimal inArrearsTolerance = rs.getBigDecimal("inArrearsTolerance");
|
||||
final BigDecimal totalDisbursementCharges = rs.getBigDecimal("totalDisbursementCharges");
|
||||
|
||||
Integer numberOfRepayments = JdbcSupport.getInteger(rs, "numberOfRepayments");
|
||||
Integer repaymentEvery = JdbcSupport.getInteger(rs, "repaymentEvery");
|
||||
BigDecimal interestRatePerPeriod = rs.getBigDecimal("interestRatePerPeriod");
|
||||
BigDecimal annualInterestRate = rs.getBigDecimal("annualInterestRate");
|
||||
final Integer numberOfRepayments = JdbcSupport.getInteger(rs, "numberOfRepayments");
|
||||
final Integer repaymentEvery = JdbcSupport.getInteger(rs, "repaymentEvery");
|
||||
final BigDecimal interestRatePerPeriod = rs.getBigDecimal("interestRatePerPeriod");
|
||||
final BigDecimal annualInterestRate = rs.getBigDecimal("annualInterestRate");
|
||||
|
||||
Integer termFrequency = JdbcSupport.getInteger(rs, "termFrequency");
|
||||
Integer termPeriodFrequencyTypeInt = JdbcSupport.getInteger(rs, "termPeriodFrequencyType");
|
||||
EnumOptionData termPeriodFrequencyType = LoanEnumerations.termFrequencyType(termPeriodFrequencyTypeInt);
|
||||
final Integer termFrequency = JdbcSupport.getInteger(rs, "termFrequency");
|
||||
final Integer termPeriodFrequencyTypeInt = JdbcSupport.getInteger(rs, "termPeriodFrequencyType");
|
||||
final EnumOptionData termPeriodFrequencyType = LoanEnumerations.termFrequencyType(termPeriodFrequencyTypeInt);
|
||||
|
||||
int repaymentFrequencyTypeInt = JdbcSupport.getInteger(rs, "repaymentFrequencyType");
|
||||
EnumOptionData repaymentFrequencyType = LoanEnumerations.repaymentFrequencyType(repaymentFrequencyTypeInt);
|
||||
final int repaymentFrequencyTypeInt = JdbcSupport.getInteger(rs, "repaymentFrequencyType");
|
||||
final EnumOptionData repaymentFrequencyType = LoanEnumerations.repaymentFrequencyType(repaymentFrequencyTypeInt);
|
||||
|
||||
int interestRateFrequencyTypeInt = JdbcSupport.getInteger(rs, "interestRateFrequencyType");
|
||||
EnumOptionData interestRateFrequencyType = LoanEnumerations.interestRateFrequencyType(interestRateFrequencyTypeInt);
|
||||
final int interestRateFrequencyTypeInt = JdbcSupport.getInteger(rs, "interestRateFrequencyType");
|
||||
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");
|
||||
int interestTypeInt = JdbcSupport.getInteger(rs, "interestType");
|
||||
int interestCalculationPeriodTypeInt = JdbcSupport.getInteger(rs, "interestCalculationPeriodType");
|
||||
final int amortizationTypeInt = JdbcSupport.getInteger(rs, "amortizationType");
|
||||
final int interestTypeInt = JdbcSupport.getInteger(rs, "interestType");
|
||||
final int interestCalculationPeriodTypeInt = JdbcSupport.getInteger(rs, "interestCalculationPeriodType");
|
||||
|
||||
EnumOptionData amortizationType = LoanEnumerations.amortizationType(amortizationTypeInt);
|
||||
EnumOptionData interestType = LoanEnumerations.interestType(interestTypeInt);
|
||||
EnumOptionData interestCalculationPeriodType = LoanEnumerations.interestCalculationPeriodType(interestCalculationPeriodTypeInt);
|
||||
final EnumOptionData amortizationType = LoanEnumerations.amortizationType(amortizationTypeInt);
|
||||
final EnumOptionData interestType = LoanEnumerations.interestType(interestTypeInt);
|
||||
final EnumOptionData interestCalculationPeriodType = LoanEnumerations
|
||||
.interestCalculationPeriodType(interestCalculationPeriodTypeInt);
|
||||
|
||||
Integer lifeCycleStatusId = JdbcSupport.getInteger(rs, "lifeCycleStatusId");
|
||||
EnumOptionData status = LoanEnumerations.status(lifeCycleStatusId);
|
||||
final Integer lifeCycleStatusId = JdbcSupport.getInteger(rs, "lifeCycleStatusId");
|
||||
final EnumOptionData status = LoanEnumerations.status(lifeCycleStatusId);
|
||||
|
||||
LocalDate lifeCycleStatusDate = submittedOnDate;
|
||||
if (approvedOnDate != null) {
|
||||
@@ -473,8 +473,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
}
|
||||
|
||||
Collection<LoanChargeData> charges = null;
|
||||
return new LoanBasicDetailsData(id, externalId, clientId, clientName, clientOfficeId, groupId, groupName, groupOfficeId,
|
||||
loanProductId, loanProductName, loanProductDescription, fundId, fundName, closedOnDate, submittedOnDate,
|
||||
return new LoanBasicDetailsData(id, accountNo, externalId, clientId, clientName, clientOfficeId, groupId, groupName,
|
||||
groupOfficeId, loanProductId, loanProductName, loanProductDescription, fundId, fundName, closedOnDate, submittedOnDate,
|
||||
approvedOnDate, expectedDisbursementDate, actualDisbursementDate, expectedMaturityDate, expectedFirstRepaymentOnDate,
|
||||
interestChargedFromDate, currencyData, principal, inArrearsTolerance, numberOfRepayments, repaymentEvery,
|
||||
interestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType,
|
||||
|
||||
Reference in New Issue
Block a user