finish off integration of organisation admin functions in UI with backend services through cross origin request from jQuery.

This commit is contained in:
Keith Woodlock
2012-05-11 14:24:16 +01:00
parent 525831db04
commit f82c87de78
34 changed files with 544 additions and 1946 deletions
@@ -6,7 +6,6 @@ import java.util.Map;
import org.mifosng.data.AppUserData;
import org.mifosng.data.ClientData;
import org.mifosng.data.ClientDataWithAccountsData;
import org.mifosng.data.CurrencyData;
import org.mifosng.data.EntityIdentifier;
import org.mifosng.data.EnumOptionReadModel;
import org.mifosng.data.LoanAccountData;
@@ -15,23 +14,19 @@ import org.mifosng.data.LoanRepaymentData;
import org.mifosng.data.LoanSchedule;
import org.mifosng.data.NewLoanWorkflowStepOneData;
import org.mifosng.data.NoteData;
import org.mifosng.data.OfficeData;
import org.mifosng.data.PermissionData;
import org.mifosng.data.RoleData;
import org.mifosng.data.command.AdjustLoanTransactionCommand;
import org.mifosng.data.command.CalculateLoanScheduleCommand;
import org.mifosng.data.command.ChangePasswordCommand;
import org.mifosng.data.command.EnrollClientCommand;
import org.mifosng.data.command.LoanProductCommand;
import org.mifosng.data.command.LoanStateTransitionCommand;
import org.mifosng.data.command.LoanTransactionCommand;
import org.mifosng.data.command.NoteCommand;
import org.mifosng.data.command.OfficeCommand;
import org.mifosng.data.command.RoleCommand;
import org.mifosng.data.command.SubmitLoanApplicationCommand;
import org.mifosng.data.command.UndoLoanApprovalCommand;
import org.mifosng.data.command.UndoLoanDisbursalCommand;
import org.mifosng.data.command.UpdateOrganisationCurrencyCommand;
import org.mifosng.data.command.UserCommand;
import org.mifosng.data.reports.GenericResultset;
import org.springframework.security.oauth.consumer.ProtectedResourceDetails;
@@ -43,12 +38,6 @@ public interface CommonRestOperations {
void updateProtectedResource(
ProtectedResourceDetails loadProtectedResourceDetailsById);
void updateOrganisationCurrencies(UpdateOrganisationCurrencyCommand command);
Collection<OfficeData> retrieveAllOffices();
OfficeData retrieveOffice(Long officeId);
Collection<AppUserData> retrieveAllUsers();
AppUserData retrieveNewUserDetails();
@@ -79,34 +68,10 @@ public interface CommonRestOperations {
EntityIdentifier createRole(RoleCommand command);
EntityIdentifier createOffice(OfficeCommand command);
EntityIdentifier updateOffice(OfficeCommand command);
Collection<ClientData> retrieveAllIndividualClients();
Collection<LoanProductData> retrieveAllLoanProducts();
Collection<CurrencyData> retrieveAllowedCurrencies();
Collection<CurrencyData> retrieveAllPlatformCurrencies();
Collection<EnumOptionReadModel> retrieveAllowedLoanAmortizationMethodOptions();
Collection<EnumOptionReadModel> retrieveAllowedLoanInterestMethodOptions();
Collection<EnumOptionReadModel> retrieveAllowedRepaymentFrequencyOptions();
Collection<EnumOptionReadModel> retrieveAllowedNominalInterestFrequencyOptions();
EntityIdentifier createLoanProduct(LoanProductCommand command);
EntityIdentifier updateLoanProduct(LoanProductCommand command);
LoanProductData retrieveLoanProductDetails(Long selectedLoanProductOption);
LoanProductData retrieveNewLoanProductDetails();
LoanSchedule calculateLoanSchedule(CalculateLoanScheduleCommand command);
NewLoanWorkflowStepOneData retrieveNewLoanApplicationStepOneDetails(
@@ -13,8 +13,6 @@ import org.mifosng.data.AppUserData;
import org.mifosng.data.ClientData;
import org.mifosng.data.ClientDataWithAccountsData;
import org.mifosng.data.ClientList;
import org.mifosng.data.CurrencyData;
import org.mifosng.data.CurrencyList;
import org.mifosng.data.EntityIdentifier;
import org.mifosng.data.EnumOptionList;
import org.mifosng.data.EnumOptionReadModel;
@@ -28,8 +26,6 @@ import org.mifosng.data.LoanSchedule;
import org.mifosng.data.NewLoanWorkflowStepOneData;
import org.mifosng.data.NoteData;
import org.mifosng.data.NoteDataList;
import org.mifosng.data.OfficeData;
import org.mifosng.data.OfficeList;
import org.mifosng.data.PermissionData;
import org.mifosng.data.PermissionList;
import org.mifosng.data.RoleData;
@@ -39,16 +35,13 @@ import org.mifosng.data.command.AdjustLoanTransactionCommand;
import org.mifosng.data.command.CalculateLoanScheduleCommand;
import org.mifosng.data.command.ChangePasswordCommand;
import org.mifosng.data.command.EnrollClientCommand;
import org.mifosng.data.command.LoanProductCommand;
import org.mifosng.data.command.LoanStateTransitionCommand;
import org.mifosng.data.command.LoanTransactionCommand;
import org.mifosng.data.command.NoteCommand;
import org.mifosng.data.command.OfficeCommand;
import org.mifosng.data.command.RoleCommand;
import org.mifosng.data.command.SubmitLoanApplicationCommand;
import org.mifosng.data.command.UndoLoanApprovalCommand;
import org.mifosng.data.command.UndoLoanDisbursalCommand;
import org.mifosng.data.command.UpdateOrganisationCurrencyCommand;
import org.mifosng.data.command.UserCommand;
import org.mifosng.data.reports.GenericResultset;
import org.mifosng.ui.loanproduct.ClientValidationException;
@@ -129,38 +122,7 @@ public class CommonRestOperationsImpl implements CommonRestOperations {
return s.getBody().getProducts();
}
@Override
public EntityIdentifier createLoanProduct(final LoanProductCommand command) {
try {
URI restUri = URI
.create(getBaseServerUrl().concat("api/protected/product/loan/new"));
ResponseEntity<EntityIdentifier> s = this.oauthRestServiceTemplate.postForEntity(restUri,
updateLoanProductRequest(command), EntityIdentifier.class);
return s.getBody();
} catch (HttpStatusCodeException e) {
ErrorResponseList errorList = parseErrors(e);
throw new ClientValidationException(errorList.getErrors());
}
}
@Override
public EntityIdentifier updateLoanProduct(LoanProductCommand command) {
try {
URI restUri = URI
.create(getBaseServerUrl().concat("api/protected/product/loan/update"));
ResponseEntity<EntityIdentifier> s = this.oauthRestServiceTemplate
.postForEntity(restUri, updateLoanProductRequest(command),
EntityIdentifier.class);
return s.getBody();
} catch (HttpStatusCodeException e) {
ErrorResponseList errorList = parseErrors(e);
throw new ClientValidationException(errorList.getErrors());
}
}
private ErrorResponseList parseErrors(HttpStatusCodeException e) {
@@ -184,53 +146,6 @@ public class CommonRestOperationsImpl implements CommonRestOperations {
}
return errorList;
}
private HttpEntity<LoanProductCommand> updateLoanProductRequest(
final LoanProductCommand command) {
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("Accept", "application/xml");
requestHeaders.set("Content-Type", "application/xml");
HttpEntity<LoanProductCommand> requestEntity = new HttpEntity<LoanProductCommand>(
command, requestHeaders);
return requestEntity;
}
@Override
public LoanProductData retrieveLoanProductDetails(
final Long selectedLoanProductOption) {
try {
URI restUri = URI
.create(getBaseServerUrl().concat("api/protected/product/loan/"
+ selectedLoanProductOption));
ResponseEntity<LoanProductData> s = this.oauthRestServiceTemplate
.exchange(restUri, HttpMethod.GET, emptyRequest(),
LoanProductData.class);
return s.getBody();
} catch (HttpStatusCodeException e) {
ErrorResponseList errorList = parseErrors(e);
throw new ClientValidationException(errorList.getErrors());
}
}
@Override
public LoanProductData retrieveNewLoanProductDetails() {
try {
URI restUri = URI
.create(getBaseServerUrl().concat("api/protected/product/loan/empty"));
ResponseEntity<LoanProductData> s = this.oauthRestServiceTemplate
.exchange(restUri, HttpMethod.GET, emptyRequest(),
LoanProductData.class);
return s.getBody();
} catch (HttpStatusCodeException e) {
ErrorResponseList errorList = parseErrors(e);
throw new ClientValidationException(errorList.getErrors());
}
}
@Override
public LoanSchedule calculateLoanSchedule(
@@ -587,116 +502,7 @@ public class CommonRestOperationsImpl implements CommonRestOperations {
return new HttpEntity<CalculateLoanScheduleCommand>(command,
requestHeaders);
}
@Override
public Collection<CurrencyData> retrieveAllowedCurrencies() {
try {
URI restUri = URI
.create(getBaseServerUrl().concat("api/protected/config/currency/allowed"));
ResponseEntity<CurrencyList> s = this.oauthRestServiceTemplate
.exchange(restUri, HttpMethod.GET, emptyRequest(),
CurrencyList.class);
return s.getBody().getCurrencies();
} catch (HttpStatusCodeException e) {
ErrorResponseList errorList = parseErrors(e);
throw new ClientValidationException(errorList.getErrors());
}
}
@Override
public Collection<EnumOptionReadModel> retrieveAllowedLoanAmortizationMethodOptions() {
URI restUri = URI
.create(getBaseServerUrl().concat("api/protected/config/loan/amortization/allowed"));
ResponseEntity<EnumOptionList> s = this.oauthRestServiceTemplate
.exchange(restUri, HttpMethod.GET, emptyRequest(),
EnumOptionList.class);
return s.getBody().getOptions();
}
@Override
public Collection<EnumOptionReadModel> retrieveAllowedLoanInterestMethodOptions() {
URI restUri = URI
.create(getBaseServerUrl().concat("api/protected/config/loan/interestcalculation/allowed"));
ResponseEntity<EnumOptionList> s = this.oauthRestServiceTemplate
.exchange(restUri, HttpMethod.GET, emptyRequest(),
EnumOptionList.class);
return s.getBody().getOptions();
}
@Override
public Collection<EnumOptionReadModel> retrieveAllowedRepaymentFrequencyOptions() {
URI restUri = URI
.create(getBaseServerUrl().concat("api/protected/config/loan/repaymentfrequency/allowed"));
ResponseEntity<EnumOptionList> s = this.oauthRestServiceTemplate
.exchange(restUri, HttpMethod.GET, emptyRequest(),
EnumOptionList.class);
return s.getBody().getOptions();
}
@Override
public Collection<EnumOptionReadModel> retrieveAllowedNominalInterestFrequencyOptions() {
URI restUri = URI
.create(getBaseServerUrl().concat("api/protected/config/loan/interestfrequency/allowed"));
ResponseEntity<EnumOptionList> s = this.oauthRestServiceTemplate
.exchange(restUri, HttpMethod.GET, emptyRequest(),
EnumOptionList.class);
return s.getBody().getOptions();
}
@Override
public Collection<CurrencyData> retrieveAllPlatformCurrencies() {
try {
URI restUri = URI
.create(getBaseServerUrl().concat("api/protected/config/currency/all"));
ResponseEntity<CurrencyList> s = this.oauthRestServiceTemplate
.exchange(restUri, HttpMethod.GET, emptyRequest(),
CurrencyList.class);
return s.getBody().getCurrencies();
} catch (HttpStatusCodeException e) {
ErrorResponseList errorList = parseErrors(e);
throw new ClientValidationException(errorList.getErrors());
}
}
@Override
public void updateOrganisationCurrencies(UpdateOrganisationCurrencyCommand command) {
try {
URI restUri = URI
.create(getBaseServerUrl().concat("api/protected/config/currency/update"));
this.oauthRestServiceTemplate.exchange(restUri, HttpMethod.PUT,
updateCurrencyRequest(command),
UpdateOrganisationCurrencyCommand.class);
} catch (HttpStatusCodeException e) {
ErrorResponseList errorList = parseErrors(e);
throw new ClientValidationException(errorList.getErrors());
}
}
private HttpEntity<UpdateOrganisationCurrencyCommand> updateCurrencyRequest(
final UpdateOrganisationCurrencyCommand command) {
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("Accept", "application/xml");
requestHeaders.set("Content-Type", "application/xml");
HttpEntity<UpdateOrganisationCurrencyCommand> requestEntity = new HttpEntity<UpdateOrganisationCurrencyCommand>(
command, requestHeaders);
return requestEntity;
}
@Override
public EntityIdentifier createUser(final UserCommand command) {
try {
@@ -950,99 +756,6 @@ public class CommonRestOperationsImpl implements CommonRestOperations {
}
}
@Override
public Collection<OfficeData> retrieveAllOffices() {
try {
URI restUri = URI
.create(getBaseServerUrl().concat("api/protected/office/all"));
ResponseEntity<OfficeList> s = this.oauthRestServiceTemplate
.exchange(restUri, HttpMethod.GET, emptyRequest(),
OfficeList.class);
return s.getBody().getOffices();
} catch (HttpStatusCodeException e) {
ErrorResponseList errorList = parseErrors(e);
throw new ClientValidationException(errorList.getErrors());
}
}
@Override
public OfficeData retrieveOffice(final Long officeId) {
try {
URI restUri = URI
.create(getBaseServerUrl().concat("api/protected/office/"
+ officeId));
ResponseEntity<OfficeData> s = this.oauthRestServiceTemplate
.exchange(restUri, HttpMethod.GET, emptyRequest(),
OfficeData.class);
return s.getBody();
} catch (HttpStatusCodeException e) {
ErrorResponseList errorList = parseErrors(e);
throw new ClientValidationException(errorList.getErrors());
}
}
@Override
public EntityIdentifier createOffice(final OfficeCommand command) {
try {
URI restUri = URI
.create(getBaseServerUrl().concat("api/protected/office/new"));
ResponseEntity<EntityIdentifier> s = this.oauthRestServiceTemplate
.postForEntity(restUri, createOfficeRequest(command),
EntityIdentifier.class);
return s.getBody();
} catch (HttpStatusCodeException e) {
ErrorResponseList errorList = parseErrors(e);
throw new ClientValidationException(errorList.getErrors());
}
}
@Override
public EntityIdentifier updateOffice(final OfficeCommand command) {
try {
URI restUri = URI
.create(getBaseServerUrl().concat("api/protected/office/update"));
ResponseEntity<EntityIdentifier> s = this.oauthRestServiceTemplate
.postForEntity(restUri, updateOfficeRequest(command),
EntityIdentifier.class);
return s.getBody();
} catch (HttpStatusCodeException e) {
ErrorResponseList errorList = parseErrors(e);
throw new ClientValidationException(errorList.getErrors());
}
}
private HttpEntity<OfficeCommand> createOfficeRequest(
final OfficeCommand command) {
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("Accept", "application/xml");
requestHeaders.set("Content-Type", "application/xml");
HttpEntity<OfficeCommand> requestEntity = new HttpEntity<OfficeCommand>(
command, requestHeaders);
return requestEntity;
}
private HttpEntity<OfficeCommand> updateOfficeRequest(
final OfficeCommand command) {
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("Accept", "application/xml");
requestHeaders.set("Content-Type", "application/xml");
HttpEntity<OfficeCommand> requestEntity = new HttpEntity<OfficeCommand>(
command, requestHeaders);
return requestEntity;
}
@Override
public ClientData retrieveNewIndividualClient() {
URI restUri = URI.create(getBaseServerUrl().concat("api/protected/client/new"));
@@ -1,35 +1,24 @@
package org.mifosng.ui.configuration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.mifosng.configuration.ApplicationConfigurationService;
import org.mifosng.configuration.OAuthProviderDetails;
import org.mifosng.data.ConfigurationData;
import org.mifosng.data.CurrencyData;
import org.mifosng.data.EntityIdentifier;
import org.mifosng.data.ErrorResponse;
import org.mifosng.data.command.UpdateOrganisationCurrencyCommand;
import org.mifosng.oauth.RefreshableProtectedResourceDetailsService;
import org.mifosng.ui.CommonRestOperations;
import org.mifosng.ui.loanproduct.ClientValidationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.oauth.consumer.ProtectedResourceDetailsService;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ModelAttribute;
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;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;
@@ -66,38 +55,6 @@ public class ConfigurationController {
return ex.getValidationErrors();
}
@RequestMapping(consumes="application/json", produces="application/json", value = "org/configuration/edit", method = RequestMethod.GET)
public @ResponseBody ConfigurationData viewConfigurationDetails() {
List<CurrencyData> selectedCurrencyOptions = new ArrayList<CurrencyData>(this.commonRestOperations.retrieveAllowedCurrencies());
List<CurrencyData> currencyOptions = new ArrayList<CurrencyData>(this.commonRestOperations.retrieveAllPlatformCurrencies());
// remove selected currency options
currencyOptions.removeAll(selectedCurrencyOptions);
ConfigurationData configurationData = new ConfigurationData();
configurationData.setCurrencyOptions(currencyOptions);
configurationData.setSelectedCurrencyOptions(selectedCurrencyOptions);
return configurationData;
}
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "org/configuration/edit", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.OK)
public @ResponseBody EntityIdentifier updateOrganisationCurrencies(@RequestParam(value="selectedItems", required=false) String[] selectedCurrencies) {
List<String> codes = new ArrayList<String>();
if (selectedCurrencies != null) {
codes = Arrays.asList(selectedCurrencies);
}
UpdateOrganisationCurrencyCommand command = new UpdateOrganisationCurrencyCommand(codes);
this.commonRestOperations.updateOrganisationCurrencies(command);
return new EntityIdentifier(Long.valueOf(1));
}
@ModelAttribute("oauthSettingsFormBean")
@RequestMapping(value = "oauth/configuration/edit", method = RequestMethod.GET)
public ModelAndView showOAuthConfiguration() {
@@ -114,9 +71,7 @@ public class ConfigurationController {
}
@RequestMapping(value = "oauth/configuration/edit", method = RequestMethod.POST)
public ModelAndView updateOAuthConfiguration(
@ModelAttribute final OauthSettingsFormBean oauthSettingsFormBean,
final BindingResult result) {
public ModelAndView updateOAuthConfiguration(@ModelAttribute final OauthSettingsFormBean oauthSettingsFormBean) {
ModelAndView mav = new ModelAndView("redirect:/");
@@ -1,195 +0,0 @@
package org.mifosng.ui.loanproduct;
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.mifosng.data.EntityIdentifier;
import org.mifosng.data.ErrorResponse;
import org.mifosng.data.LoanProductData;
import org.mifosng.data.command.LoanProductCommand;
import org.mifosng.ui.CommonRestOperations;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
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;
import org.springframework.web.bind.annotation.ResponseStatus;
@Controller
public class LoanProductController {
private final CommonRestOperations commonRestOperations;
@Autowired
public LoanProductController(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 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/json", produces="application/json", value = "/portfolio/product/loan/all", method = RequestMethod.GET)
public @ResponseBody Collection<LoanProductData> viewAllLoanProducts() {
return this.commonRestOperations.retrieveAllLoanProducts();
}
@RequestMapping(consumes="application/json", produces="application/json", value = "/portfolio/product/loan/new", method = RequestMethod.GET)
public @ResponseBody LoanProductData viewNewLoanProductForm() {
return this.commonRestOperations.retrieveNewLoanProductDetails();
}
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/portfolio/product/loan/new", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.OK)
public @ResponseBody EntityIdentifier createLoanProduct(
@RequestParam("name") String name,
@RequestParam("description") String description,
@RequestParam("selectedCurrency") String currencyCode, @RequestParam("selectedDigitsAfterDecimal") Integer digitsAfterDecimal,
@RequestParam("amount") String principalAsNumber,
@RequestParam("repaidEvery") Integer repaymentEvery,
@RequestParam("selectedRepaymentFrequencyOption") Integer repaymentFrequency,
@RequestParam("numberOfRepayments") Integer numberOfRepayments,
@RequestParam("selectedAmortizationMethodOption") Integer amortizationMethod,
@RequestParam("inArrearsTolerance") String inArrearsToleranceAsNumber,
@RequestParam("nominalInterestRate") String nominalInterestRatePerPeriodAsNumber,
@RequestParam("selectedInterestFrequencyOption") Integer nominalInterestRatePerPeriodFrequency,
@RequestParam("selectedInterestMethodOption") Integer interestMethod,
@RequestParam(value="interestRateCalculatedInPeriod", required=false) Integer interestCalculationPeriodMethod
) {
LoanProductCommand command = new LoanProductCommand();
command.setName(name);
command.setDescription(description);
command.setCurrencyCode(currencyCode);
command.setDigitsAfterDecimal(digitsAfterDecimal);
if (StringUtils.isNotBlank(principalAsNumber)) {
BigDecimal principal = parseStringToBigDecimal(principalAsNumber);
command.setPrincipal(principal);
}
command.setRepaymentEvery(repaymentEvery);
command.setRepaymentFrequency(repaymentFrequency);
command.setNumberOfRepayments(numberOfRepayments);
command.setAmortizationMethod(amortizationMethod);
if (StringUtils.isNotBlank(inArrearsToleranceAsNumber)) {
BigDecimal inArrearsToleranceAmount = parseStringToBigDecimal(inArrearsToleranceAsNumber);
command.setInArrearsToleranceAmount(inArrearsToleranceAmount);
}
if (StringUtils.isNotBlank(nominalInterestRatePerPeriodAsNumber)) {
BigDecimal interestRatePerPeriod = parseStringToBigDecimal(nominalInterestRatePerPeriodAsNumber);
command.setInterestRatePerPeriod(interestRatePerPeriod);
}
command.setInterestRateFrequencyMethod(nominalInterestRatePerPeriodFrequency);
command.setInterestMethod(interestMethod);
command.setInterestCalculationPeriodMethod(interestCalculationPeriodMethod);
return this.commonRestOperations.createLoanProduct(command);
}
@RequestMapping(consumes="application/json", produces="application/json", value = "/portfolio/product/loan/{productId}", method = RequestMethod.GET)
public @ResponseBody LoanProductData viewLoanProduct(@PathVariable("productId") final Long productId) {
return this.commonRestOperations.retrieveLoanProductDetails(productId);
}
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/portfolio/product/loan/{productId}", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.OK)
public @ResponseBody EntityIdentifier updateLoanProduct(@PathVariable("productId") final Long productId,
@RequestParam("name") String name, @RequestParam("description") String description,
@RequestParam("selectedCurrency") String currencyCode, @RequestParam("selectedDigitsAfterDecimal") Integer digitsAfterDecimal,
@RequestParam("amount") String principalAsNumber,
@RequestParam("repaidEvery") Integer repaymentEvery,
@RequestParam("selectedRepaymentFrequencyOption") Integer repaymentFrequency,
@RequestParam("numberOfRepayments") Integer numberOfRepayments,
@RequestParam("selectedAmortizationMethodOption") Integer amortizationMethod,
@RequestParam("inArrearsTolerance") String inArrearsToleranceAsNumber,
@RequestParam("nominalInterestRate") String nominalInterestRatePerPeriodAsNumber,
@RequestParam("selectedInterestFrequencyOption") Integer nominalInterestRatePerPeriodFrequency,
@RequestParam("selectedInterestMethodOption") Integer interestMethod,
@RequestParam(value="interestRateCalculatedInPeriod", required=false) Integer interestCalculationPeriodMethod
) {
LoanProductCommand command = new LoanProductCommand();
command.setId(productId);
command.setName(name);
command.setDescription(description);
command.setExternalId(null);
command.setCurrencyCode(currencyCode);
command.setDigitsAfterDecimal(digitsAfterDecimal);
if (StringUtils.isNotBlank(principalAsNumber)) {
BigDecimal principal = parseStringToBigDecimal(principalAsNumber);
command.setPrincipal(principal);
}
command.setRepaymentEvery(repaymentEvery);
command.setRepaymentFrequency(repaymentFrequency);
command.setNumberOfRepayments(numberOfRepayments);
command.setAmortizationMethod(amortizationMethod);
if (StringUtils.isNotBlank(inArrearsToleranceAsNumber)) {
BigDecimal inArrearsToleranceAmount = parseStringToBigDecimal(inArrearsToleranceAsNumber);
command.setInArrearsToleranceAmount(inArrearsToleranceAmount);
}
if (StringUtils.isNotBlank(nominalInterestRatePerPeriodAsNumber)) {
BigDecimal interestRatePerPeriod = parseStringToBigDecimal(nominalInterestRatePerPeriodAsNumber);
command.setInterestRatePerPeriod(interestRatePerPeriod);
}
command.setInterestRateFrequencyMethod(nominalInterestRatePerPeriodFrequency);
command.setInterestMethod(interestMethod);
command.setInterestCalculationPeriodMethod(interestCalculationPeriodMethod);
return this.commonRestOperations.updateLoanProduct(command);
}
}
@@ -1,127 +0,0 @@
package org.mifosng.ui.office;
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.OfficeData;
import org.mifosng.data.command.OfficeCommand;
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.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
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;
import org.springframework.web.bind.annotation.ResponseStatus;
@Controller
public class OfficeController {
private final CommonRestOperations commonRestOperations;
@Autowired
public OfficeController(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;
}
@RequestMapping(consumes="application/json", produces="application/json", value = "/org/office/all", method = RequestMethod.GET)
public @ResponseBody Collection<OfficeData> viewAllOffices() {
return this.commonRestOperations.retrieveAllOffices();
}
@RequestMapping(consumes="application/json", produces="application/json", value = "/org/office/new", method = RequestMethod.GET)
public @ResponseBody OfficeData viewNewOfficeForm() {
OfficeData newOffice = new OfficeData();
newOffice.setOpeningDate(new LocalDate());
Collection<OfficeData> allOffices = this.commonRestOperations.retrieveAllOffices();
List<OfficeData> allowedParents = new ArrayList<OfficeData>(allOffices);
newOffice.setAllowedParents(allowedParents);
return newOffice;
}
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/org/office/new", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.OK)
public @ResponseBody EntityIdentifier createOffice(
@RequestParam("name") String name,
@RequestParam(value="parentId", required=false) Long parentId,
@RequestParam("openingDate") String openingDate,
@RequestParam(value="externalId", required=false) String externalId) {
LocalDate openingLocalDate = parseStringToLocalDate(openingDate, "openingDate");
OfficeCommand command = new OfficeCommand(name, externalId, parentId, openingLocalDate);
return this.commonRestOperations.createOffice(command);
}
@RequestMapping(consumes="application/json", produces="application/json", value = "/org/office/{officeId}", method = RequestMethod.GET)
public @ResponseBody OfficeData viewOffice(@PathVariable("officeId") final Long officeId) {
return this.commonRestOperations.retrieveOffice(officeId);
}
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/org/office/{officeId}", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.OK)
public @ResponseBody EntityIdentifier updateOffice(@PathVariable("officeId") final Long officeId,
@RequestParam("name") String name,
@RequestParam(value="parentId", required=false) Long parentId,
@RequestParam("openingDate") String openingDate,
@RequestParam(value="externalId", required=false) String externalId) {
LocalDate openingLocalDate = parseStringToLocalDate(openingDate, "openingDate");
OfficeCommand command = new OfficeCommand(officeId, name, externalId, parentId, openingLocalDate);
return this.commonRestOperations.updateOffice(command);
}
}
@@ -250,7 +250,7 @@ validation.msg.product.interest.rate.per.period.amount.cannot.be.empty=Nominal i
validation.msg.product.currency.digitsAfterDecimal.must.be.between.zero.and.six.inclusive=Decimal places must be a number between zero and six inclusive.
validation.msg.product.principal.amount.must.be.greater.than.zero=Loan amount must be greater than zero.
validation.msg.product.repayment.repaidEvery.outside.allowed.range=Repaid every is out of allowed range for selected repayment frequency type.
validation.msg.product.repayment.repaidEvery.outside.allowed.range=Repaid every must be between {0} and {1} inclusive given the selected repayment frequency type.
validation.msg.product.number.of.repayments.is.out.of.range=# of repayments is out of allowed range for selected repayment frequency type.
validation.msg.product.arrears.tolerance.amount.cannot.be.negative=Arrears tolerance cannot be negative.
validation.msg.product.interest.rate.per.period.amount.cannot.be.negative=Nominal interest rate % cannot be negative.
@@ -112,17 +112,28 @@
removeErrors(placeholderDiv);
var jsonErrors = JSON.parse(jqXHR.responseText);
console.log(jsonErrors);
var valErrors = jsonErrors.errors;
console.log(valErrors);
var errorArray = new Array();
var arrayIndex = 0;
$.each(jsonErrors, function() {
var fieldId = '#' + this.field;
$.each(valErrors, function() {
var fieldId = '#' + this.parameterName;
$(fieldId).addClass("ui-state-error");
var errorObj = new Object();
errorObj.field = this.field;
errorObj.code = this.code;
errorObj.message = jQuery.i18n.prop(this.code, this.args);
errorObj.field = this.parameterName;
errorObj.code = this.userMessageGlobalisationCode;
var argArray = new Array();
var argArrayIndex = 0;
$.each(this.args, function() {
argArray[argArrayIndex] = this.value;
argArrayIndex++;
});
console.log(argArray);
// hardcoded support for six arguments
errorObj.message = jQuery.i18n.prop(this.userMessageGlobalisationCode, argArray[0], argArray[1], argArray[2], argArray[3], argArray[4], argArray[5]);
errorObj.value = this.value;
errorArray[arrayIndex] = errorObj;
@@ -182,7 +193,7 @@
return o;
};
function popupDialogWithFormView(getUrl, postUrl, titleCode, templateSelector, width, height, saveSuccessFunction) {
function popupDialogWithFormView(getUrl, postUrl, submitType, titleCode, templateSelector, width, height, saveSuccessFunction) {
var dialogDiv = $("<div id='dialog-form'></div>");
var jqxhr = $.ajax({
url: getUrl,
@@ -218,7 +229,7 @@
var jqxhr = $.ajax({
url: postUrl,
type: 'POST',
type: submitType,
contentType: 'application/json',
dataType: 'json',
data: newFormData,
@@ -273,7 +284,6 @@
$('#addloanproduct').click(function(e) {
var getUrl = 'http://localhost:8085/mifosng-provider/api/v1/loanproducts/template';
var postUrl = 'http://localhost:8085/mifosng-provider/api/v1/loanproducts';
//var url = '${rootContext}portfolio/product/loan/new';
var templateSelector = "#productFormTemplate";
var width = 800;
var height = 550;
@@ -283,13 +293,13 @@
refreshLoanProductsView();
}
popupDialogWithFormView(getUrl, postUrl, "dialog.title.add.loan.product", templateSelector, width, height, saveSuccessFunction);
popupDialogWithFormView(getUrl, postUrl, 'POST', "dialog.title.add.loan.product", templateSelector, width, height, saveSuccessFunction);
e.preventDefault();
});
function refreshLoanProductsView() {
var jqxhr = $.ajax({
url: '${allLoanProductsUrl}',
url: 'http://localhost:8085/mifosng-provider/api/v1/loanproducts', //'${allLoanProductsUrl}',
type: 'GET',
contentType: 'application/json',
dataType: 'json',
@@ -297,7 +307,7 @@
success: function(data, textStatus, jqXHR) {
var productlistParent = new Object();
productlistParent.items = data;
productlistParent.items = data.products;
var productListHtml = $("#productListTemplate").render(productlistParent);
$("#listplaceholder").html(productListHtml);
@@ -305,7 +315,8 @@
$("a.editproduct").click( function(e) {
var linkId = this.id;
var productId = linkId.replace("editproduct", "");
var url = '${rootContext}portfolio/product/loan/' + productId;
var getUrl = 'http://localhost:8085/mifosng-provider/api/v1/loanproducts/' + productId;
var putUrl = 'http://localhost:8085/mifosng-provider/api/v1/loanproducts/' + productId;
var templateSelector = "#productFormTemplate";
var width = 800;
@@ -316,7 +327,7 @@
refreshLoanProductsView();
}
popupDialogWithFormView(url, "dialog.title.product.details", templateSelector, width, height, saveSuccessFunction);
popupDialogWithFormView(getUrl, putUrl, 'PUT', "dialog.title.product.details", templateSelector, width, height, saveSuccessFunction);
e.preventDefault();
});
@@ -374,7 +385,7 @@
refreshOfficesView();
}
popupDialogWithFormView(url, "dialog.title.add.office", templateSelector, width, height, saveSuccessFunction);
popupDialogWithFormView(getUrl, postUrl, 'POST', "dialog.title.add.office", templateSelector, width, height, saveSuccessFunction);
e.preventDefault();
});
@@ -399,7 +410,9 @@
$("a.edit").click( function(e) {
var linkId = this.id;
var entityId = linkId.replace("edit", "");
var url = '${rootContext}org/office/' + entityId;
var getUrl = 'http://localhost:8085/mifosng-provider/api/v1/offices/' + entityId;
var putUrl = 'http://localhost:8085/mifosng-provider/api/v1/offices/' + entityId;
var templateSelector = "#officeFormTemplate";
var width = 600;
var height = 400;
@@ -409,7 +422,7 @@
refreshOfficesView();
}
popupDialogWithFormView(url, "dialog.title.office.details", templateSelector, width, height, saveSuccessFunction);
popupDialogWithFormView(getUrl, putUrl, 'PUT', "dialog.title.office.details", templateSelector, width, height, saveSuccessFunction);
e.preventDefault();
});
@@ -444,7 +457,8 @@
// currency configuration
$('#editconfiguration').click(function(e) {
var url = '${rootContext}org/configuration/edit';
var getUrl = 'http://localhost:8085/mifosng-provider/api/v1/configurations/currency';
var putUrl = 'http://localhost:8085/mifosng-provider/api/v1/configurations/currency';
var templateSelector = "#configurationFormTemplate";
var width = 900;
var height = 400;
@@ -453,7 +467,7 @@
$("#dialog-form").dialog("close");
}
popupDialogWithFormView(url, "dialog.title.configuration.currencies", templateSelector, width, height, saveSuccessFunction);
popupDialogWithFormView(getUrl, putUrl, 'PUT', "dialog.title.configuration.currencies", templateSelector, width, height, saveSuccessFunction);
e.preventDefault();
});
@@ -34,8 +34,8 @@
</fieldset>
<fieldset>
<legend><spring:message code="form.legend.loan.product.currency"/></legend>
<label for="selectedCurrency"><spring:message code="form.label.loan.product.currency"/></label>
<select id="selectedCurrency" name="selectedCurrency" title="" style="width: 300px;">
<label for="currencyCode"><spring:message code="form.label.loan.product.currency"/></label>
<select id="currencyCode" name="currencyCode" title="" style="width: 300px;">
{{#each possibleCurrencies}}
{{#if $parent.parent.data.principalMoney.currencyCode===code}}
<option value="{{=code}}" selected="selected">{{=name}}</option>
@@ -44,8 +44,8 @@
{{/if}}
{{/each}}
</select>
<label for="selectedDigitsAfterDecimal"><spring:message code="form.label.loan.product.decimalplaces"/></label>
<input id="selectedDigitsAfterDecimal" name="selectedDigitsAfterDecimal" title="" style="width: 300px;" value="{{=$ctx.number(principalMoney.currencyDigitsAfterDecimal)}}" />
<label for="digitsAfterDecimal"><spring:message code="form.label.loan.product.decimalplaces"/></label>
<input id="digitsAfterDecimal" name="digitsAfterDecimal" title="" style="width: 300px;" value="{{=$ctx.number(principalMoney.currencyDigitsAfterDecimal)}}" />
</fieldset>
<fieldset>
<legend><spring:message code="form.legend.loan.product.loan.terms"/></legend>
@@ -57,15 +57,15 @@
<tr>
<td><spring:message code="form.label.loan.product.loan.amount"/></td>
<td>
<input id="amount" name="amount" title="" style="width: 125px;" value="{{=$ctx.money(principalMoney)}}" />
<input id="principal" name="principal" title="" style="width: 125px;" value="{{=$ctx.money(principalMoney)}}" />
</td>
</tr>
<tr>
<td><spring:message code="form.label.loan.product.repaidevery"/></td>
<td>
<input id="repaidEvery" name="repaidEvery" title="" style="width: 50px;" value="{{=$ctx.number(repaidEvery)}}"/>
<input id="repaymentEvery" name="repaymentEvery" title="" style="width: 50px;" value="{{=$ctx.number(repaidEvery)}}"/>
<select id="selectedRepaymentFrequencyOption" name="selectedRepaymentFrequencyOption" title="" style="width: 121px;">
<select id="repaymentFrequency" name="repaymentFrequency" title="" style="width: 121px;">
{{#each repaymentFrequencyOptions}}
{{#if $ctx.number($parent.parent.data.repaymentPeriodFrequency)===$ctx.number(id)}}
<option value="{{=$ctx.number(id)}}" selected="selected">{{=value}}</option>
@@ -89,9 +89,9 @@
<tr>
<td><spring:message code="form.label.loan.product.nominal.interestrate"/></td>
<td>
<input id="nominalInterestRate" name="nominalInterestRate" title="" style="width: 70px;" value="{{=$ctx.decimal(interestRatePerPeriod, 4)}}" />
<input id="interestRatePerPeriod" name="interestRatePerPeriod" title="" style="width: 70px;" value="{{=$ctx.decimal(interestRatePerPeriod, 4)}}" />
<select id="selectedInterestFrequencyOption" name="selectedInterestFrequencyOption" title="" style="width: 139px;">
<select id="interestRateFrequencyMethod" name="interestRateFrequencyMethod" title="" style="width: 139px;">
{{#each interestFrequencyOptions}}
{{#if $ctx.number($parent.parent.data.interestRatePeriod)===$ctx.number(id)}}
<option value="{{=$ctx.number(id)}}" selected="selected">{{=value}}</option>
@@ -105,7 +105,7 @@
<tr>
<td><spring:message code="form.label.loan.product.amortization"/></td>
<td>
<select id="selectedAmortizationMethodOption" name="selectedAmortizationMethodOption" title="" style="width: 220px;">
<select id="amortizationMethod" name="amortizationMethod" title="" style="width: 220px;">
{{#each possibleAmortizationOptions}}
{{#if $ctx.number($parent.parent.data.amortizationMethod)===$ctx.number(id)}}
<option value="{{=$ctx.number(id)}}" selected="selected">{{=value}}</option>
@@ -119,7 +119,7 @@
<tr>
<td><spring:message code="form.label.loan.product.interest.method"/></td>
<td>
<select id="selectedInterestMethodOption" name="selectedInterestMethodOption" title="" style="width: 220px;">
<select id="interestMethod" name="interestMethod" title="" style="width: 220px;">
{{#each possibleInterestOptions}}
{{#if $ctx.number($parent.parent.data.interestMethod)===$ctx.number(id)}}
<option value="{{=$ctx.number(id)}}" selected="selected">{{=value}}</option>
@@ -133,7 +133,7 @@
<tr>
<td><spring:message code="form.label.loan.product.interest.rate.calcutated.in.period"/></td>
<td>
<select id="interestRateCalculatedInPeriod" name="interestRateCalculatedInPeriod" title="" style="width: 220px;">
<select id="interestCalculationPeriodMethod" name="interestCalculationPeriodMethod" title="" style="width: 220px;">
{{#each possibleInterestRateCalculatedInPeriodOptions}}
{{#if $ctx.number($parent.parent.data.interestRateCalculatedInPeriod)===$ctx.number(id)}}
<option value="{{=$ctx.number(id)}}" selected="selected">{{=value}}</option>
@@ -147,7 +147,7 @@
<tr>
<td><spring:message code="form.label.loan.product.arrears.tolerance"/></td>
<td>
<input id="inArrearsTolerance" name="inArrearsTolerance" title="" style="width: 215px;" value="{{=$ctx.money(inArrearsTolerance)}}" />
<input id="inArrearsToleranceAmount" name="inArrearsToleranceAmount" title="" style="width: 215px;" value="{{=$ctx.money(inArrearsTolerance)}}" />
</td>
</tr>
</table>
@@ -240,10 +240,13 @@
{{/if}}
{{/each}}
</select>
{{#else}}
<input type="hidden" id="rootOffice" name="rootOffice" value="true" />
{{/if}}
<label for="openingDate"><spring:message code="form.label.office.openedon"/></label>
<input id="openingDate" name="openingDate" title="" type="text" value="{{=$ctx.globalDate(openingDate)}}" size="75" class="datepickerfield" />
<input type="hidden" id="dateFormat" name="dateFormat" value="dd MMMM yyyy" />
<label for="openingDateFormatted"><spring:message code="form.label.office.openedon"/></label>
<input id="openingDateFormatted" name="openingDateFormatted" title="" type="text" value="{{=$ctx.globalDate(openingDate)}}" size="75" class="datepickerfield" />
<label for="externalId"><spring:message code="form.label.office.externalid"/></label>
<input id="externalId" name="externalId" title="" type="text" value="{{=externalId}}" size="75"/>