update api-docs and loan functionality from api.
This commit is contained in:
+22
-4
@@ -9,8 +9,8 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Used to process the query parameters provided in a API request to see features of
|
||||
* the RESTful API are being asked for such as:
|
||||
* Used to process the query parameters provided in a API request to see
|
||||
* features of the RESTful API are being asked for such as:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>Pretty printing through pretty=true, defaults to false</li>
|
||||
@@ -21,6 +21,23 @@ import org.springframework.stereotype.Component;
|
||||
@Component
|
||||
public class ApiRequestParameterHelper {
|
||||
|
||||
public ApiRequestJsonSerializationSettings process(final MultivaluedMap<String, String> queryParameters,
|
||||
final Set<String> mandatoryResponseParameters) {
|
||||
|
||||
Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(queryParameters);
|
||||
if (!responseParameters.isEmpty()) {
|
||||
responseParameters.addAll(mandatoryResponseParameters);
|
||||
}
|
||||
final boolean prettyPrint = ApiParameterHelper.prettyPrint(queryParameters);
|
||||
final boolean template = ApiParameterHelper.template(queryParameters);
|
||||
final Long commandId = ApiParameterHelper.commandId(queryParameters);
|
||||
final boolean makerCheckerable = ApiParameterHelper.makerCheckerable(queryParameters);
|
||||
final boolean includeJson = ApiParameterHelper.includeJson(queryParameters);
|
||||
|
||||
return ApiRequestJsonSerializationSettings
|
||||
.from(prettyPrint, responseParameters, template, commandId, makerCheckerable, includeJson);
|
||||
}
|
||||
|
||||
public ApiRequestJsonSerializationSettings process(final MultivaluedMap<String, String> queryParameters) {
|
||||
|
||||
final Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(queryParameters);
|
||||
@@ -29,7 +46,8 @@ public class ApiRequestParameterHelper {
|
||||
final Long commandId = ApiParameterHelper.commandId(queryParameters);
|
||||
final boolean makerCheckerable = ApiParameterHelper.makerCheckerable(queryParameters);
|
||||
final boolean includeJson = ApiParameterHelper.includeJson(queryParameters);
|
||||
|
||||
return ApiRequestJsonSerializationSettings.from(prettyPrint, responseParameters, template, commandId, makerCheckerable, includeJson);
|
||||
|
||||
return ApiRequestJsonSerializationSettings
|
||||
.from(prettyPrint, responseParameters, template, commandId, makerCheckerable, includeJson);
|
||||
}
|
||||
}
|
||||
+4
-3
@@ -25,8 +25,9 @@ public class CreateDatatableEntryCommandHandler implements NewCommandSourceHandl
|
||||
|
||||
this.writePlatformService.newDatatableEntry(command.entityName(), command.getApptableId(), command);
|
||||
|
||||
// FIXME - kw - need to find office and either group/client/loan that
|
||||
// this datatable is against.
|
||||
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(command.getApptableId()).build();
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(command.getApptableId()) //
|
||||
.build();
|
||||
}
|
||||
}
|
||||
+635
-817
File diff suppressed because it is too large
Load Diff
+14
-4
@@ -76,10 +76,11 @@ public class LoansApiResource {
|
||||
"annualInterestRate", "repaymentFrequencyType", "interestRateFrequencyType", "amortizationType", "interestType",
|
||||
"interestCalculationPeriodType", "submittedOnDate", "approvedOnDate", "expectedDisbursementDate", "actualDisbursementDate",
|
||||
"expectedFirstRepaymentOnDate", "interestChargedFromDate", "closedOnDate", "expectedMaturityDate", "status",
|
||||
"lifeCycleStatusDate", "repaymentSchedule", "transactions", "permissions", "convenienceData", "charges", "productOptions",
|
||||
"lifeCycleStatusDate", "repaymentSchedule", "transactions", "permissions", "convenienceData", "charges", "guarantor", "productOptions",
|
||||
"amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions", "repaymentFrequencyTypeOptions",
|
||||
"interestRateFrequencyTypeOptions", "fundOptions", "repaymentStrategyOptions", "chargeOptions", "loanOfficerId",
|
||||
"loanOfficerName", "loanOfficerOptions", "chargeTemplate"));
|
||||
"loanOfficerName", "loanOfficerOptions", "chargeTemplate", "transactionProcessingStrategyId",
|
||||
"termFrequency", "termPeriodFrequencyType"));
|
||||
|
||||
private final String resourceNameForPermissions = "LOAN";
|
||||
|
||||
@@ -201,6 +202,7 @@ public class LoansApiResource {
|
||||
Collection<LoanChargeData> charges = null;
|
||||
Collection<GuarantorData> guarantors = null;
|
||||
|
||||
final Set<String> mandatoryResponseParameters = new HashSet<String>();
|
||||
boolean convenienceDataRequired = false;
|
||||
final Set<String> associationParameters = ApiParameterHelper.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters());
|
||||
if (!associationParameters.isEmpty()) {
|
||||
@@ -211,6 +213,7 @@ public class LoansApiResource {
|
||||
}
|
||||
|
||||
if (associationParameters.contains("guarantor")) {
|
||||
mandatoryResponseParameters.add("guarantor");
|
||||
guarantors = this.guarantorReadPlatformService.retrieveGuarantorsForLoan(loanId);
|
||||
if (CollectionUtils.isEmpty(guarantors)) {
|
||||
guarantors = null; // set back to null so doesn't appear in JSON
|
||||
@@ -218,6 +221,7 @@ public class LoansApiResource {
|
||||
}
|
||||
|
||||
if (associationParameters.contains("transactions")) {
|
||||
mandatoryResponseParameters.add("transactions");
|
||||
final Collection<LoanTransactionData> currentLoanRepayments = this.loanReadPlatformService.retrieveLoanTransactions(loanId);
|
||||
if (!CollectionUtils.isEmpty(currentLoanRepayments)) {
|
||||
loanRepayments = currentLoanRepayments;
|
||||
@@ -226,6 +230,10 @@ public class LoansApiResource {
|
||||
|
||||
if (associationParameters.contains("repaymentSchedule") || associationParameters.contains("permissions")) {
|
||||
|
||||
if (associationParameters.contains("repaymentSchedule")) {
|
||||
mandatoryResponseParameters.add("repaymentSchedule");
|
||||
}
|
||||
|
||||
DisbursementData singleDisbursement = loanBasicDetails.toDisburementData();
|
||||
repaymentSchedule = this.loanReadPlatformService.retrieveRepaymentSchedule(loanId, loanBasicDetails.getCurrency(),
|
||||
singleDisbursement, loanBasicDetails.getTotalDisbursementCharges(), loanBasicDetails.getInArrearsTolerance());
|
||||
@@ -236,7 +244,8 @@ public class LoansApiResource {
|
||||
if (associationParameters.contains("permissions")) {
|
||||
|
||||
if (repaymentSchedule == null) { throw new IllegalStateException(); }
|
||||
|
||||
mandatoryResponseParameters.add("permissions");
|
||||
|
||||
// FIXME - KW - Waive feature was changed to waive interest at
|
||||
// anytime so this permission checking is probably not needed -
|
||||
// look into.
|
||||
@@ -259,6 +268,7 @@ public class LoansApiResource {
|
||||
}
|
||||
|
||||
if (associationParameters.contains("charges")) {
|
||||
mandatoryResponseParameters.add("charges");
|
||||
charges = this.loanChargeReadPlatformService.retrieveLoanCharges(loanId);
|
||||
if (CollectionUtils.isEmpty(charges)) {
|
||||
charges = null; // set back to null so doesnt appear in JSON
|
||||
@@ -302,7 +312,7 @@ public class LoansApiResource {
|
||||
repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions,
|
||||
interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, null, guarantors);
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters(), mandatoryResponseParameters);
|
||||
return this.toApiJsonSerializer.serialize(settings, loanAccount, LOAN_DATA_PARAMETERS);
|
||||
}
|
||||
|
||||
|
||||
+98
-100
@@ -4,113 +4,111 @@ import java.util.List;
|
||||
|
||||
public class DefaultLoanLifecycleStateMachine implements LoanLifecycleStateMachine {
|
||||
|
||||
private final List<LoanStatus> allowedLoanStatuses;
|
||||
private final List<LoanStatus> allowedLoanStatuses;
|
||||
|
||||
public DefaultLoanLifecycleStateMachine(List<LoanStatus> allowedLoanStatuses) {
|
||||
this.allowedLoanStatuses = allowedLoanStatuses;
|
||||
}
|
||||
public DefaultLoanLifecycleStateMachine(List<LoanStatus> allowedLoanStatuses) {
|
||||
this.allowedLoanStatuses = allowedLoanStatuses;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoanStatus transition(LoanEvent loanEvent, LoanStatus from) {
|
||||
@Override
|
||||
public LoanStatus transition(LoanEvent loanEvent, LoanStatus from) {
|
||||
|
||||
LoanStatus newState = null;
|
||||
LoanStatus newState = from;
|
||||
|
||||
switch (loanEvent) {
|
||||
case LOAN_CREATED:
|
||||
if (from == null) {
|
||||
newState = stateOf(LoanStatus.SUBMITED_AND_PENDING_APPROVAL,
|
||||
allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case LOAN_REJECTED:
|
||||
if (from.hasStateOf(LoanStatus.SUBMITED_AND_PENDING_APPROVAL)) {
|
||||
newState = stateOf(LoanStatus.REJECTED, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case LOAN_APPROVED:
|
||||
if (from.hasStateOf(LoanStatus.SUBMITED_AND_PENDING_APPROVAL)) {
|
||||
newState = stateOf(LoanStatus.APPROVED, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case LOAN_WITHDRAWN:
|
||||
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.SUBMITED_AND_PENDING_APPROVAL, LoanStatus.APPROVED)) {
|
||||
newState = stateOf(LoanStatus.WITHDRAWN_BY_CLIENT, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case LOAN_DISBURSED:
|
||||
if (from.hasStateOf(LoanStatus.APPROVED)) {
|
||||
newState = stateOf(LoanStatus.ACTIVE, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case LOAN_APPROVAL_UNDO:
|
||||
if (from.hasStateOf(LoanStatus.APPROVED)) {
|
||||
newState = stateOf(LoanStatus.SUBMITED_AND_PENDING_APPROVAL, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case LOAN_DISBURSAL_UNDO:
|
||||
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE)) {
|
||||
newState = stateOf(LoanStatus.APPROVED, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case LOAN_REPAYMENT_OR_WAIVER:
|
||||
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE, LoanStatus.CLOSED_OBLIGATIONS_MET, LoanStatus.OVERPAID)) {
|
||||
newState = stateOf(LoanStatus.ACTIVE, allowedLoanStatuses);
|
||||
} else {
|
||||
newState = from;
|
||||
}
|
||||
break;
|
||||
case REPAID_IN_FULL:
|
||||
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE, LoanStatus.OVERPAID)) {
|
||||
newState = stateOf(LoanStatus.CLOSED_OBLIGATIONS_MET, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case WRITE_OFF_OUTSTANDING:
|
||||
if (this.anyOfAllowedWhenComingFrom(from,LoanStatus.ACTIVE)) {
|
||||
newState = stateOf(LoanStatus.CLOSED_WRITTEN_OFF, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case LOAN_RESCHEDULE:
|
||||
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE)) {
|
||||
newState = stateOf(LoanStatus.CLOSED_RESCHEDULE_OUTSTANDING_AMOUNT, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case INTERST_REBATE_OWED:
|
||||
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.CLOSED_OBLIGATIONS_MET)) {
|
||||
newState = stateOf(LoanStatus.CLOSED_OBLIGATIONS_MET, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case LOAN_OVERPAYMENT:
|
||||
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.CLOSED_OBLIGATIONS_MET, LoanStatus.ACTIVE)) {
|
||||
newState = stateOf(LoanStatus.OVERPAID, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
}
|
||||
switch (loanEvent) {
|
||||
case LOAN_CREATED:
|
||||
if (from == null) {
|
||||
newState = stateOf(LoanStatus.SUBMITED_AND_PENDING_APPROVAL, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case LOAN_REJECTED:
|
||||
if (from.hasStateOf(LoanStatus.SUBMITED_AND_PENDING_APPROVAL)) {
|
||||
newState = stateOf(LoanStatus.REJECTED, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case LOAN_APPROVED:
|
||||
if (from.hasStateOf(LoanStatus.SUBMITED_AND_PENDING_APPROVAL)) {
|
||||
newState = stateOf(LoanStatus.APPROVED, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case LOAN_WITHDRAWN:
|
||||
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.SUBMITED_AND_PENDING_APPROVAL, LoanStatus.APPROVED)) {
|
||||
newState = stateOf(LoanStatus.WITHDRAWN_BY_CLIENT, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case LOAN_DISBURSED:
|
||||
if (from.hasStateOf(LoanStatus.APPROVED)) {
|
||||
newState = stateOf(LoanStatus.ACTIVE, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case LOAN_APPROVAL_UNDO:
|
||||
if (from.hasStateOf(LoanStatus.APPROVED)) {
|
||||
newState = stateOf(LoanStatus.SUBMITED_AND_PENDING_APPROVAL, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case LOAN_DISBURSAL_UNDO:
|
||||
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE)) {
|
||||
newState = stateOf(LoanStatus.APPROVED, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case LOAN_REPAYMENT_OR_WAIVER:
|
||||
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE, LoanStatus.CLOSED_OBLIGATIONS_MET, LoanStatus.OVERPAID)) {
|
||||
newState = stateOf(LoanStatus.ACTIVE, allowedLoanStatuses);
|
||||
} else {
|
||||
newState = from;
|
||||
}
|
||||
break;
|
||||
case REPAID_IN_FULL:
|
||||
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE, LoanStatus.OVERPAID)) {
|
||||
newState = stateOf(LoanStatus.CLOSED_OBLIGATIONS_MET, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case WRITE_OFF_OUTSTANDING:
|
||||
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE)) {
|
||||
newState = stateOf(LoanStatus.CLOSED_WRITTEN_OFF, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case LOAN_RESCHEDULE:
|
||||
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE)) {
|
||||
newState = stateOf(LoanStatus.CLOSED_RESCHEDULE_OUTSTANDING_AMOUNT, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case INTERST_REBATE_OWED:
|
||||
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.CLOSED_OBLIGATIONS_MET)) {
|
||||
newState = stateOf(LoanStatus.CLOSED_OBLIGATIONS_MET, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case LOAN_OVERPAYMENT:
|
||||
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.CLOSED_OBLIGATIONS_MET, LoanStatus.ACTIVE)) {
|
||||
newState = stateOf(LoanStatus.OVERPAID, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return newState;
|
||||
}
|
||||
return newState;
|
||||
}
|
||||
|
||||
private LoanStatus stateOf(LoanStatus state, List<LoanStatus> allowedLoanStatuses) {
|
||||
LoanStatus match = null;
|
||||
for (LoanStatus loanStatus : allowedLoanStatuses) {
|
||||
if (loanStatus.hasStateOf(state)) {
|
||||
match = loanStatus;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return match;
|
||||
}
|
||||
private LoanStatus stateOf(LoanStatus state, List<LoanStatus> allowedLoanStatuses) {
|
||||
LoanStatus match = null;
|
||||
for (LoanStatus loanStatus : allowedLoanStatuses) {
|
||||
if (loanStatus.hasStateOf(state)) {
|
||||
match = loanStatus;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
private boolean anyOfAllowedWhenComingFrom(final LoanStatus state,
|
||||
final LoanStatus... allowedStates) {
|
||||
boolean allowed = false;
|
||||
private boolean anyOfAllowedWhenComingFrom(final LoanStatus state, final LoanStatus... allowedStates) {
|
||||
boolean allowed = false;
|
||||
|
||||
for (LoanStatus allowedState : allowedStates) {
|
||||
if (state.hasStateOf(allowedState)) {
|
||||
allowed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (LoanStatus allowedState : allowedStates) {
|
||||
if (state.hasStateOf(allowedState)) {
|
||||
allowed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return allowed;
|
||||
}
|
||||
return allowed;
|
||||
}
|
||||
}
|
||||
+101
-100
@@ -803,32 +803,32 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
if (!statusEnum.hasStateOf(LoanStatus.fromInt(this.loanStatus))) {
|
||||
this.loanStatus = statusEnum.getValue();
|
||||
actualChanges.put("status", LoanEnumerations.status(this.loanStatus));
|
||||
}
|
||||
|
||||
LocalDate rejectedOn = command.localDateValueOfParameterNamed("rejectedOnDate");
|
||||
if (rejectedOn == null) {
|
||||
rejectedOn = command.localDateValueOfParameterNamed("eventDate");
|
||||
}
|
||||
|
||||
LocalDate rejectedOn = command.localDateValueOfParameterNamed("rejectedOnDate");
|
||||
if (rejectedOn == null) {
|
||||
rejectedOn = command.localDateValueOfParameterNamed("eventDate");
|
||||
}
|
||||
final Locale locale = new Locale(command.locale());
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
|
||||
final Locale locale = new Locale(command.locale());
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
this.rejectedOnDate = rejectedOn.toDate();
|
||||
this.closedOnDate = rejectedOn.toDate();
|
||||
actualChanges.put("locale", command.locale());
|
||||
actualChanges.put("dateFormat", command.dateFormat());
|
||||
actualChanges.put("rejectedOnDate", rejectedOn.toString(fmt));
|
||||
actualChanges.put("closedOnDate", rejectedOn.toString(fmt));
|
||||
|
||||
this.rejectedOnDate = rejectedOn.toDate();
|
||||
this.closedOnDate = rejectedOn.toDate();
|
||||
actualChanges.put("locale", command.locale());
|
||||
actualChanges.put("dateFormat", command.dateFormat());
|
||||
actualChanges.put("rejectedOnDate", rejectedOn.toString(fmt));
|
||||
actualChanges.put("closedOnDate", rejectedOn.toString(fmt));
|
||||
|
||||
if (rejectedOn.isBefore(getSubmittedOnDate())) {
|
||||
final String errorMessage = "The date on which a loan is rejected cannot be before its submittal date: "
|
||||
+ getSubmittedOnDate().toString();
|
||||
throw new InvalidLoanStateTransitionException("reject", "cannot.be.before.submittal.date", errorMessage, rejectedOn,
|
||||
getSubmittedOnDate());
|
||||
}
|
||||
if (rejectedOn.isAfter(new LocalDate())) {
|
||||
final String errorMessage = "The date on which a loan is rejected cannot be in the future.";
|
||||
throw new InvalidLoanStateTransitionException("reject", "cannot.be.a.future.date", errorMessage, rejectedOn);
|
||||
if (rejectedOn.isBefore(getSubmittedOnDate())) {
|
||||
final String errorMessage = "The date on which a loan is rejected cannot be before its submittal date: "
|
||||
+ getSubmittedOnDate().toString();
|
||||
throw new InvalidLoanStateTransitionException("reject", "cannot.be.before.submittal.date", errorMessage, rejectedOn,
|
||||
getSubmittedOnDate());
|
||||
}
|
||||
if (rejectedOn.isAfter(new LocalDate())) {
|
||||
final String errorMessage = "The date on which a loan is rejected cannot be in the future.";
|
||||
throw new InvalidLoanStateTransitionException("reject", "cannot.be.a.future.date", errorMessage, rejectedOn);
|
||||
}
|
||||
}
|
||||
|
||||
return actualChanges;
|
||||
@@ -843,33 +843,33 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
if (!statusEnum.hasStateOf(LoanStatus.fromInt(this.loanStatus))) {
|
||||
this.loanStatus = statusEnum.getValue();
|
||||
actualChanges.put("status", LoanEnumerations.status(this.loanStatus));
|
||||
}
|
||||
|
||||
LocalDate withdrawnOn = command.localDateValueOfParameterNamed("withdrawnOnDate");
|
||||
if (withdrawnOn == null) {
|
||||
withdrawnOn = command.localDateValueOfParameterNamed("eventDate");
|
||||
}
|
||||
|
||||
LocalDate withdrawnOn = command.localDateValueOfParameterNamed("withdrawnOnDate");
|
||||
if (withdrawnOn == null) {
|
||||
withdrawnOn = command.localDateValueOfParameterNamed("eventDate");
|
||||
}
|
||||
final Locale locale = new Locale(command.locale());
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
|
||||
final Locale locale = new Locale(command.locale());
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
this.withdrawnOnDate = withdrawnOn.toDate();
|
||||
this.closedOnDate = withdrawnOn.toDate();
|
||||
actualChanges.put("locale", command.locale());
|
||||
actualChanges.put("dateFormat", command.dateFormat());
|
||||
actualChanges.put("withdrawnOnDate", withdrawnOn.toString(fmt));
|
||||
actualChanges.put("closedOnDate", withdrawnOn.toString(fmt));
|
||||
|
||||
this.withdrawnOnDate = withdrawnOn.toDate();
|
||||
this.closedOnDate = withdrawnOn.toDate();
|
||||
actualChanges.put("locale", command.locale());
|
||||
actualChanges.put("dateFormat", command.dateFormat());
|
||||
actualChanges.put("withdrawnOnDate", withdrawnOn.toString(fmt));
|
||||
actualChanges.put("closedOnDate", withdrawnOn.toString(fmt));
|
||||
if (withdrawnOn.isBefore(getSubmittedOnDate())) {
|
||||
final String errorMessage = "The date on which a loan is withdrawn cannot be before its submittal date: "
|
||||
+ getSubmittedOnDate().toString();
|
||||
throw new InvalidLoanStateTransitionException("reject", "cannot.be.before.submittal.date", errorMessage, command,
|
||||
getSubmittedOnDate());
|
||||
}
|
||||
|
||||
if (withdrawnOn.isBefore(getSubmittedOnDate())) {
|
||||
final String errorMessage = "The date on which a loan is withdrawn cannot be before its submittal date: "
|
||||
+ getSubmittedOnDate().toString();
|
||||
throw new InvalidLoanStateTransitionException("reject", "cannot.be.before.submittal.date", errorMessage, command,
|
||||
getSubmittedOnDate());
|
||||
}
|
||||
|
||||
if (withdrawnOn.isAfter(new LocalDate())) {
|
||||
final String errorMessage = "The date on which a loan is withdrawn cannot be in the future.";
|
||||
throw new InvalidLoanStateTransitionException("reject", "cannot.be.a.future.date", errorMessage, command);
|
||||
if (withdrawnOn.isAfter(new LocalDate())) {
|
||||
final String errorMessage = "The date on which a loan is withdrawn cannot be in the future.";
|
||||
throw new InvalidLoanStateTransitionException("reject", "cannot.be.a.future.date", errorMessage, command);
|
||||
}
|
||||
}
|
||||
|
||||
return actualChanges;
|
||||
@@ -883,34 +883,37 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
if (!statusEnum.hasStateOf(LoanStatus.fromInt(this.loanStatus))) {
|
||||
this.loanStatus = statusEnum.getValue();
|
||||
actualChanges.put("status", LoanEnumerations.status(this.loanStatus));
|
||||
}
|
||||
|
||||
// only do below if status has changed in the 'approval' case
|
||||
LocalDate approvedOn = command.localDateValueOfParameterNamed("approvedOnDate");
|
||||
String approvedOnDateChange = command.stringValueOfParameterNamed("approvedOnDate");
|
||||
if (approvedOn == null) {
|
||||
approvedOn = command.localDateValueOfParameterNamed("eventDate");
|
||||
approvedOnDateChange = command.stringValueOfParameterNamed("eventDate");
|
||||
}
|
||||
|
||||
LocalDate approvedOn = command.localDateValueOfParameterNamed("approvedOnDate");
|
||||
if (approvedOn == null) {
|
||||
approvedOn = command.localDateValueOfParameterNamed("eventDate");
|
||||
}
|
||||
this.approvedOnDate = approvedOn.toDate();
|
||||
actualChanges.put("locale", command.locale());
|
||||
actualChanges.put("dateFormat", command.dateFormat());
|
||||
actualChanges.put("approvedOnDate", approvedOnDateChange);
|
||||
|
||||
this.approvedOnDate = approvedOn.toDate();
|
||||
actualChanges.put("locale", command.locale());
|
||||
actualChanges.put("dateFormat", command.dateFormat());
|
||||
actualChanges.put("approvedOnDate", command.stringValueOfParameterNamed("approvedOnDate"));
|
||||
final LocalDate submittalDate = new LocalDate(this.submittedOnDate);
|
||||
if (approvedOn.isBefore(submittalDate)) {
|
||||
final String errorMessage = "The date on which a loan is approved cannot be before its submittal date: "
|
||||
+ submittalDate.toString();
|
||||
throw new InvalidLoanStateTransitionException("approval", "cannot.be.before.submittal.date", errorMessage, getApprovedOnDate(),
|
||||
submittalDate);
|
||||
}
|
||||
if (approvedOn.isAfter(new LocalDate())) {
|
||||
final String errorMessage = "The date on which a loan is approved cannot be in the future.";
|
||||
throw new InvalidLoanStateTransitionException("approval", "cannot.be.a.future.date", errorMessage, getApprovedOnDate());
|
||||
}
|
||||
|
||||
final LocalDate submittalDate = new LocalDate(this.submittedOnDate);
|
||||
if (approvedOn.isBefore(submittalDate)) {
|
||||
final String errorMessage = "The date on which a loan is approved cannot be before its submittal date: "
|
||||
+ submittalDate.toString();
|
||||
throw new InvalidLoanStateTransitionException("approval", "cannot.be.before.submittal.date", errorMessage, getApprovedOnDate(),
|
||||
submittalDate);
|
||||
}
|
||||
if (approvedOn.isAfter(new LocalDate())) {
|
||||
final String errorMessage = "The date on which a loan is approved cannot be in the future.";
|
||||
throw new InvalidLoanStateTransitionException("approval", "cannot.be.a.future.date", errorMessage, getApprovedOnDate());
|
||||
}
|
||||
|
||||
if (this.loanofficer != null) {
|
||||
final LoanOfficerAssignmentHistory loanOfficerAssignmentHistory = LoanOfficerAssignmentHistory.createNew(this,
|
||||
this.loanofficer, approvedOn);
|
||||
this.loanOfficerHistory.add(loanOfficerAssignmentHistory);
|
||||
if (this.loanofficer != null) {
|
||||
final LoanOfficerAssignmentHistory loanOfficerAssignmentHistory = LoanOfficerAssignmentHistory.createNew(this,
|
||||
this.loanofficer, approvedOn);
|
||||
this.loanOfficerHistory.add(loanOfficerAssignmentHistory);
|
||||
}
|
||||
}
|
||||
|
||||
return actualChanges;
|
||||
@@ -925,13 +928,13 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
if (!statusEnum.hasStateOf(currentStatus)) {
|
||||
this.loanStatus = statusEnum.getValue();
|
||||
actualChanges.put("status", LoanEnumerations.status(this.loanStatus));
|
||||
|
||||
this.approvedOnDate = null;
|
||||
actualChanges.put("approvedOnDate", "");
|
||||
|
||||
this.loanOfficerHistory.clear();
|
||||
}
|
||||
|
||||
this.approvedOnDate = null;
|
||||
actualChanges.put("approvedOnDate", "");
|
||||
|
||||
this.loanOfficerHistory.clear();
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
@@ -952,28 +955,28 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
if (!statusEnum.hasStateOf(LoanStatus.fromInt(this.loanStatus))) {
|
||||
this.loanStatus = statusEnum.getValue();
|
||||
actualChanges.put("status", LoanEnumerations.status(this.loanStatus));
|
||||
}
|
||||
|
||||
LocalDate disbursedOn = command.localDateValueOfParameterNamed("disbursedOnDate");
|
||||
if (disbursedOn == null) {
|
||||
disbursedOn = command.localDateValueOfParameterNamed("eventDate");
|
||||
}
|
||||
|
||||
LocalDate disbursedOn = command.localDateValueOfParameterNamed("disbursedOnDate");
|
||||
if (disbursedOn == null) {
|
||||
disbursedOn = command.localDateValueOfParameterNamed("eventDate");
|
||||
}
|
||||
final Locale locale = new Locale(command.locale());
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
|
||||
final Locale locale = new Locale(command.locale());
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
this.disbursedOnDate = disbursedOn.toDate();
|
||||
this.expectedMaturityDate = determineExpectedMaturityDate().toDate();
|
||||
|
||||
this.disbursedOnDate = disbursedOn.toDate();
|
||||
this.expectedMaturityDate = determineExpectedMaturityDate().toDate();
|
||||
actualChanges.put("locale", command.locale());
|
||||
actualChanges.put("dateFormat", command.dateFormat());
|
||||
actualChanges.put("disbursedOnDate", disbursedOn.toString(fmt));
|
||||
actualChanges.put("expectedMaturityDate", LocalDate.fromDateFields(this.expectedDisbursedOnDate).toString(fmt));
|
||||
|
||||
actualChanges.put("locale", command.locale());
|
||||
actualChanges.put("dateFormat", command.dateFormat());
|
||||
actualChanges.put("disbursedOnDate", disbursedOn.toString(fmt));
|
||||
actualChanges.put("expectedMaturityDate", LocalDate.fromDateFields(this.expectedDisbursedOnDate).toString(fmt));
|
||||
handleDisbursementTransaction(disbursedOn);
|
||||
|
||||
handleDisbursementTransaction(disbursedOn);
|
||||
|
||||
if (isRepaymentScheduleRegenerationRequiredForDisbursement(disbursedOn)) {
|
||||
regenerateRepaymentSchedule(currency);
|
||||
if (isRepaymentScheduleRegenerationRequiredForDisbursement(disbursedOn)) {
|
||||
regenerateRepaymentSchedule(currency);
|
||||
}
|
||||
}
|
||||
|
||||
return actualChanges;
|
||||
@@ -1067,19 +1070,17 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
if (!statusEnum.hasStateOf(currentStatus)) {
|
||||
this.loanStatus = statusEnum.getValue();
|
||||
actualChanges.put("status", LoanEnumerations.status(this.loanStatus));
|
||||
|
||||
this.approvedOnDate = null;
|
||||
actualChanges.put("disbursedOnDate", "");
|
||||
|
||||
updateLoanToPreDisbursalState();
|
||||
}
|
||||
|
||||
this.approvedOnDate = null;
|
||||
actualChanges.put("disbursedOnDate", "");
|
||||
|
||||
updateLoanToPreDisbursalState();
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
private void updateLoanToPreDisbursalState() {
|
||||
this.loanStatus = LoanStatus.APPROVED.getValue();
|
||||
|
||||
this.loanTransactions.clear();
|
||||
this.disbursedOnDate = null;
|
||||
|
||||
|
||||
+1
-2
@@ -2,6 +2,5 @@ package org.mifosplatform.portfolio.loanaccount.domain;
|
||||
|
||||
public interface LoanLifecycleStateMachine {
|
||||
|
||||
LoanStatus transition(LoanEvent loanEvent, LoanStatus from);
|
||||
|
||||
LoanStatus transition(LoanEvent loanEvent, LoanStatus from);
|
||||
}
|
||||
|
||||
+33
-25
@@ -294,13 +294,15 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
"User has no authority to approve loan with a date in the past."); }
|
||||
|
||||
final Map<String, Object> changes = loan.loanApplicationApproval(command, defaultLoanLifecycleStateMachine());
|
||||
this.loanRepository.save(loan);
|
||||
|
||||
final String noteText = command.stringValueOfParameterNamed("note");
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
Note note = Note.loanNote(loan, noteText);
|
||||
changes.put("note", noteText);
|
||||
this.noteRepository.save(note);
|
||||
if (!changes.isEmpty()) {
|
||||
this.loanRepository.save(loan);
|
||||
|
||||
final String noteText = command.stringValueOfParameterNamed("note");
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
Note note = Note.loanNote(loan, noteText);
|
||||
changes.put("note", noteText);
|
||||
this.noteRepository.save(note);
|
||||
}
|
||||
}
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
@@ -323,12 +325,14 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
final Loan loan = retrieveLoanBy(loanId);
|
||||
|
||||
final Map<String, Object> changes = loan.undoApproval(defaultLoanLifecycleStateMachine());
|
||||
this.loanRepository.save(loan);
|
||||
|
||||
String noteText = command.stringValueOfParameterNamed("note");
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
Note note = Note.loanNote(loan, noteText);
|
||||
this.noteRepository.save(note);
|
||||
if (!changes.isEmpty()) {
|
||||
this.loanRepository.save(loan);
|
||||
|
||||
String noteText = command.stringValueOfParameterNamed("note");
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
Note note = Note.loanNote(loan, noteText);
|
||||
this.noteRepository.save(note);
|
||||
}
|
||||
}
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
@@ -359,12 +363,14 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
"User has no authority to reject loan with a date in the past."); }
|
||||
|
||||
final Map<String, Object> changes = loan.loanApplicationRejection(command, defaultLoanLifecycleStateMachine());
|
||||
this.loanRepository.save(loan);
|
||||
|
||||
String noteText = command.stringValueOfParameterNamed("note");
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
Note note = Note.loanNote(loan, noteText);
|
||||
this.noteRepository.save(note);
|
||||
if (!changes.isEmpty()) {
|
||||
this.loanRepository.save(loan);
|
||||
|
||||
String noteText = command.stringValueOfParameterNamed("note");
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
Note note = Note.loanNote(loan, noteText);
|
||||
this.noteRepository.save(note);
|
||||
}
|
||||
}
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
@@ -395,12 +401,14 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
"User has no authority to mark loan as withdrawn by applicant with a date in the past."); }
|
||||
|
||||
final Map<String, Object> changes = loan.loanApplicationWithdrawnByApplicant(command, defaultLoanLifecycleStateMachine());
|
||||
this.loanRepository.save(loan);
|
||||
|
||||
String noteText = command.stringValueOfParameterNamed("note");
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
Note note = Note.loanNote(loan, noteText);
|
||||
this.noteRepository.save(note);
|
||||
if (!changes.isEmpty()) {
|
||||
this.loanRepository.save(loan);
|
||||
|
||||
String noteText = command.stringValueOfParameterNamed("note");
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
Note note = Note.loanNote(loan, noteText);
|
||||
this.noteRepository.save(note);
|
||||
}
|
||||
}
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
|
||||
+37
-33
@@ -121,35 +121,37 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(loan.getPrincpal().getCurrencyCode());
|
||||
|
||||
final Map<String, Object> changes = loan.disburse(command, defaultLoanLifecycleStateMachine(), currency);
|
||||
// variable stores Id's of all existing loan transactions (newly created
|
||||
// loan transactions would not have an Id before save)
|
||||
Set<Long> existingLoanTransactionIds = new HashSet<Long>();
|
||||
for(LoanTransaction loanTransaction:loan.getLoanTransactions()){
|
||||
if(!(loanTransaction.getId()==null)){
|
||||
existingLoanTransactionIds.add(loanTransaction.getId());
|
||||
}
|
||||
}
|
||||
this.loanRepository.save(loan);
|
||||
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
Note note = Note.loanNote(loan, noteText);
|
||||
this.noteRepository.save(note);
|
||||
}
|
||||
|
||||
// make a call to accounting
|
||||
if (loan.isAccountingEnabledOnLoanProduct()) {
|
||||
/***
|
||||
* Variable holds list of all newly created loan transactions during
|
||||
* this disbursal
|
||||
**/
|
||||
List<LoanTransaction> newLoanTransactions = new ArrayList<LoanTransaction>();
|
||||
for (LoanTransaction loanTransaction : loan.getLoanTransactions()) {
|
||||
if (!existingLoanTransactionIds.contains(loanTransaction.getId())) {
|
||||
newLoanTransactions.add(loanTransaction);
|
||||
if (!changes.isEmpty()) {
|
||||
// variable stores Id's of all existing loan transactions (newly created
|
||||
// loan transactions would not have an Id before save)
|
||||
final Set<Long> existingLoanTransactionIds = new HashSet<Long>();
|
||||
for(LoanTransaction loanTransaction:loan.getLoanTransactions()){
|
||||
if(!(loanTransaction.getId()==null)){
|
||||
existingLoanTransactionIds.add(loanTransaction.getId());
|
||||
}
|
||||
}
|
||||
LoanDTO loanDTO = populateLoanDTO(loan, newLoanTransactions);
|
||||
journalEntryWritePlatformService.createJournalEntriesForLoan(loanDTO);
|
||||
this.loanRepository.save(loan);
|
||||
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
Note note = Note.loanNote(loan, noteText);
|
||||
this.noteRepository.save(note);
|
||||
}
|
||||
|
||||
// make a call to accounting
|
||||
if (loan.isAccountingEnabledOnLoanProduct()) {
|
||||
/***
|
||||
* Variable holds list of all newly created loan transactions during
|
||||
* this disbursal
|
||||
**/
|
||||
List<LoanTransaction> newLoanTransactions = new ArrayList<LoanTransaction>();
|
||||
for (LoanTransaction loanTransaction : loan.getLoanTransactions()) {
|
||||
if (!existingLoanTransactionIds.contains(loanTransaction.getId())) {
|
||||
newLoanTransactions.add(loanTransaction);
|
||||
}
|
||||
}
|
||||
LoanDTO loanDTO = populateLoanDTO(loan, newLoanTransactions);
|
||||
journalEntryWritePlatformService.createJournalEntriesForLoan(loanDTO);
|
||||
}
|
||||
}
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
@@ -172,12 +174,14 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final Loan loan = retrieveLoanBy(loanId);
|
||||
|
||||
final Map<String, Object> changes = loan.undoDisbursal(defaultLoanLifecycleStateMachine());
|
||||
this.loanRepository.save(loan);
|
||||
|
||||
final String noteText = command.stringValueOfParameterNamed("note");
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
Note note = Note.loanNote(loan, noteText);
|
||||
this.noteRepository.save(note);
|
||||
if (!changes.isEmpty()) {
|
||||
this.loanRepository.save(loan);
|
||||
|
||||
final String noteText = command.stringValueOfParameterNamed("note");
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
Note note = Note.loanNote(loan, noteText);
|
||||
this.noteRepository.save(note);
|
||||
}
|
||||
}
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
|
||||
+1
-1
@@ -74,7 +74,7 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
final InterestMethod interestMethod = InterestMethod.fromInt(command.integerValueOfParameterNamed("interestType"));
|
||||
final InterestCalculationPeriodMethod interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(command
|
||||
.integerValueOfParameterNamed("interestCalculationPeriodType"));
|
||||
final AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.integerValueOfParameterNamed("interestType"));
|
||||
final AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.integerValueOfParameterNamed("amortizationType"));
|
||||
final PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.fromInt(command
|
||||
.integerValueOfParameterNamed("repaymentFrequencyType"));
|
||||
final PeriodFrequencyType interestFrequencyType = PeriodFrequencyType.fromInt(command
|
||||
|
||||
Reference in New Issue
Block a user