support submit new loan application and delete loan capabilities through api.

This commit is contained in:
Keith Woodlock
2012-05-16 18:21:36 +01:00
parent bf7783fc94
commit a006e60681
32 changed files with 1040 additions and 1118 deletions
@@ -1,16 +1,10 @@
package org.mifosng.ui;
import java.util.Collection;
import org.mifosng.data.EntityIdentifier;
import org.mifosng.data.LoanProductData;
import org.mifosng.data.LoanRepaymentData;
import org.mifosng.data.LoanSchedule;
import org.mifosng.data.command.AdjustLoanTransactionCommand;
import org.mifosng.data.command.CalculateLoanScheduleCommand;
import org.mifosng.data.command.LoanStateTransitionCommand;
import org.mifosng.data.command.LoanTransactionCommand;
import org.mifosng.data.command.SubmitLoanApplicationCommand;
import org.mifosng.data.command.UndoLoanApprovalCommand;
import org.mifosng.data.command.UndoLoanDisbursalCommand;
import org.springframework.security.oauth.consumer.ProtectedResourceDetails;
@@ -21,12 +15,6 @@ public interface CommonRestOperations {
void updateProtectedResource(ProtectedResourceDetails loadProtectedResourceDetailsById);
Collection<LoanProductData> retrieveAllLoanProducts();
LoanSchedule calculateLoanSchedule(CalculateLoanScheduleCommand command);
Long submitLoanApplication(SubmitLoanApplicationCommand command);
EntityIdentifier deleteLoan(Long loanId);
EntityIdentifier approveLoan(LoanStateTransitionCommand command);
@@ -2,7 +2,6 @@ package org.mifosng.ui;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.mifosng.configuration.ApplicationConfigurationService;
@@ -10,15 +9,10 @@ import org.mifosng.data.ClientList;
import org.mifosng.data.EntityIdentifier;
import org.mifosng.data.ErrorResponse;
import org.mifosng.data.ErrorResponseList;
import org.mifosng.data.LoanProductData;
import org.mifosng.data.LoanProductList;
import org.mifosng.data.LoanRepaymentData;
import org.mifosng.data.LoanSchedule;
import org.mifosng.data.command.AdjustLoanTransactionCommand;
import org.mifosng.data.command.CalculateLoanScheduleCommand;
import org.mifosng.data.command.LoanStateTransitionCommand;
import org.mifosng.data.command.LoanTransactionCommand;
import org.mifosng.data.command.SubmitLoanApplicationCommand;
import org.mifosng.data.command.UndoLoanApprovalCommand;
import org.mifosng.data.command.UndoLoanDisbursalCommand;
import org.mifosng.ui.loanproduct.ClientValidationException;
@@ -81,18 +75,6 @@ public class CommonRestOperationsImpl implements CommonRestOperations {
return requestEntity;
}
@Override
public Collection<LoanProductData> retrieveAllLoanProducts() {
URI restUri = URI.create(getBaseServerUrl().concat(
"api/protected/product/loan/all"));
ResponseEntity<LoanProductList> s = this.oauthRestServiceTemplate
.exchange(restUri, HttpMethod.GET, emptyRequest(),
LoanProductList.class);
return s.getBody().getProducts();
}
private ErrorResponseList parseErrors(HttpStatusCodeException e) {
XStream xstream = new XStream();
@@ -118,43 +100,6 @@ public class CommonRestOperationsImpl implements CommonRestOperations {
return errorList;
}
@Override
public LoanSchedule calculateLoanSchedule(
final CalculateLoanScheduleCommand command) {
try {
URI restUri = URI.create(getBaseServerUrl().concat(
"api/protected/loan/calculate"));
ResponseEntity<LoanSchedule> s = this.oauthRestServiceTemplate
.exchange(restUri, HttpMethod.POST,
calculateLoanRepaymentScheduleRequest(command),
LoanSchedule.class);
return s.getBody();
} catch (HttpStatusCodeException e) {
ErrorResponseList errorList = parseErrors(e);
throw new ClientValidationException(errorList.getErrors());
}
}
@Override
public Long submitLoanApplication(final SubmitLoanApplicationCommand command) {
try {
URI restUri = URI.create(getBaseServerUrl().concat(
"api/protected/loan/new"));
ResponseEntity<EntityIdentifier> s = this.oauthRestServiceTemplate
.postForEntity(restUri,
submitLoanApplicationRequest(command),
EntityIdentifier.class);
return s.getBody().getEntityId();
} catch (HttpStatusCodeException e) {
ErrorResponseList errorList = parseErrors(e);
throw new ClientValidationException(errorList.getErrors());
}
}
@Override
public EntityIdentifier deleteLoan(Long loanId) {
try {
@@ -437,24 +382,4 @@ public class CommonRestOperationsImpl implements CommonRestOperations {
return new HttpEntity<LoanStateTransitionCommand>(command,
requestHeaders);
}
private HttpEntity<SubmitLoanApplicationCommand> submitLoanApplicationRequest(
final SubmitLoanApplicationCommand command) {
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("Accept", "application/xml");
requestHeaders.set("Content-Type", "application/xml");
return new HttpEntity<SubmitLoanApplicationCommand>(command,
requestHeaders);
}
private HttpEntity<CalculateLoanScheduleCommand> calculateLoanRepaymentScheduleRequest(
final CalculateLoanScheduleCommand command) {
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("Accept", "application/xml");
requestHeaders.set("Content-Type", "application/xml");
return new HttpEntity<CalculateLoanScheduleCommand>(command,
requestHeaders);
}
}
@@ -13,6 +13,10 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* @deprecated - some initial work around cashflow for CreoCore that can be deleted later.
*/
@Deprecated
@Controller
public class CashflowController {
@@ -1,179 +0,0 @@
package org.mifosng.ui.loan;
import java.math.BigDecimal;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.mifosng.data.EntityIdentifier;
import org.mifosng.data.ErrorResponse;
import org.mifosng.data.LoanSchedule;
import org.mifosng.data.command.CalculateLoanScheduleCommand;
import org.mifosng.data.command.SubmitLoanApplicationCommand;
import org.mifosng.ui.CommonRestOperations;
import org.mifosng.ui.loanproduct.ClientValidationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class LoanController {
private final CommonRestOperations commonRestOperations;
@Autowired
public LoanController(final CommonRestOperations commonRestOperations) {
this.commonRestOperations = commonRestOperations;
}
@ExceptionHandler(AccessDeniedException.class)
public String accessDeniedException() {
return "unAuthorizedAction";
}
@ExceptionHandler(ClientValidationException.class)
public @ResponseBody Collection<ErrorResponse> validationException(ClientValidationException ex, HttpServletResponse response) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
response.setContentType("application/json");
return ex.getValidationErrors();
}
private LocalDate parseStringToLocalDate(String eventDate, String dateFieldIdentifier) {
LocalDate eventLocalDate = null;
if (StringUtils.isNotBlank(eventDate)) {
try {
Locale locale = LocaleContextHolder.getLocale();
eventLocalDate = DateTimeFormat.forPattern("dd MMMM yyyy").withLocale(locale).parseLocalDate(eventDate.toLowerCase(locale));
} catch (IllegalArgumentException e) {
List<ErrorResponse> validationErrors = new ArrayList<ErrorResponse>();
validationErrors.add(new ErrorResponse("validation.msg.invalid.date.format", dateFieldIdentifier, eventDate));
throw new ClientValidationException(validationErrors);
}
}
return eventLocalDate;
}
private BigDecimal parseStringToBigDecimal(String source) {
try {
BigDecimal number = null;
if (StringUtils.isNotBlank(source)) {
String sourceWithoutSpaces = source.replaceAll(" ", "");
Locale locale = LocaleContextHolder.getLocale();
NumberFormat format = NumberFormat.getNumberInstance(locale);
Number parsedNumber = format.parse(sourceWithoutSpaces);
number = BigDecimal.valueOf(Double.valueOf(parsedNumber
.doubleValue()));
}
return number;
} catch (ParseException e) {
List<ErrorResponse> validationErrors = new ArrayList<ErrorResponse>();
validationErrors.add(new ErrorResponse("validation.msg.invalid.number.format", "amount", source));
throw new ClientValidationException(validationErrors);
}
}
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/portfolio/client/{clientId}/loan/new", method = RequestMethod.POST)
public @ResponseBody EntityIdentifier submitNewLoanApplication(
@RequestParam(value="clientId", required=false) Long applicantId,
@RequestParam(value="productId", required=false) Long productId,
@RequestParam(value="submittedOnDate", required=false) String submittedOnDateStr,
@RequestParam(value="submittedOnNote", required=false) String submittedOnNote,
@RequestParam(value="currencyCode", required=false) String currencyCode,
@RequestParam(value="digitsAfterDecimal", required=false) Integer digitsAfterDecimal,
@RequestParam(value="principalMoney", required=false) String principalMoney,
@RequestParam(value="repaidEvery", required=false) Integer repaymentEvery,
@RequestParam(value="selectedRepaymentFrequencyOption", required=false) Integer repaymentFrequency,
@RequestParam(value="numberOfRepayments", required=false) Integer numberOfRepayments,
@RequestParam(value="selectedAmortizationMethodOption", required=false) Integer amortizationMethod,
@RequestParam(value="inArrearsTolerance", required=false) String inArrearsTolerance,
@RequestParam(value="nominalInterestRate", required=false) String nominalInterestRate,
@RequestParam(value="selectedInterestFrequencyOption", required=false) Integer interestRateFrequencyMethod,
@RequestParam(value="selectedInterestMethodOption", required=false) Integer interestMethod,
@RequestParam(value="interestRateCalculatedInPeriod", required=false) Integer interestRateCalculatedInPeriod,
@RequestParam(value="expectedDisbursementDate", required=false) String expectedDisbursementDateStr,
@RequestParam(value="repaymentsStartingFromDate", required=false) String repaymentsStartingFromDateStr,
@RequestParam(value="interestCalculatedFromDate", required=false) String interestCalculatedFromDateStr
) {
final LocalDate submittedOnDate = parseStringToLocalDate(submittedOnDateStr, "submittedOnDate");
final Number toleranceAmount = parseStringToBigDecimal(inArrearsTolerance);
final Number principal = parseStringToBigDecimal(principalMoney);
final Number interestRatePerPeriod = parseStringToBigDecimal(nominalInterestRate);
final boolean flexibleRepaymentSchedule = false;
final boolean interestRebateAllowed = false;
final LocalDate expectedDisbursementDate = parseStringToLocalDate(expectedDisbursementDateStr, "expectedDisbursementDate");
final LocalDate repaymentsStartingFromDate = parseStringToLocalDate(repaymentsStartingFromDateStr, "repaymentsStartingFromDate");
final LocalDate interestCalculatedFromDate = parseStringToLocalDate(interestCalculatedFromDateStr, "interestCalculatedFromDate");
CalculateLoanScheduleCommand calculateLoanScheduleCommand = new CalculateLoanScheduleCommand(currencyCode, digitsAfterDecimal, principal, interestRatePerPeriod,
interestRateFrequencyMethod, interestMethod, interestRateCalculatedInPeriod, repaymentEvery, repaymentFrequency, numberOfRepayments, amortizationMethod,
flexibleRepaymentSchedule, interestRebateAllowed, expectedDisbursementDate, repaymentsStartingFromDate, interestCalculatedFromDate);
LoanSchedule loanSchedule = this.commonRestOperations.calculateLoanSchedule(calculateLoanScheduleCommand);
SubmitLoanApplicationCommand command = new SubmitLoanApplicationCommand(applicantId, productId,
submittedOnDate, submittedOnNote, expectedDisbursementDate, repaymentsStartingFromDate, interestCalculatedFromDate,
loanSchedule, currencyCode, digitsAfterDecimal, principal,
interestRatePerPeriod, interestRateFrequencyMethod, interestMethod, interestRateCalculatedInPeriod,
repaymentEvery, repaymentFrequency, numberOfRepayments, amortizationMethod,
toleranceAmount, flexibleRepaymentSchedule, interestRebateAllowed);
Long identifier = this.commonRestOperations.submitLoanApplication(command);
return new EntityIdentifier(identifier);
}
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/portfolio/loanschedule/calculate", method = RequestMethod.POST)
public @ResponseBody LoanSchedule calculateLoanSchedule(
@RequestParam(value="currencyCode", required=false) String currencyCode,
@RequestParam(value="digitsAfterDecimal", required=false) Integer digitsAfterDecimal,
@RequestParam(value="principalMoney", required=false) String principalMoney,
@RequestParam(value="repaidEvery", required=false) Integer repaymentEvery,
@RequestParam(value="selectedRepaymentFrequencyOption", required=false) Integer repaymentFrequency,
@RequestParam(value="numberOfRepayments", required=false) Integer numberOfRepayments,
@RequestParam(value="selectedAmortizationMethodOption", required=false) Integer amortizationMethod,
@RequestParam(value="nominalInterestRate", required=false) String nominalInterestRate,
@RequestParam(value="selectedInterestFrequencyOption", required=false) Integer interestRateFrequencyMethod,
@RequestParam(value="selectedInterestMethodOption", required=false) Integer interestMethod,
@RequestParam(value="interestRateCalculatedInPeriod", required=false) Integer interestRateCalculatedInPeriod,
@RequestParam(value="expectedDisbursementDate", required=false) String expectedDisbursementDateStr,
@RequestParam(value="repaymentsStartingFromDate", required=false) String repaymentsStartingFromDateStr,
@RequestParam(value="interestCalculatedFromDate", required=false) String interestCalculatedFromDateStr
) {
final Number principal = parseStringToBigDecimal(principalMoney);
final Number interestRatePerPeriod = parseStringToBigDecimal(nominalInterestRate);
final boolean flexibleRepaymentSchedule = false;
final boolean interestRebateAllowed = false;
final LocalDate expectedDisbursementDate = parseStringToLocalDate(expectedDisbursementDateStr, "expectedDisbursementDate");
final LocalDate repaymentsStartingFromDate = parseStringToLocalDate(repaymentsStartingFromDateStr, "repaymentsStartingFromDate");
final LocalDate interestCalculatedFromDate = parseStringToLocalDate(interestCalculatedFromDateStr, "interestCalculatedFromDate");
CalculateLoanScheduleCommand command = new CalculateLoanScheduleCommand(currencyCode, digitsAfterDecimal, principal, interestRatePerPeriod,
interestRateFrequencyMethod, interestMethod, interestRateCalculatedInPeriod, repaymentEvery, repaymentFrequency, numberOfRepayments, amortizationMethod,
flexibleRepaymentSchedule, interestRebateAllowed, expectedDisbursementDate, repaymentsStartingFromDate, interestCalculatedFromDate);
return this.commonRestOperations.calculateLoanSchedule(command);
}
}