tidy up error handling and services around loan product.

This commit is contained in:
Keith Woodlock
2012-05-10 21:09:37 +01:00
parent 01adabab47
commit 6f4a47a1ca
33 changed files with 839 additions and 1087 deletions
@@ -1,470 +0,0 @@
package org.mifosng.data;
import java.math.BigDecimal;
import javax.xml.bind.annotation.XmlRootElement;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.LocalDate;
import org.joda.time.Months;
@XmlRootElement(name = "loan")
public class BasicLoanAccountData {
private boolean open = true;
private boolean openWithRepaymentMade = true;
private boolean closed = false;
private boolean interestRebateOutstanding = false;
private boolean pendingApproval = false;
private boolean waitingForDisbursal = false;
private String lifeCycleStatusText = "Active";
private Long id = Long.valueOf(1);
private String externalId = "1234567";
private String loanProductName = "Standard loan 1.75%";
private LocalDate submittedOnDate = new LocalDate();
private String submittedOnNote = "";
private LocalDate approvedOnDate = new LocalDate();
private String approvedOnNote = "";
private LocalDate expectedDisbursementDate = new LocalDate();
private LocalDate actualDisbursementDate = new LocalDate();
private String disbursedOnNote = "";
private boolean undoDisbursalAllowed = true;
private LocalDate closedOnDate = new LocalDate();
private String closedOnNote = "";
private LocalDate maturityDate = new LocalDate();
private MoneyData principal = MoneyData.of(new CurrencyData("XOF", "CFA", 0, "CFA", "currency.CFA"), BigDecimal.valueOf(Double.valueOf("12345.89")));
private BigDecimal interestRatePerYear = BigDecimal.valueOf(Double.valueOf("21.0"));
private BigDecimal interestRatePerPeriod = BigDecimal.valueOf(Double.valueOf("1.75"));
private Integer interestPeriodFrequencyType = Integer.valueOf(2);
private String interestPeriodFrequencyText = "Month(s)";
private Integer interestMethodType = Integer.valueOf(1);
private String interestMethodText = "Declining Balance";
private Integer amortizationMethodValue = Integer.valueOf(1);
private String amortizationMethodText = "Equal Installments";
private Integer numberOfRepayments = 12;
private Integer repaymentFrequencyNumber = 1;
private Integer repaymentFrequencyTypeEnumOrdinal = 2;
private String repaymentFrequencyTypeText = "Month(s)";
private MoneyData interestRebateOwed = MoneyData.of(new CurrencyData("XOF", "CFA", 0, "CFA", "currency.CFA"), BigDecimal.valueOf(Double.valueOf("0.0")));
// private DerivedLoanData loanData;
// private MoneyData arrearsTolerance;
private boolean waiveAllowed = false;
public BasicLoanAccountData() {
//
}
public BasicLoanAccountData(final boolean closed, final boolean open,
final boolean openWithRepaymentMade,
final boolean interestRebateOutstanding,
final boolean pendingApproval, final boolean waitingForDisbursal,
final String lifeCycleStatusText, final Long id, String externalId,
final String loanProductName, final LocalDate closedOnDate,
final String closedOnNote, final LocalDate submittedOnDate,
final String submittedOnNote, final LocalDate approvedOnDate,
final String approvedOnNote,
final LocalDate expectedDisbursementDate,
final LocalDate actualDisbursementDate,
final String disbursedOnNote, final LocalDate maturityDate,
final MoneyData principal, final BigDecimal interestRatePerYear,
final BigDecimal interestRatePerPeriod,
final Integer interestPeriodFrequencyType,
final String interestPeriodFrequencyText,
final Integer interestMethodType,
final String interestMethodText,
final Integer amortizationMethodValue,
final String amortizationMethodText,
final Integer numberOfRepayments,
final Integer repayEvery,
final Integer repaymentFrequencyValue,
final String repaymentFrequencyText,
final MoneyData arrearsTolerance, final DerivedLoanData derivedLoanData,
boolean waiveAllowed, final MoneyData interestRebateOwed) {
this.closed = closed;
this.open = open;
this.openWithRepaymentMade = openWithRepaymentMade;
this.externalId = externalId;
this.undoDisbursalAllowed = !openWithRepaymentMade;
this.interestRebateOutstanding = interestRebateOutstanding;
this.pendingApproval = pendingApproval;
this.waitingForDisbursal = waitingForDisbursal;
this.lifeCycleStatusText = lifeCycleStatusText;
this.id = id;
this.loanProductName = loanProductName;
this.closedOnDate = closedOnDate;
this.closedOnNote = closedOnNote;
this.submittedOnDate = submittedOnDate;
this.submittedOnNote = submittedOnNote;
this.approvedOnDate = approvedOnDate;
this.approvedOnNote = approvedOnNote;
this.expectedDisbursementDate = expectedDisbursementDate;
this.actualDisbursementDate = actualDisbursementDate;
this.disbursedOnNote = disbursedOnNote;
this.maturityDate = maturityDate;
this.principal = principal;
this.interestRatePerYear = interestRatePerYear;
this.interestRatePerPeriod = interestRatePerPeriod;
this.interestPeriodFrequencyType = interestPeriodFrequencyType;
this.interestPeriodFrequencyText = interestPeriodFrequencyText;
this.interestMethodType = interestMethodType;
this.interestMethodText = interestMethodText;
this.amortizationMethodValue = amortizationMethodValue;
this.amortizationMethodText = amortizationMethodText;
this.numberOfRepayments = numberOfRepayments;
this.repaymentFrequencyNumber = repayEvery;
this.repaymentFrequencyTypeEnumOrdinal = repaymentFrequencyValue;
this.repaymentFrequencyTypeText = repaymentFrequencyText;
this.waiveAllowed = waiveAllowed;
this.interestRebateOwed = interestRebateOwed;
}
public int getMaxSubmittedOnOffsetFromToday() {
return Days.daysBetween(new DateTime(),
this.getSubmittedOnDate().toDateMidnight().toDateTime())
.getDays();
}
public int getMaxApprovedOnOffsetFromToday() {
return Days.daysBetween(new DateTime(),
this.getApprovedOnDate().toDateMidnight().toDateTime())
.getDays();
}
public int getMaxDisbursedOnOffsetFromToday() {
int offset = 0;
if (this.getActualDisbursementDate() != null) {
offset = Days.daysBetween(new DateTime(),
this.getActualDisbursementDate().toDateMidnight().toDateTime())
.getDays();
}
return offset;
}
public int getLoanTermInDays() {
LocalDate dateToUse = getExpectedDisbursementDate();
if (getActualDisbursementDate() != null) {
dateToUse = getActualDisbursementDate();
}
return Days.daysBetween(dateToUse.toDateMidnight().toDateTime(), this.getMaturityDate().toDateMidnight().toDateTime()).getDays();
}
public int getLoanTermInMonths() {
LocalDate dateToUse = getExpectedDisbursementDate();
if (getActualDisbursementDate() != null) {
dateToUse = getActualDisbursementDate();
}
return Months.monthsBetween(dateToUse.toDateMidnight().toDateTime(), this.getMaturityDate().toDateMidnight().toDateTime()).getMonths();
}
public boolean isOpen() {
return this.open;
}
public void setOpen(final boolean open) {
this.open = open;
}
public boolean isClosed() {
return this.closed;
}
public void setClosed(final boolean closed) {
this.closed = closed;
}
public boolean isInterestRebateOutstanding() {
return this.interestRebateOutstanding;
}
public void setInterestRebateOutstanding(
final boolean interestRebateOutstanding) {
this.interestRebateOutstanding = interestRebateOutstanding;
}
public boolean isPendingApproval() {
return this.pendingApproval;
}
public void setPendingApproval(final boolean pendingApproval) {
this.pendingApproval = pendingApproval;
}
public boolean isWaitingForDisbursal() {
return this.waitingForDisbursal;
}
public void setWaitingForDisbursal(final boolean waitingForDisbursal) {
this.waitingForDisbursal = waitingForDisbursal;
}
public LocalDate getClosedOnDate() {
return this.closedOnDate;
}
public void setClosedOnDate(final LocalDate closedOnDate) {
this.closedOnDate = closedOnDate;
}
public LocalDate getSubmittedOnDate() {
return this.submittedOnDate;
}
public void setSubmittedOnDate(final LocalDate submittedOnDate) {
this.submittedOnDate = submittedOnDate;
}
public Long getId() {
return this.id;
}
public void setId(final Long id) {
this.id = id;
}
public LocalDate getExpectedDisbursementDate() {
return this.expectedDisbursementDate;
}
public void setExpectedDisbursementDate(
final LocalDate expectedDisbursementDate) {
this.expectedDisbursementDate = expectedDisbursementDate;
}
public LocalDate getActualDisbursementDate() {
return this.actualDisbursementDate;
}
public void setActualDisbursementDate(final LocalDate actualDisbursementDate) {
this.actualDisbursementDate = actualDisbursementDate;
}
public MoneyData getPrincipal() {
return this.principal;
}
public void setPrincipal(final MoneyData principal) {
this.principal = principal;
}
public BigDecimal getInterestRatePerYear() {
return this.interestRatePerYear;
}
public void setInterestRatePerYear(final BigDecimal interestRatePerYear) {
this.interestRatePerYear = interestRatePerYear;
}
public String getSubmittedOnNote() {
return this.submittedOnNote;
}
public void setSubmittedOnNote(final String submittedOnNote) {
this.submittedOnNote = submittedOnNote;
}
public Integer getRepaymentFrequencyNumber() {
return this.repaymentFrequencyNumber;
}
public void setRepaymentFrequencyNumber(
final Integer repaymentFrequencyNumber) {
this.repaymentFrequencyNumber = repaymentFrequencyNumber;
}
public Integer getRepaymentFrequencyTypeEnumOrdinal() {
return this.repaymentFrequencyTypeEnumOrdinal;
}
public void setRepaymentFrequencyTypeEnumOrdinal(
final Integer repaymentFrequencyTypeEnumOrdinal) {
this.repaymentFrequencyTypeEnumOrdinal = repaymentFrequencyTypeEnumOrdinal;
}
public String getRepaymentFrequencyTypeText() {
return this.repaymentFrequencyTypeText;
}
public void setRepaymentFrequencyTypeText(
final String repaymentFrequencyTypeText) {
this.repaymentFrequencyTypeText = repaymentFrequencyTypeText;
}
public String getLoanProductName() {
return this.loanProductName;
}
public void setLoanProductName(final String loanProductName) {
this.loanProductName = loanProductName;
}
public LocalDate getApprovedOnDate() {
return this.approvedOnDate;
}
public void setApprovedOnDate(final LocalDate approvedOnDate) {
this.approvedOnDate = approvedOnDate;
}
public String getApprovedOnNote() {
return this.approvedOnNote;
}
public void setApprovedOnNote(final String approvedOnNote) {
this.approvedOnNote = approvedOnNote;
}
public String getDisbursedOnNote() {
return this.disbursedOnNote;
}
public void setDisbursedOnNote(final String disbursedOnNote) {
this.disbursedOnNote = disbursedOnNote;
}
public String getClosedOnNote() {
return this.closedOnNote;
}
public void setClosedOnNote(final String closedOnNote) {
this.closedOnNote = closedOnNote;
}
public MoneyData getInterestRebateOwed() {
return this.interestRebateOwed;
}
public void setInterestRebateOwed(final MoneyData interestRebateOwed) {
this.interestRebateOwed = interestRebateOwed;
}
public String getLifeCycleStatusText() {
return this.lifeCycleStatusText;
}
public void setLifeCycleStatusText(final String lifeCycleStatusText) {
this.lifeCycleStatusText = lifeCycleStatusText;
}
public LocalDate getMaturityDate() {
return this.maturityDate;
}
public void setMaturityDate(final LocalDate maturityDate) {
this.maturityDate = maturityDate;
}
public boolean isOpenWithRepaymentMade() {
return this.openWithRepaymentMade;
}
public void setOpenWithRepaymentMade(final boolean openWithRepaymentMade) {
this.openWithRepaymentMade = openWithRepaymentMade;
}
public boolean isUndoDisbursalAllowed() {
return this.undoDisbursalAllowed;
}
public void setUndoDisbursalAllowed(final boolean undoDisbursalAllowed) {
this.undoDisbursalAllowed = undoDisbursalAllowed;
}
public String getExternalId() {
return externalId;
}
public void setExternalId(String externalId) {
this.externalId = externalId;
}
public BigDecimal getInterestRatePerPeriod() {
return interestRatePerPeriod;
}
public void setInterestRatePerPeriod(BigDecimal interestRatePerPeriod) {
this.interestRatePerPeriod = interestRatePerPeriod;
}
public Integer getInterestPeriodFrequencyType() {
return interestPeriodFrequencyType;
}
public void setInterestPeriodFrequencyType(Integer interestPeriodFrequencyType) {
this.interestPeriodFrequencyType = interestPeriodFrequencyType;
}
public String getInterestPeriodFrequencyText() {
return interestPeriodFrequencyText;
}
public void setInterestPeriodFrequencyText(String interestPeriodFrequencyText) {
this.interestPeriodFrequencyText = interestPeriodFrequencyText;
}
public Integer getInterestMethodType() {
return interestMethodType;
}
public void setInterestMethodType(Integer interestMethodType) {
this.interestMethodType = interestMethodType;
}
public String getInterestMethodText() {
return interestMethodText;
}
public void setInterestMethodText(String interestMethodText) {
this.interestMethodText = interestMethodText;
}
public Integer getAmortizationMethodValue() {
return amortizationMethodValue;
}
public void setAmortizationMethodValue(Integer amortizationMethodValue) {
this.amortizationMethodValue = amortizationMethodValue;
}
public String getAmortizationMethodText() {
return amortizationMethodText;
}
public void setAmortizationMethodText(String amortizationMethodText) {
this.amortizationMethodText = amortizationMethodText;
}
public Integer getNumberOfRepayments() {
return numberOfRepayments;
}
public void setNumberOfRepayments(Integer numberOfRepayments) {
this.numberOfRepayments = numberOfRepayments;
}
public boolean isWaiveAllowed() {
return waiveAllowed;
}
public void setWaiveAllowed(boolean waiveAllowed) {
this.waiveAllowed = waiveAllowed;
}
}
@@ -1,7 +1,5 @@
package org.mifosng.data;
import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
@@ -1,252 +0,0 @@
package org.mifosng.data.command;
import java.math.BigDecimal;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class CreateLoanProductCommand implements LoanProductCommandData {
private String name;
private String description;
private CommonLoanProperties commonLoanProperties;
public CreateLoanProductCommand() {
this.commonLoanProperties = new CommonLoanProperties();
}
public CreateLoanProductCommand(final String currencyCode,
final Integer digitsAfterDecimal, final Number principal,
final String name, final String description,
final Number interestRatePerPeriod, Integer interestRateFrequencyMethod,
final Integer interestMethod, final Integer interestCalculationPeriodMethod,
final Integer repaymentEvery, final Integer repaymentFrequency, final Integer numberOfRepayments, Integer amortizationMethod, final Number toleranceAmount,
final boolean flexibleRepaymentSchedule,
final boolean interestRebateAllowed) {
this.name = name;
this.description = description;
commonLoanProperties = new CommonLoanProperties(currencyCode, digitsAfterDecimal, principal, interestRatePerPeriod, interestRateFrequencyMethod,
interestMethod, interestCalculationPeriodMethod,
repaymentEvery, repaymentFrequency, numberOfRepayments, amortizationMethod, toleranceAmount, flexibleRepaymentSchedule, interestRebateAllowed);
}
/* (non-Javadoc)
* @see org.mifosng.data.command.LoanProductCommandData#getName()
*/
@Override
public String getName() {
return this.name;
}
public void setName(final String name) {
this.name = name;
}
/* (non-Javadoc)
* @see org.mifosng.data.command.LoanProductCommandData#getDescription()
*/
@Override
public String getDescription() {
return this.description;
}
public void setDescription(final String description) {
this.description = description;
}
/* (non-Javadoc)
* @see org.mifosng.data.command.LoanProductCommandData#getCurrencyCode()
*/
@Override
public String getCurrencyCode() {
return this.commonLoanProperties.getCurrencyCode();
}
public void setCurrencyCode(final String currencyCode) {
this.commonLoanProperties.setCurrencyCode(currencyCode);
}
/* (non-Javadoc)
* @see org.mifosng.data.command.LoanProductCommandData#getDigitsAfterDecimal()
*/
@Override
public Integer getDigitsAfterDecimal() {
return this.commonLoanProperties.getDigitsAfterDecimal();
}
public void setDigitsAfterDecimal(final Integer digitsAfterDecimal) {
this.commonLoanProperties.setDigitsAfterDecimal(digitsAfterDecimal);
}
/* (non-Javadoc)
* @see org.mifosng.data.command.LoanProductCommandData#getRepaymentEvery()
*/
@Override
public Integer getRepaymentEvery() {
return this.commonLoanProperties.getRepaymentEvery();
}
public void setRepaymentEvery(final Integer repaymentEvery) {
this.commonLoanProperties.setRepaymentEvery(repaymentEvery);
}
/* (non-Javadoc)
* @see org.mifosng.data.command.LoanProductCommandData#getRepaymentFrequency()
*/
@Override
public Integer getRepaymentFrequency() {
return this.commonLoanProperties.getRepaymentFrequency();
}
public void setRepaymentFrequency(final Integer repaymentFrequency) {
this.commonLoanProperties.setRepaymentFrequency(repaymentFrequency);
}
/* (non-Javadoc)
* @see org.mifosng.data.command.LoanProductCommandData#isFlexibleRepaymentSchedule()
*/
@Override
public Boolean isFlexibleRepaymentSchedule() {
return this.commonLoanProperties.isFlexibleRepaymentSchedule();
}
public void setFlexibleRepaymentSchedule(
final Boolean flexibleRepaymentSchedule) {
this.commonLoanProperties.setFlexibleRepaymentSchedule(flexibleRepaymentSchedule);
}
/* (non-Javadoc)
* @see org.mifosng.data.command.LoanProductCommandData#isInterestRebateAllowed()
*/
@Override
public Boolean isInterestRebateAllowed() {
return this.commonLoanProperties.isInterestRebateAllowed();
}
public void setInterestRebateAllowed(final Boolean interestRebateAllowed) {
this.commonLoanProperties.setInterestRebateAllowed(interestRebateAllowed);
}
/* (non-Javadoc)
* @see org.mifosng.data.command.LoanProductCommandData#getPrincipal()
*/
@Override
public BigDecimal getPrincipal() {
return this.commonLoanProperties.getPrincipal();
}
public void setPrincipal(final BigDecimal principal) {
this.commonLoanProperties.setPrincipal(principal);
}
/* (non-Javadoc)
* @see org.mifosng.data.command.LoanProductCommandData#getFlexibleRepaymentSchedule()
*/
// @Override
// public Boolean getFlexibleRepaymentSchedule() {
// return this.commonLoanProperties.getFlexibleRepaymentSchedule();
// }
/* (non-Javadoc)
* @see org.mifosng.data.command.LoanProductCommandData#getInterestRebateAllowed()
*/
// @Override
// public Boolean getInterestRebateAllowed() {
// return this.commonLoanProperties.getInterestRebateAllowed();
// }
/* (non-Javadoc)
* @see org.mifosng.data.command.LoanProductCommandData#getInterestRateFrequencyMethod()
*/
@Override
public Integer getInterestRateFrequencyMethod() {
return commonLoanProperties.getInterestRateFrequencyMethod();
}
public void setInterestRateFrequencyMethod(Integer interestRateFrequencyMethod) {
this.commonLoanProperties.setInterestRateFrequencyMethod(interestRateFrequencyMethod);
}
/* (non-Javadoc)
* @see org.mifosng.data.command.LoanProductCommandData#getInterestMethod()
*/
@Override
public Integer getInterestMethod() {
return commonLoanProperties.getInterestMethod();
}
public void setInterestMethod(Integer interestMethod) {
this.commonLoanProperties.setInterestMethod(interestMethod);
}
/* (non-Javadoc)
* @see org.mifosng.data.command.LoanProductCommandData#getAmortizationMethod()
*/
@Override
public Integer getAmortizationMethod() {
return commonLoanProperties.getAmortizationMethod();
}
public void setAmortizationMethod(Integer amortizationMethod) {
this.commonLoanProperties.setAmortizationMethod(amortizationMethod);
}
/* (non-Javadoc)
* @see org.mifosng.data.command.LoanProductCommandData#getNumberOfRepayments()
*/
@Override
public Integer getNumberOfRepayments() {
return commonLoanProperties.getNumberOfRepayments();
}
public void setNumberOfRepayments(Integer numberOfRepayments) {
this.commonLoanProperties.setNumberOfRepayments(numberOfRepayments);
}
/* (non-Javadoc)
* @see org.mifosng.data.command.LoanProductCommandData#getInterestRatePerPeriod()
*/
@Override
public BigDecimal getInterestRatePerPeriod() {
return commonLoanProperties.getInterestRatePerPeriod();
}
public void setInterestRatePerPeriod(BigDecimal interestRatePerPeriod) {
this.commonLoanProperties.setInterestRatePerPeriod(interestRatePerPeriod);
}
/* (non-Javadoc)
* @see org.mifosng.data.command.LoanProductCommandData#getCommonLoanProperties()
*/
@Override
public CommonLoanProperties getCommonLoanProperties() {
return commonLoanProperties;
}
public void setCommonLoanProperties(CommonLoanProperties commonLoanProperties) {
this.commonLoanProperties = commonLoanProperties;
}
/* (non-Javadoc)
* @see org.mifosng.data.command.LoanProductCommandData#getInArrearsToleranceAmount()
*/
@Override
public BigDecimal getInArrearsToleranceAmount() {
return this.commonLoanProperties.getInArrearsToleranceAmount();
}
public void setInArrearsToleranceAmount(BigDecimal inArrearsToleranceAmount) {
this.commonLoanProperties.setInArrearsToleranceAmount(inArrearsToleranceAmount);
}
@Override
public Integer getInterestCalculationPeriodMethod() {
return this.commonLoanProperties.getInterestCalculationPeriodMethod();
}
public void setInterestCalculationPeriodMethod(final Integer interestCalculationPeriodMethod) {
this.commonLoanProperties.setInterestCalculationPeriodMethod(interestCalculationPeriodMethod);
}
}
@@ -5,7 +5,7 @@ import java.math.BigDecimal;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class UpdateLoanProductCommand implements LoanProductCommandData {
public class LoanProductCommand implements LoanProductCommandData {
private Long id;
private String name;
@@ -14,11 +14,11 @@ public class UpdateLoanProductCommand implements LoanProductCommandData {
private CommonLoanProperties commonLoanProperties;
public UpdateLoanProductCommand() {
public LoanProductCommand() {
this.commonLoanProperties = new CommonLoanProperties();
}
public UpdateLoanProductCommand(final String currencyCode,
public LoanProductCommand(final String currencyCode,
final Integer digitsAfterDecimal, final Number principal,
final String name, final String description,
final Number interestRatePerPeriod, Integer interestRateFrequencyMethod, final Integer interestMethod, final Integer interestCalculationPeriodMethod,
@@ -115,14 +115,6 @@ public class UpdateLoanProductCommand implements LoanProductCommandData {
this.commonLoanProperties.setPrincipal(principal);
}
// public Boolean getFlexibleRepaymentSchedule() {
// return this.commonLoanProperties.getFlexibleRepaymentSchedule();
// }
//
// public Boolean getInterestRebateAllowed() {
// return this.commonLoanProperties.getInterestRebateAllowed();
// }
@Override
public Integer getInterestRateFrequencyMethod() {
return commonLoanProperties.getInterestRateFrequencyMethod();
+1 -1
View File
@@ -72,7 +72,7 @@ dependencies {
[group: 'org.hibernate', name: 'hibernate-validator', version: hibernateValidatorVersion],
[group: 'javax.ws.rs', name: 'jsr311-api', version: '1.1.1'],
[group: 'com.sun.jersey', name: 'jersey-core', version: jerseyVersion],
[group: 'com.sun.jersey', name: 'jersey-server', version: jerseyVersion],
[group: 'com.sun.jersey', name: 'jersey-client', version: jerseyVersion],
[group: 'org.codehaus.jackson', name: 'jackson-mapper-asl', version: '1.9.4'],
[group: 'com.thoughtworks.xstream', name: 'xstream', version: '1.4.2'],
[group: 'net.sf.kxml', name: 'kxml2-min', version: '2.3.0'],
@@ -22,8 +22,8 @@ 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.CreateLoanProductCommand;
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;
@@ -32,7 +32,6 @@ 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.UpdateLoanProductCommand;
import org.mifosng.data.command.UpdateOrganisationCurrencyCommand;
import org.mifosng.data.command.UserCommand;
import org.mifosng.data.reports.GenericResultset;
@@ -101,9 +100,9 @@ public interface CommonRestOperations {
Collection<EnumOptionReadModel> retrieveAllowedNominalInterestFrequencyOptions();
EntityIdentifier createLoanProduct(CreateLoanProductCommand command);
EntityIdentifier createLoanProduct(LoanProductCommand command);
EntityIdentifier updateLoanProduct(UpdateLoanProductCommand command);
EntityIdentifier updateLoanProduct(LoanProductCommand command);
LoanProductData retrieveLoanProductDetails(Long selectedLoanProductOption);
@@ -39,8 +39,8 @@ import org.mifosng.data.UserList;
import org.mifosng.data.command.AdjustLoanTransactionCommand;
import org.mifosng.data.command.CalculateLoanScheduleCommand;
import org.mifosng.data.command.ChangePasswordCommand;
import org.mifosng.data.command.CreateLoanProductCommand;
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;
@@ -49,7 +49,6 @@ 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.UpdateLoanProductCommand;
import org.mifosng.data.command.UpdateOrganisationCurrencyCommand;
import org.mifosng.data.command.UserCommand;
import org.mifosng.data.reports.GenericResultset;
@@ -137,13 +136,13 @@ public class CommonRestOperationsImpl implements CommonRestOperations {
}
@Override
public EntityIdentifier createLoanProduct(final CreateLoanProductCommand command) {
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,
createLoanProductRequest(command), EntityIdentifier.class);
updateLoanProductRequest(command), EntityIdentifier.class);
return s.getBody();
} catch (HttpStatusCodeException e) {
@@ -153,7 +152,7 @@ public class CommonRestOperationsImpl implements CommonRestOperations {
}
@Override
public EntityIdentifier updateLoanProduct(UpdateLoanProductCommand command) {
public EntityIdentifier updateLoanProduct(LoanProductCommand command) {
try {
URI restUri = URI
.create(getBaseServerUrl().concat("api/protected/product/loan/update"));
@@ -192,24 +191,13 @@ public class CommonRestOperationsImpl implements CommonRestOperations {
return errorList;
}
private HttpEntity<UpdateLoanProductCommand> updateLoanProductRequest(
final UpdateLoanProductCommand command) {
private HttpEntity<LoanProductCommand> updateLoanProductRequest(
final LoanProductCommand command) {
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("Accept", "application/xml");
requestHeaders.set("Content-Type", "application/xml");
HttpEntity<UpdateLoanProductCommand> requestEntity = new HttpEntity<UpdateLoanProductCommand>(
command, requestHeaders);
return requestEntity;
}
private HttpEntity<CreateLoanProductCommand> createLoanProductRequest(
final CreateLoanProductCommand command) {
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("Accept", "application/xml");
requestHeaders.set("Content-Type", "application/xml");
HttpEntity<CreateLoanProductCommand> requestEntity = new HttpEntity<CreateLoanProductCommand>(
HttpEntity<LoanProductCommand> requestEntity = new HttpEntity<LoanProductCommand>(
command, requestHeaders);
return requestEntity;
}
@@ -2,7 +2,6 @@ package org.mifosng.ui.admin;
import java.util.Collection;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.mifosng.data.AppUserData;
@@ -16,7 +15,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@@ -62,7 +60,7 @@ public class AdministrationController {
}
@RequestMapping(value = "/org/admin/settings", method = RequestMethod.GET)
public String userSettingsScreen(Model model) {
public String userSettingsScreen() {
return "admin/accountsettings";
}
@@ -74,7 +72,7 @@ public class AdministrationController {
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "org/admin/settings/details", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.OK)
public @ResponseBody EntityIdentifier updateUserDetails(HttpServletRequest request,
public @ResponseBody EntityIdentifier updateUserDetails(
@RequestParam(value="username", required=false) String username,
@RequestParam(value="firstname", required=false) String firstname,
@RequestParam(value="lastname", required=false) String lastname,
@@ -93,7 +91,7 @@ public class AdministrationController {
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "org/admin/settings/password", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.OK)
public @ResponseBody EntityIdentifier updateUserDetails(HttpServletRequest request,
public @ResponseBody EntityIdentifier updateUserDetails(
@RequestParam(value="password", required=false) String password,
@RequestParam(value="passwordrepeat", required=false) String passwordrepeat) {
@@ -8,15 +8,13 @@ import java.util.Collection;
import java.util.List;
import java.util.Locale;
import javax.servlet.http.HttpServletRequest;
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.CreateLoanProductCommand;
import org.mifosng.data.command.UpdateLoanProductCommand;
import org.mifosng.data.command.LoanProductCommand;
import org.mifosng.ui.CommonRestOperations;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
@@ -90,7 +88,7 @@ public class LoanProductController {
@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(HttpServletRequest request,
public @ResponseBody EntityIdentifier createLoanProduct(
@RequestParam("name") String name,
@RequestParam("description") String description,
@RequestParam("selectedCurrency") String currencyCode, @RequestParam("selectedDigitsAfterDecimal") Integer digitsAfterDecimal,
@@ -106,7 +104,7 @@ public class LoanProductController {
@RequestParam(value="interestRateCalculatedInPeriod", required=false) Integer interestCalculationPeriodMethod
) {
CreateLoanProductCommand command = new CreateLoanProductCommand();
LoanProductCommand command = new LoanProductCommand();
command.setName(name);
command.setDescription(description);
command.setCurrencyCode(currencyCode);
@@ -146,7 +144,7 @@ public class LoanProductController {
@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, HttpServletRequest request,
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,
@@ -161,7 +159,7 @@ public class LoanProductController {
@RequestParam(value="interestRateCalculatedInPeriod", required=false) Integer interestCalculationPeriodMethod
) {
UpdateLoanProductCommand command = new UpdateLoanProductCommand();
LoanProductCommand command = new LoanProductCommand();
command.setId(productId);
command.setName(name);
command.setDescription(description);
@@ -5,7 +5,6 @@ import java.util.Collection;
import java.util.List;
import java.util.Locale;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
@@ -94,7 +93,7 @@ public class OfficeController {
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/org/office/new", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.OK)
public @ResponseBody EntityIdentifier createOffice(HttpServletRequest request,
public @ResponseBody EntityIdentifier createOffice(
@RequestParam("name") String name,
@RequestParam(value="parentId", required=false) Long parentId,
@RequestParam("openingDate") String openingDate,
@@ -114,7 +113,7 @@ public class OfficeController {
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/org/office/{officeId}", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.OK)
public @ResponseBody EntityIdentifier updateOffice(HttpServletRequest request, @PathVariable("officeId") final Long officeId,
public @ResponseBody EntityIdentifier updateOffice(@PathVariable("officeId") final Long officeId,
@RequestParam("name") String name,
@RequestParam(value="parentId", required=false) Long parentId,
@RequestParam("openingDate") String openingDate,
@@ -1,219 +0,0 @@
package org.mifosng.platform;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.mifosng.data.ErrorResponse;
import org.mifosng.data.command.CreateLoanProductCommand;
import org.mifosng.data.command.LoanProductCommandData;
import org.mifosng.data.command.UpdateLoanProductCommand;
import org.mifosng.platform.exceptions.NewDataValidationException;
import org.mifosng.platform.loan.domain.AmortizationMethod;
import org.mifosng.platform.loan.domain.InterestMethod;
import org.mifosng.platform.loan.domain.PeriodFrequencyType;
public class LoanProductValidator {
public void validateForUpdate(UpdateLoanProductCommand command) {
List<ErrorResponse> dataValidationErrors = new ArrayList<ErrorResponse>();
Long productId = command.getId();
if (productId == null) {
ErrorResponse error = new ErrorResponse("validation.msg.product.id.cannot.be.empty", "id");
dataValidationErrors.add(error);
}
validateRemainingAttributes(command, dataValidationErrors);
}
public void validateForCreate(CreateLoanProductCommand command) {
List<ErrorResponse> dataValidationErrors = new ArrayList<ErrorResponse>();
validateRemainingAttributes(command, dataValidationErrors);
}
private void validateRemainingAttributes(LoanProductCommandData command, List<ErrorResponse> dataValidationErrors) {
if (StringUtils.isBlank(command.getName())) {
ErrorResponse error = new ErrorResponse("validation.msg.product.name.cannot.be.blank", "name");
dataValidationErrors.add(error);
}
if (command.getDescription() != null) {
if (command.getDescription().length() > 500) {
ErrorResponse error = new ErrorResponse("validation.msg.product.description.exceeds.max.length", "description");
dataValidationErrors.add(error);
}
}
if (StringUtils.isBlank(command.getCurrencyCode())) {
ErrorResponse error = new ErrorResponse("validation.msg.product.currency.cannot.be.empty", "currencyCode");
dataValidationErrors.add(error);
}
if (command.getDigitsAfterDecimal() != null) {
if (command.getDigitsAfterDecimal() < 0 || command.getDigitsAfterDecimal() > 6) {
ErrorResponse error = new ErrorResponse("validation.msg.product.currency.digitsAfterDecimal.must.be.between.zero.and.six.inclusive", "selectedDigitsAfterDecimal", command.getDigitsAfterDecimal());
dataValidationErrors.add(error);
}
} else {
ErrorResponse error = new ErrorResponse("validation.msg.product.currency.digitsAfterDecimal.cannot.be.empty", "selectedDigitsAfterDecimal");
dataValidationErrors.add(error);
}
if (command.getPrincipal() != null) {
if (command.getPrincipal().doubleValue() <= Double.valueOf("0.0")) {
ErrorResponse error = new ErrorResponse("validation.msg.product.principal.amount.must.be.greater.than.zero", "amount");
dataValidationErrors.add(error);
}
// TODO - check number of digits before decimal and after decimal
} else {
ErrorResponse error = new ErrorResponse("validation.msg.product.principal.amount.cannot.be.empty", "amount");
dataValidationErrors.add(error);
}
if (command.getRepaymentFrequency() != null) {
PeriodFrequencyType frequencyType = PeriodFrequencyType.fromInt(command.getRepaymentFrequency());
ErrorResponse error = null;
switch (frequencyType) {
case DAYS:
error = validateNumberExistsAndInRange("validation.msg.product.repayment.repaidEvery", "repaidEvery", command.getRepaymentEvery(), 1, 365);
break;
case WEEKS:
error = validateNumberExistsAndInRange("validation.msg.product.repayment.repaidEvery", "repaidEvery", command.getRepaymentEvery(), 1, 52);
break;
case MONTHS:
error = validateNumberExistsAndInRange("validation.msg.product.repayment.repaidEvery", "repaidEvery", command.getRepaymentEvery(), 1, 12);
break;
case YEARS:
error = validateNumberExistsAndInRange("validation.msg.product.repayment.repaidEvery", "repaidEvery", command.getRepaymentEvery(), 1, 2);
break;
default:
error = new ErrorResponse("validation.msg.product.repayment.frequency.invalid", "selectedRepaymentFrequencyOption");
break;
}
if (error != null) {
dataValidationErrors.add(error);
}
} else {
ErrorResponse error = new ErrorResponse("validation.msg.product.repayment.frequency.cannot.be.empty", "selectedRepaymentFrequencyOption");
dataValidationErrors.add(error);
}
if (command.getNumberOfRepayments() != null) {
if (command.getNumberOfRepayments() < 1 || command.getNumberOfRepayments() > 100) {
ErrorResponse error = new ErrorResponse("validation.msg.product.number.of.repayments.is.out.of.range", "numberOfRepayments");
dataValidationErrors.add(error);
}
} else {
ErrorResponse error = new ErrorResponse("validation.msg.product.number.of.repayments.cannot.be.empty", "numberOfRepayments");
dataValidationErrors.add(error);
}
if (command.getAmortizationMethod() != null) {
AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.getAmortizationMethod());
ErrorResponse error = null;
switch (amortizationMethod) {
case EQUAL_PRINCIPAL:
break;
case EQUAL_INSTALLMENTS:
break;
default:
error = new ErrorResponse("validation.msg.product.amortization.method.invalid", "selectedAmortizationMethodOption");
break;
}
if (error != null) {
dataValidationErrors.add(error);
}
} else {
ErrorResponse error = new ErrorResponse("validation.msg.product.amortization.method.cannot.be.empty", "selectedAmortizationMethodOption");
dataValidationErrors.add(error);
}
// refactor in validation of monetary value.
if (command.getInArrearsToleranceAmount() != null) {
if (command.getInArrearsToleranceAmount().doubleValue() < Double.valueOf("0.0")) {
ErrorResponse error = new ErrorResponse("validation.msg.product.arrears.tolerance.amount.cannot.be.negative", "inArrearsTolerance");
dataValidationErrors.add(error);
}
} else {
ErrorResponse error = new ErrorResponse("validation.msg.product.arrears.tolerance.amount.cannot.be.empty", "inArrearsTolerance");
dataValidationErrors.add(error);
}
if (command.getInterestRatePerPeriod()!= null) {
if (command.getInterestRatePerPeriod().doubleValue() < Double.valueOf("0.0")) {
ErrorResponse error = new ErrorResponse("validation.msg.product.interest.rate.per.period.amount.cannot.be.negative", "nominalInterestRate");
dataValidationErrors.add(error);
}
} else {
ErrorResponse error = new ErrorResponse("validation.msg.product.interest.rate.per.period.amount.cannot.be.empty", "nominalInterestRate");
dataValidationErrors.add(error);
}
// interest rate period type
if (command.getInterestRateFrequencyMethod() != null) {
PeriodFrequencyType frequencyType = PeriodFrequencyType.fromInt(command.getInterestRateFrequencyMethod());
ErrorResponse error = null;
switch (frequencyType) {
case DAYS:
break;
case WEEKS:
break;
case MONTHS:
break;
case YEARS:
break;
default:
error = new ErrorResponse("validation.msg.product.interest.frequency.invalid", "selectedInterestFrequencyOption");
break;
}
if (error != null) {
dataValidationErrors.add(error);
}
} else {
ErrorResponse error = new ErrorResponse("validation.msg.product.interest.frequency.cannot.be.empty", "selectedInterestFrequencyOption");
dataValidationErrors.add(error);
}
if (command.getInterestMethod() != null) {
InterestMethod interestMethod = InterestMethod.fromInt(command.getInterestMethod());
ErrorResponse error = null;
switch (interestMethod) {
case DECLINING_BALANCE:
break;
case FLAT:
break;
default:
error = new ErrorResponse("validation.msg.product.interest.method.invalid", "selectedInterestMethodOption");
break;
}
if (error != null) {
dataValidationErrors.add(error);
}
} else {
ErrorResponse error = new ErrorResponse("validation.msg.product.interest.method.cannot.be.empty", "selectedInterestMethodOption");
dataValidationErrors.add(error);
}
if (!dataValidationErrors.isEmpty()) {
throw new NewDataValidationException(dataValidationErrors, "Validation errors exist.");
}
}
private ErrorResponse validateNumberExistsAndInRange(String errorCodePreFix, String fieldName, Integer value, int min, int max) {
ErrorResponse error = null;
if (value == null) {
error = new ErrorResponse(errorCodePreFix + ".cannot.be.empty", fieldName);
} else {
if (value < min || value > max) {
error = new ErrorResponse(errorCodePreFix + ".outside.allowed.range", fieldName);
}
}
return error;
}
}
@@ -33,7 +33,6 @@ import org.mifosng.data.ClientDataWithAccountsData;
import org.mifosng.data.CurrencyData;
import org.mifosng.data.DerivedLoanData;
import org.mifosng.data.EnumOptionReadModel;
import org.mifosng.data.ErrorResponse;
import org.mifosng.data.ExtraDatasetRow;
import org.mifosng.data.ExtraDatasets;
import org.mifosng.data.LoanAccountData;
@@ -3,8 +3,8 @@ package org.mifosng.platform;
import org.mifosng.data.EntityIdentifier;
import org.mifosng.data.command.AdjustLoanTransactionCommand;
import org.mifosng.data.command.ChangePasswordCommand;
import org.mifosng.data.command.CreateLoanProductCommand;
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;
@@ -14,7 +14,6 @@ import org.mifosng.data.command.SignupCommand;
import org.mifosng.data.command.SubmitLoanApplicationCommand;
import org.mifosng.data.command.UndoLoanApprovalCommand;
import org.mifosng.data.command.UndoLoanDisbursalCommand;
import org.mifosng.data.command.UpdateLoanProductCommand;
import org.mifosng.data.command.UpdateOrganisationCurrencyCommand;
import org.mifosng.data.command.UpdateUsernamePasswordCommand;
import org.mifosng.data.command.UserCommand;
@@ -53,9 +52,9 @@ public interface WritePlatformService {
void updateOrganisationCurrencies(UpdateOrganisationCurrencyCommand command);
EntityIdentifier createLoanProduct(CreateLoanProductCommand command);
EntityIdentifier createLoanProduct(LoanProductCommand command);
EntityIdentifier updateLoanProduct(UpdateLoanProductCommand command);
EntityIdentifier updateLoanProduct(LoanProductCommand command);
@PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE', 'CAN_DELETE_LOAN_THAT_IS_SUBMITTED_AND_NOT_APPROVED')")
EntityIdentifier deleteLoan(Long loanId);
@@ -24,8 +24,8 @@ import org.mifosng.data.ScheduledLoanInstallment;
import org.mifosng.data.command.AdjustLoanTransactionCommand;
import org.mifosng.data.command.CalculateLoanScheduleCommand;
import org.mifosng.data.command.ChangePasswordCommand;
import org.mifosng.data.command.CreateLoanProductCommand;
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;
@@ -35,7 +35,6 @@ import org.mifosng.data.command.SignupCommand;
import org.mifosng.data.command.SubmitLoanApplicationCommand;
import org.mifosng.data.command.UndoLoanApprovalCommand;
import org.mifosng.data.command.UndoLoanDisbursalCommand;
import org.mifosng.data.command.UpdateLoanProductCommand;
import org.mifosng.data.command.UpdateOrganisationCurrencyCommand;
import org.mifosng.data.command.UpdateUsernamePasswordCommand;
import org.mifosng.data.command.UserCommand;
@@ -74,6 +73,7 @@ import org.mifosng.platform.loan.domain.LoanStatusRepository;
import org.mifosng.platform.loan.domain.LoanTransaction;
import org.mifosng.platform.loan.domain.LoanTransactionRepository;
import org.mifosng.platform.loan.domain.PeriodFrequencyType;
import org.mifosng.platform.loanproduct.service.LoanProductCommandValidator;
import org.mifosng.platform.organisation.domain.Office;
import org.mifosng.platform.organisation.domain.OfficeRepository;
import org.mifosng.platform.organisation.domain.Organisation;
@@ -444,11 +444,11 @@ public class WritePlatformServiceJpaRepositoryImpl implements
@Transactional
@Override
public EntityIdentifier createLoanProduct(final CreateLoanProductCommand command) {
public EntityIdentifier createLoanProduct(final LoanProductCommand command) {
AppUser currentUser = extractAuthenticatedUser();
LoanProductValidator validator = new LoanProductValidator();
LoanProductCommandValidator validator = new LoanProductCommandValidator();
validator.validateForCreate(command);
// assemble LoanProduct from data
@@ -496,11 +496,11 @@ public class WritePlatformServiceJpaRepositoryImpl implements
@Transactional
@Override
public EntityIdentifier updateLoanProduct(UpdateLoanProductCommand command) {
public EntityIdentifier updateLoanProduct(LoanProductCommand command) {
AppUser currentUser = extractAuthenticatedUser();
LoanProductValidator validator = new LoanProductValidator();
LoanProductCommandValidator validator = new LoanProductCommandValidator();
validator.validateForUpdate(command);
LoanProduct product = this.loanProductRepository.findOne(productThatMatches(currentUser.getOrganisation(), command.getId()));
@@ -6,7 +6,6 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
@@ -25,8 +24,8 @@ import org.mifosng.data.ErrorResponseList;
import org.mifosng.data.reports.GenericResultset;
import org.mifosng.platform.ReadPlatformService;
import org.mifosng.platform.exceptions.ApplicationDomainRuleException;
import org.mifosng.platform.exceptions.UnAuthenticatedUserException;
import org.mifosng.platform.exceptions.NewDataValidationException;
import org.mifosng.platform.exceptions.UnAuthenticatedUserException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -48,7 +47,7 @@ public class FlexibleReportingApiResource {
@Path("flexireport")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Response retrieveReport(@Context UriInfo uriInfo, @Context HttpServletResponse httpServletResponse) {
public Response retrieveReport(@Context UriInfo uriInfo) {
MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();
String rptDB = queryParams.getFirst("MRP_rptDB");
@@ -1,4 +1,4 @@
package org.mifosng.platform.api;
package org.mifosng.platform.api.loanproduct;
import java.util.Collection;
@@ -9,21 +9,15 @@ import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.mifosng.data.EntityIdentifier;
import org.mifosng.data.ErrorResponseList;
import org.mifosng.data.LoanProductData;
import org.mifosng.data.LoanProductList;
import org.mifosng.data.command.CreateLoanProductCommand;
import org.mifosng.data.command.UpdateLoanProductCommand;
import org.mifosng.platform.ReadPlatformService;
import org.mifosng.platform.WritePlatformService;
import org.mifosng.platform.exceptions.ApplicationDomainRuleException;
import org.mifosng.platform.exceptions.NewDataValidationException;
import org.mifosng.data.command.LoanProductCommand;
import org.mifosng.platform.loanproduct.service.LoanProductReadPlatformService;
import org.mifosng.platform.loanproduct.service.LoanProductWritePlatformService;
import org.mifosng.platform.user.domain.AppUser;
import org.mifosng.platform.user.domain.AppUserRepository;
import org.springframework.beans.factory.annotation.Autowired;
@@ -59,10 +53,10 @@ import org.springframework.stereotype.Component;
public class LoanProductApiResource {
@Autowired
private ReadPlatformService readPlatformService;
private LoanProductReadPlatformService loanProductReadPlatformService;
@Autowired
private WritePlatformService writePlatformService;
private LoanProductWritePlatformService loanProductWritePlatformService;
@Autowired
private AppUserRepository appUserRepository;
@@ -99,20 +93,13 @@ public class LoanProductApiResource {
@POST
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Produces({ MediaType.APPLICATION_JSON})
public Response createLoanProduct(CreateLoanProductCommand command) {
public Response createLoanProduct(LoanProductCommand command) {
try {
// TODO - move CreateLoanProductCommand and UpdateLoanProductCommand into one.
hardcodeUserIntoSecurityContext();
EntityIdentifier entityIdentifier = this.writePlatformService.createLoanProduct(command);
hardcodeUserIntoSecurityContext();
EntityIdentifier entityIdentifier = this.loanProductWritePlatformService.createLoanProduct(command);
return Response.ok().entity(entityIdentifier).build();
} catch (ApplicationDomainRuleException e) {
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getErrors())).build());
} catch (NewDataValidationException e) {
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getValidationErrors())).build());
}
return Response.ok().entity(entityIdentifier).build();
}
@GET
@@ -120,17 +107,11 @@ public class LoanProductApiResource {
@Produces({MediaType.APPLICATION_JSON})
public Response retrieveAllLoanProducts() {
try {
hardcodeUserIntoSecurityContext();
Collection<LoanProductData> products = this.readPlatformService.retrieveAllLoanProducts();
hardcodeUserIntoSecurityContext();
Collection<LoanProductData> products = this.loanProductReadPlatformService.retrieveAllLoanProducts();
return Response.ok().entity(new LoanProductList(products)).build();
} catch (ApplicationDomainRuleException e) {
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getErrors())).build());
} catch (NewDataValidationException e) {
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getValidationErrors())).build());
}
return Response.ok().entity(new LoanProductList(products)).build();
}
/*
@@ -142,17 +123,11 @@ public class LoanProductApiResource {
@Produces({ MediaType.APPLICATION_JSON})
public Response retrieveNewLoanProductDetails() {
try {
hardcodeUserIntoSecurityContext();
LoanProductData loanProduct = this.readPlatformService.retrieveNewLoanProductDetails();
hardcodeUserIntoSecurityContext();
LoanProductData loanProduct = this.loanProductReadPlatformService.retrieveNewLoanProductDetails();
return Response.ok().entity(loanProduct).build();
} catch (ApplicationDomainRuleException e) {
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getErrors())).build());
} catch (NewDataValidationException e) {
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getValidationErrors())).build());
}
return Response.ok().entity(loanProduct).build();
}
@GET
@@ -161,17 +136,11 @@ public class LoanProductApiResource {
@Produces({ MediaType.APPLICATION_JSON})
public Response retrieveLoanProductDetails(@PathParam("productId") final Long productId) {
try {
hardcodeUserIntoSecurityContext();
LoanProductData loanProduct = this.readPlatformService.retrieveLoanProduct(productId);
hardcodeUserIntoSecurityContext();
LoanProductData loanProduct = this.loanProductReadPlatformService.retrieveLoanProduct(productId);
return Response.ok().entity(loanProduct).build();
} catch (ApplicationDomainRuleException e) {
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getErrors())).build());
} catch (NewDataValidationException e) {
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getValidationErrors())).build());
}
return Response.ok().entity(loanProduct).build();
}
// example PUT request
@@ -201,18 +170,13 @@ public class LoanProductApiResource {
@Path("{productId}")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Produces({ MediaType.APPLICATION_JSON })
public Response updateLoanProduct(@PathParam("productId") final Long productId, final UpdateLoanProductCommand command) {
public Response updateLoanProduct(@PathParam("productId") final Long productId, final LoanProductCommand command) {
try {
hardcodeUserIntoSecurityContext();
EntityIdentifier entityIdentifier = this.writePlatformService.updateLoanProduct(command);
return Response.ok().entity(entityIdentifier).build();
} catch (ApplicationDomainRuleException e) {
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getErrors())).build());
} catch (NewDataValidationException e) {
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getValidationErrors())).build());
}
hardcodeUserIntoSecurityContext();
command.setId(productId);
EntityIdentifier entityIdentifier = this.loanProductWritePlatformService.updateLoanProduct(command);
return Response.ok().entity(entityIdentifier).build();
}
}
@@ -16,8 +16,8 @@ import org.mifosng.data.EntityIdentifier;
import org.mifosng.data.OfficeData;
import org.mifosng.data.OfficeList;
import org.mifosng.data.command.OfficeCommand;
import org.mifosng.platform.WritePlatformService;
import org.mifosng.platform.organisation.service.OfficeReadPlatformService;
import org.mifosng.platform.organisation.service.OfficeWritePlatformService;
import org.mifosng.platform.user.domain.AppUser;
import org.mifosng.platform.user.domain.AppUserRepository;
import org.springframework.beans.factory.annotation.Autowired;
@@ -37,7 +37,7 @@ public class OfficeApiResource {
private OfficeReadPlatformService readPlatformService;
@Autowired
private WritePlatformService writePlatformService;
private OfficeWritePlatformService writePlatformService;
@Autowired
private AppUserRepository appUserRepository;
@@ -0,0 +1,12 @@
package org.mifosng.platform.currency.service;
import java.util.List;
import org.mifosng.data.CurrencyData;
public interface CurrencyReadPlatformService {
List<CurrencyData> retrieveAllowedCurrencies();
List<CurrencyData> retrieveAllPlatformCurrencies();
}
@@ -0,0 +1,68 @@
package org.mifosng.platform.currency.service;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import javax.sql.DataSource;
import org.mifosng.data.CurrencyData;
import org.mifosng.platform.security.PlatformSecurityContext;
import org.mifosng.platform.user.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.stereotype.Service;
@Service
public class CurrencyReadPlatformServiceImpl implements CurrencyReadPlatformService {
private final SimpleJdbcTemplate jdbcTemplate;
private final PlatformSecurityContext context;
@Autowired
public CurrencyReadPlatformServiceImpl(final PlatformSecurityContext context, final DataSource dataSource) {
this.context = context;
this.jdbcTemplate = new SimpleJdbcTemplate(dataSource);
}
@Override
public List<CurrencyData> retrieveAllowedCurrencies() {
AppUser currentUser = context.authenticatedUser();
String sql = "select c.code as code, c.name as name, c.decimal_places as decimalPlaces, c.display_symbol as displaySymbol, c.internationalized_name_code as nameCode from org_organisation_currency c where c.org_id = ?";
RowMapper<CurrencyData> rm = new CurrencyMapper();
return this.jdbcTemplate.query(sql, rm, new Object[] { currentUser
.getOrganisation().getId() });
}
@Override
public List<CurrencyData> retrieveAllPlatformCurrencies() {
String sql = "select c.code as code, c.name as name, c.decimal_places as decimalPlaces, c.display_symbol as displaySymbol, c.internationalized_name_code as nameCode from ref_currency c";
RowMapper<CurrencyData> rm = new CurrencyMapper();
return this.jdbcTemplate.query(sql, rm, new Object[] {});
}
private static final class CurrencyMapper implements RowMapper<CurrencyData> {
@Override
public CurrencyData mapRow(final ResultSet rs, final int rowNum)
throws SQLException {
String code = rs.getString("code");
String name = rs.getString("name");
int decimalPlaces = rs.getInt("decimalPlaces");
String displaySymbol = rs.getString("displaySymbol");
String nameCode = rs.getString("nameCode");
return new CurrencyData(code, name, decimalPlaces, displaySymbol,
nameCode);
}
}
}
@@ -10,7 +10,7 @@ import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.apache.commons.lang.StringUtils;
import org.mifosng.data.command.UpdateLoanProductCommand;
import org.mifosng.data.command.LoanProductCommand;
import org.mifosng.platform.currency.domain.MonetaryCurrency;
import org.mifosng.platform.currency.domain.Money;
import org.mifosng.platform.infrastructure.AbstractAuditableCustom;
@@ -134,7 +134,7 @@ public class LoanProduct extends AbstractAuditableCustom<AppUser, Long> {
return this.loanProductRelatedDetail.getAmortizationMethod();
}
public void update(UpdateLoanProductCommand command) {
public void update(LoanProductCommand command) {
this.name = command.getName();
this.description = command.getDescription();
this.loanProductRelatedDetail.update(command);
@@ -8,7 +8,7 @@ import javax.persistence.Embedded;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import org.mifosng.data.command.UpdateLoanProductCommand;
import org.mifosng.data.command.LoanProductCommand;
import org.mifosng.platform.currency.domain.MonetaryCurrency;
import org.mifosng.platform.currency.domain.Money;
@@ -173,7 +173,7 @@ public class LoanProductRelatedDetail implements
return interestRebateAllowed;
}
public void update(UpdateLoanProductCommand command) {
public void update(LoanProductCommand command) {
this.currency = new MonetaryCurrency(command.getCurrencyCode(), command.getDigitsAfterDecimal());
this.principal = command.getPrincipal();
@@ -0,0 +1,18 @@
package org.mifosng.platform.loanproduct.service;
import java.util.List;
import org.mifosng.data.EnumOptionReadModel;
public interface LoanDropdownReadPlatformService {
List<EnumOptionReadModel> retrieveLoanAmortizationMethodOptions();
List<EnumOptionReadModel> retrieveLoanInterestMethodOptions();
List<EnumOptionReadModel> retrieveLoanInterestRateCalculatedInPeriodOptions();
List<EnumOptionReadModel> retrieveRepaymentFrequencyOptions();
List<EnumOptionReadModel> retrieveInterestFrequencyOptions();
}
@@ -0,0 +1,99 @@
package org.mifosng.platform.loanproduct.service;
import java.util.Arrays;
import java.util.List;
import javax.sql.DataSource;
import org.mifosng.data.EnumOptionReadModel;
import org.mifosng.platform.loan.domain.AmortizationMethod;
import org.mifosng.platform.loan.domain.PeriodFrequencyType;
import org.mifosng.platform.security.PlatformSecurityContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.stereotype.Service;
/*
* FIXME - remove hardcoded return of loan dropdown options
*/
@SuppressWarnings("unused")
@Service
public class LoanDropdownReadPlatformServiceImpl implements LoanDropdownReadPlatformService {
private final PlatformSecurityContext context;
private final SimpleJdbcTemplate jdbcTemplate;
@Autowired
public LoanDropdownReadPlatformServiceImpl(final PlatformSecurityContext context, final DataSource dataSource) {
this.context = context;
this.jdbcTemplate = new SimpleJdbcTemplate(dataSource);
}
@Override
public List<EnumOptionReadModel> retrieveLoanAmortizationMethodOptions() {
EnumOptionReadModel equalInstallments = new EnumOptionReadModel(
"Equal installments", AmortizationMethod.EQUAL_INSTALLMENTS
.getValue().longValue());
EnumOptionReadModel equalPrinciplePayments = new EnumOptionReadModel(
"Equal principle payments", AmortizationMethod.EQUAL_PRINCIPAL
.getValue().longValue());
List<EnumOptionReadModel> allowedAmortizationMethods = Arrays.asList(
equalInstallments, equalPrinciplePayments);
return allowedAmortizationMethods;
}
@Override
public List<EnumOptionReadModel> retrieveLoanInterestMethodOptions() {
EnumOptionReadModel interestRateCalculationMethod2 = new EnumOptionReadModel(
"Declining Balance", Long.valueOf(0));
EnumOptionReadModel interestRateCalculationMethod1 = new EnumOptionReadModel(
"Flat", Long.valueOf(1));
List<EnumOptionReadModel> allowedRepaymentScheduleCalculationMethods = Arrays
.asList(interestRateCalculationMethod2,
interestRateCalculationMethod1);
return allowedRepaymentScheduleCalculationMethods;
}
@Override
public List<EnumOptionReadModel> retrieveLoanInterestRateCalculatedInPeriodOptions() {
EnumOptionReadModel option1 = new EnumOptionReadModel("Daily",
Long.valueOf(0));
EnumOptionReadModel option2 = new EnumOptionReadModel(
"Same as repayment period", Long.valueOf(1));
List<EnumOptionReadModel> allowedOptions = Arrays.asList(option1,
option2);
return allowedOptions;
}
@Override
public List<EnumOptionReadModel> retrieveRepaymentFrequencyOptions() {
EnumOptionReadModel frequency1 = new EnumOptionReadModel("Days",
Long.valueOf(0));
EnumOptionReadModel frequency2 = new EnumOptionReadModel("Weeks",
Long.valueOf(1));
EnumOptionReadModel frequency3 = new EnumOptionReadModel("Months",
Long.valueOf(2));
List<EnumOptionReadModel> repaymentFrequencyOptions = Arrays.asList(
frequency1, frequency2, frequency3);
return repaymentFrequencyOptions;
}
@Override
public List<EnumOptionReadModel> retrieveInterestFrequencyOptions() {
// support for monthly and annual percentage rate (MPR) and (APR)
EnumOptionReadModel perMonth = new EnumOptionReadModel("Per month",
PeriodFrequencyType.MONTHS.getValue().longValue());
EnumOptionReadModel perYear = new EnumOptionReadModel("Per year",
PeriodFrequencyType.YEARS.getValue().longValue());
List<EnumOptionReadModel> repaymentFrequencyOptions = Arrays.asList(
perMonth, perYear);
return repaymentFrequencyOptions;
}
}
@@ -0,0 +1,230 @@
package org.mifosng.platform.loanproduct.service;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.mifosng.data.ApiParameterError;
import org.mifosng.data.command.LoanProductCommand;
import org.mifosng.data.command.LoanProductCommandData;
import org.mifosng.platform.exceptions.PlatformApiDataValidationException;
import org.mifosng.platform.loan.domain.AmortizationMethod;
import org.mifosng.platform.loan.domain.InterestMethod;
import org.mifosng.platform.loan.domain.PeriodFrequencyType;
public class LoanProductCommandValidator {
public void validateForUpdate(LoanProductCommand command) {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
Long productId = command.getId();
if (productId == null) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.id.cannot.be.empty", "The parameter id cannot be blank.", "id");
dataValidationErrors.add(error);
}
validateRemainingAttributes(command, dataValidationErrors);
}
public void validateForCreate(LoanProductCommand command) {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
validateRemainingAttributes(command, dataValidationErrors);
}
private void validateRemainingAttributes(LoanProductCommandData command, List<ApiParameterError> dataValidationErrors) {
if (StringUtils.isBlank(command.getName())) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.name.cannot.be.blank", "The parameter name cannot be blank.", "name");
dataValidationErrors.add(error);
}
if (command.getDescription() != null) {
if (command.getDescription().length() > 500) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.description.exceeds.max.length", "The parameter description cannot exceed max length of {}.", "description", 500);
dataValidationErrors.add(error);
}
}
if (StringUtils.isBlank(command.getCurrencyCode())) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.currency.cannot.be.empty", "The parameter currencyCode cannot be blank.", "currencyCode");
dataValidationErrors.add(error);
}
if (command.getDigitsAfterDecimal() != null) {
if (command.getDigitsAfterDecimal() < 0 || command.getDigitsAfterDecimal() > 6) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.currency.digitsAfterDecimal.must.be.between.zero.and.six.inclusive", "The parameter digitsAfterDecimal must be between {0} and {1} inclusive.", "selectedDigitsAfterDecimal", 0, 6);
dataValidationErrors.add(error);
}
} else {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.currency.digitsAfterDecimal.cannot.be.empty", "The parameter digitsAfterDecimal cannot be blank.", "selectedDigitsAfterDecimal");
dataValidationErrors.add(error);
}
if (command.getPrincipal() != null) {
if (command.getPrincipal().doubleValue() <= Double.valueOf("0.0")) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.principal.amount.must.be.greater.than.zero", "The parameter amount must be greater than zero.", "amount");
dataValidationErrors.add(error);
}
// TODO - check number of digits before decimal and after decimal
} else {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.principal.amount.cannot.be.empty", "The parameter amount cannot be blank.", "amount");
dataValidationErrors.add(error);
}
if (command.getRepaymentFrequency() != null) {
PeriodFrequencyType frequencyType = PeriodFrequencyType.fromInt(command.getRepaymentFrequency());
ApiParameterError error = null;
switch (frequencyType) {
case DAYS:
error = validateNumberExistsAndInRange("validation.msg.product.repayment.repaidEvery", "repaidEvery", command.getRepaymentEvery(), 1, 365);
break;
case WEEKS:
error = validateNumberExistsAndInRange("validation.msg.product.repayment.repaidEvery", "repaidEvery", command.getRepaymentEvery(), 1, 52);
break;
case MONTHS:
error = validateNumberExistsAndInRange("validation.msg.product.repayment.repaidEvery", "repaidEvery", command.getRepaymentEvery(), 1, 12);
break;
case YEARS:
error = validateNumberExistsAndInRange("validation.msg.product.repayment.repaidEvery", "repaidEvery", command.getRepaymentEvery(), 1, 2);
break;
default:
error = ApiParameterError.parameterError("validation.msg.product.repayment.frequency.invalid", "The parameter selectedRepaymentFrequencyOption is invalid.", "selectedRepaymentFrequencyOption");
break;
}
if (error != null) {
dataValidationErrors.add(error);
}
} else {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.repayment.frequency.cannot.be.empty",
"The parameter selectedRepaymentFrequencyOption cannot be blank.", "selectedRepaymentFrequencyOption");
dataValidationErrors.add(error);
}
if (command.getNumberOfRepayments() != null) {
if (command.getNumberOfRepayments() < 1 || command.getNumberOfRepayments() > 100) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.number.of.repayments.is.out.of.range",
"The parameter numberOfRepayments must be between {} and {} inclusive.", "numberOfRepayments", 1, 100);
dataValidationErrors.add(error);
}
} else {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.number.of.repayments.cannot.be.empty",
"The parameter numberOfRepayments cannot be empty.", "numberOfRepayments");
dataValidationErrors.add(error);
}
if (command.getAmortizationMethod() != null) {
AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.getAmortizationMethod());
ApiParameterError error = null;
switch (amortizationMethod) {
case EQUAL_PRINCIPAL:
break;
case EQUAL_INSTALLMENTS:
break;
default:
error = ApiParameterError.parameterError("validation.msg.product.amortization.method.invalid",
"The parameter selectedAmortizationMethodOption cannot be empty.", "selectedAmortizationMethodOption");
break;
}
if (error != null) {
dataValidationErrors.add(error);
}
} else {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.amortization.method.cannot.be.empty",
"The parameter selectedAmortizationMethodOption cannot be empty.", "selectedAmortizationMethodOption");
dataValidationErrors.add(error);
}
// refactor in validation of monetary value.
if (command.getInArrearsToleranceAmount() != null) {
if (command.getInArrearsToleranceAmount().doubleValue() < Double.valueOf("0.0")) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.arrears.tolerance.amount.cannot.be.negative",
"The parameter inArrearsTolerance cannot be less than zero.", "inArrearsTolerance");
dataValidationErrors.add(error);
}
} else {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.arrears.tolerance.amount.cannot.be.empty",
"The parameter inArrearsTolerance cannot be empty.", "inArrearsTolerance");
dataValidationErrors.add(error);
}
if (command.getInterestRatePerPeriod()!= null) {
if (command.getInterestRatePerPeriod().doubleValue() < Double.valueOf("0.0")) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.interest.rate.per.period.amount.cannot.be.negative",
"The parameter nominalInterestRate cannot be less than zero.", "nominalInterestRate");
dataValidationErrors.add(error);
}
} else {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.interest.rate.per.period.amount.cannot.be.empty",
"The parameter nominalInterestRate cannot be empty.", "nominalInterestRate");
dataValidationErrors.add(error);
}
// interest rate period type
if (command.getInterestRateFrequencyMethod() != null) {
PeriodFrequencyType frequencyType = PeriodFrequencyType.fromInt(command.getInterestRateFrequencyMethod());
ApiParameterError error = null;
switch (frequencyType) {
case DAYS:
break;
case WEEKS:
break;
case MONTHS:
break;
case YEARS:
break;
default:
error = ApiParameterError.parameterError("validation.msg.product.interest.frequency.invalid",
"The parameter selectedInterestFrequencyOption is invalid.", "selectedInterestFrequencyOption");
break;
}
if (error != null) {
dataValidationErrors.add(error);
}
} else {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.interest.frequency.cannot.be.empty",
"The parameter selectedInterestFrequencyOption cannot be empty.", "selectedInterestFrequencyOption");
dataValidationErrors.add(error);
}
if (command.getInterestMethod() != null) {
InterestMethod interestMethod = InterestMethod.fromInt(command.getInterestMethod());
ApiParameterError error = null;
switch (interestMethod) {
case DECLINING_BALANCE:
break;
case FLAT:
break;
default:
error = ApiParameterError.parameterError("validation.msg.product.interest.method.invalid",
"The parameter selectedInterestMethodOption is invalid.", "selectedInterestMethodOption");
break;
}
if (error != null) {
dataValidationErrors.add(error);
}
} else {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.interest.method.cannot.be.empty",
"The parameter selectedInterestMethodOption cannot be empty.", "selectedInterestMethodOption");
dataValidationErrors.add(error);
}
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors);
}
}
private ApiParameterError validateNumberExistsAndInRange(String errorCodePreFix, String fieldName, Integer value, int min, int max) {
ApiParameterError error = null;
if (value == null) {
error = ApiParameterError.parameterError(errorCodePreFix + ".cannot.be.empty", "The parameter " + fieldName + " cannot be blank.", fieldName);
} else {
if (value < min || value > max) {
error = ApiParameterError.parameterError(errorCodePreFix + ".outside.allowed.range", "The parameter " + fieldName + " must be between {0} and {1} inclusive.", fieldName, min, max);
}
}
return error;
}
}
@@ -0,0 +1,14 @@
package org.mifosng.platform.loanproduct.service;
import java.util.Collection;
import org.mifosng.data.LoanProductData;
public interface LoanProductReadPlatformService {
Collection<LoanProductData> retrieveAllLoanProducts();
LoanProductData retrieveLoanProduct(Long productId);
LoanProductData retrieveNewLoanProductDetails();
}
@@ -0,0 +1,200 @@
package org.mifosng.platform.loanproduct.service;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;
import javax.sql.DataSource;
import org.joda.time.DateTime;
import org.mifosng.data.CurrencyData;
import org.mifosng.data.EnumOptionReadModel;
import org.mifosng.data.LoanProductData;
import org.mifosng.data.MoneyData;
import org.mifosng.platform.currency.service.CurrencyReadPlatformService;
import org.mifosng.platform.exceptions.PlatformResourceNotFoundException;
import org.mifosng.platform.security.PlatformSecurityContext;
import org.mifosng.platform.user.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.stereotype.Service;
@Service
public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatformService {
private final PlatformSecurityContext context;
private final CurrencyReadPlatformService currencyReadPlatformService;
private final SimpleJdbcTemplate jdbcTemplate;
private final LoanDropdownReadPlatformService dropdownReadPlatformService;
@Autowired
public LoanProductReadPlatformServiceImpl(final PlatformSecurityContext context, final CurrencyReadPlatformService currencyReadPlatformService,
final LoanDropdownReadPlatformService dropdownReadPlatformService,
final DataSource dataSource) {
this.context = context;
this.currencyReadPlatformService = currencyReadPlatformService;
this.dropdownReadPlatformService = dropdownReadPlatformService;
this.jdbcTemplate = new SimpleJdbcTemplate(dataSource);
}
@Override
public LoanProductData retrieveLoanProduct(final Long loanProductId) {
try {
List<CurrencyData> allowedCurrencies = currencyReadPlatformService.retrieveAllowedCurrencies();
LoanProductMapper rm = new LoanProductMapper(allowedCurrencies);
String sql = "select " + rm.loanProductSchema() + " where lp.id = ?";
LoanProductData productData = this.jdbcTemplate.queryForObject(sql, rm, new Object[] { loanProductId });
populateProductDataWithDropdownOptions(productData);
return productData;
} catch (EmptyResultDataAccessException e) {
throw new PlatformResourceNotFoundException("error.msg.loanproduct.id.invalid", "Loan product with identifier {0} does not exist.", loanProductId);
}
}
@Override
public Collection<LoanProductData> retrieveAllLoanProducts() {
AppUser currentUser = this.context.authenticatedUser();
List<CurrencyData> allowedCurrencies = currencyReadPlatformService.retrieveAllowedCurrencies();
LoanProductMapper rm = new LoanProductMapper(allowedCurrencies);
String sql = "select " + rm.loanProductSchema() + " where lp.org_id = ?";
return this.jdbcTemplate.query(sql, rm, new Object[] { currentUser.getOrganisation().getId() });
}
@Override
public LoanProductData retrieveNewLoanProductDetails() {
LoanProductData productData = new LoanProductData();
populateProductDataWithDropdownOptions(productData);
if (productData.getPossibleCurrencies().size() >= 1) {
CurrencyData currency = productData.getPossibleCurrencies().get(0);
MoneyData zero = MoneyData.zero(currency);
productData.setPrincipalMoney(zero);
productData.setInArrearsTolerance(zero);
}
productData.setAmortizationMethod(Integer.valueOf(1));
productData.setInterestMethod(Integer.valueOf(0));
productData.setRepaymentPeriodFrequency(2);
productData.setInterestRatePeriod(2);
productData.setInterestRateCalculatedInPeriod(1);
productData.setRepaidEvery(1);
productData.setNumberOfRepayments(0);
return productData;
}
private static final class LoanProductMapper implements RowMapper<LoanProductData> {
private final List<CurrencyData> allowedCurrencies;
public LoanProductMapper(List<CurrencyData> allowedCurrencies) {
this.allowedCurrencies = allowedCurrencies;
}
public String loanProductSchema() {
return "lp.id as id, lp.name as name, lp.description as description, lp.flexible_repayment_schedule as isFlexible, lp.interest_rebate as isInterestRebateAllowed, "
+ "lp.principal_amount as principal, lp.currency_code as currencyCode, lp.currency_digits as currencyDigits, "
+ "lp.nominal_interest_rate_per_period as interestRatePerPeriod, lp.interest_period_frequency_enum as interestRatePerPeriodFreq, "
+ "lp.annual_nominal_interest_rate as annualInterestRate, lp.interest_method_enum as interestMethod, lp.interest_calculated_in_period_enum as interestCalculationInPeriodMethod,"
+ "lp.repay_every as repaidEvery, lp.repayment_period_frequency_enum as repaymentPeriodFrequency, lp.number_of_repayments as numberOfRepayments, "
+ "lp.amortization_method_enum as amortizationMethod, lp.arrearstolerance_amount as tolerance, "
+ "lp.created_date as createdon, lp.lastmodified_date as modifiedon "
+ " from portfolio_product_loan lp";
}
@Override
public LoanProductData mapRow(final ResultSet rs, final int rowNum)
throws SQLException {
Long id = rs.getLong("id");
String name = rs.getString("name");
String description = rs.getString("description");
boolean isFlexible = rs.getBoolean("isFlexible");
boolean isInterestRebateAllowed = rs
.getBoolean("isInterestRebateAllowed");
String currencyCode = rs.getString("currencyCode");
int currencyDigits = rs.getInt("currencyDigits");
CurrencyData currencyData = findCurrencyByCode(currencyCode, allowedCurrencies);
currencyData.setDecimalPlaces(currencyDigits);
BigDecimal principal = rs.getBigDecimal("principal");
BigDecimal tolerance = rs.getBigDecimal("tolerance");
MoneyData principalMoney = MoneyData.of(currencyData, principal);
MoneyData toleranceMoney = MoneyData.of(currencyData, tolerance);
BigDecimal interestRatePerPeriod = rs
.getBigDecimal("interestRatePerPeriod");
int interestRatePeriod = rs.getInt("interestRatePerPeriodFreq");
BigDecimal annualInterestRate = rs
.getBigDecimal("annualInterestRate");
int interestMethod = rs.getInt("interestMethod");
int interestCalculationInPeriodMethod = rs.getInt("interestCalculationInPeriodMethod");
int repaidEvery = rs.getInt("repaidEvery");
int repaymentFrequency = rs.getInt("repaymentPeriodFrequency");
int numberOfRepayments = rs.getInt("numberOfRepayments");
int amortizationMethod = rs.getInt("amortizationMethod");
DateTime createdOn = new DateTime(rs.getDate("createdOn"));
DateTime lastModifedOn = new DateTime(rs.getDate("modifiedon"));
return new LoanProductData(id, name, description, isFlexible,
isInterestRebateAllowed, principalMoney,
interestRatePerPeriod, interestRatePeriod,
annualInterestRate, interestMethod, interestCalculationInPeriodMethod,
repaidEvery,
repaymentFrequency, numberOfRepayments, amortizationMethod,
toleranceMoney, createdOn, lastModifedOn);
}
private CurrencyData findCurrencyByCode(String currencyCode, List<CurrencyData> allowedCurrencies) {
CurrencyData match = null;
for (CurrencyData currencyData : allowedCurrencies) {
if (currencyData.getCode().equalsIgnoreCase(currencyCode)) {
match = currencyData;
break;
}
}
return match;
}
}
private void populateProductDataWithDropdownOptions(LoanProductData productData) {
List<CurrencyData> possibleCurrencies = currencyReadPlatformService.retrieveAllowedCurrencies();
List<EnumOptionReadModel> possibleAmortizationOptions = dropdownReadPlatformService.retrieveLoanAmortizationMethodOptions();
List<EnumOptionReadModel> possibleInterestOptions = dropdownReadPlatformService.retrieveLoanInterestMethodOptions();
List<EnumOptionReadModel> possibleInterestRateCalculatedInPeriodOptions = dropdownReadPlatformService.retrieveLoanInterestRateCalculatedInPeriodOptions();
List<EnumOptionReadModel> repaymentFrequencyOptions = dropdownReadPlatformService.retrieveRepaymentFrequencyOptions();
List<EnumOptionReadModel> interestFrequencyOptions = dropdownReadPlatformService.retrieveInterestFrequencyOptions();
productData.setPossibleCurrencies(possibleCurrencies);
productData.setPossibleAmortizationOptions(possibleAmortizationOptions);
productData.setPossibleInterestOptions(possibleInterestOptions);
productData.setPossibleInterestRateCalculatedInPeriodOptions(possibleInterestRateCalculatedInPeriodOptions);
productData.setRepaymentFrequencyOptions(repaymentFrequencyOptions);
productData.setInterestFrequencyOptions(interestFrequencyOptions);
}
}
@@ -0,0 +1,11 @@
package org.mifosng.platform.loanproduct.service;
import org.mifosng.data.EntityIdentifier;
import org.mifosng.data.command.LoanProductCommand;
public interface LoanProductWritePlatformService {
EntityIdentifier createLoanProduct(LoanProductCommand command);
EntityIdentifier updateLoanProduct(LoanProductCommand command);
}
@@ -0,0 +1,107 @@
package org.mifosng.platform.loanproduct.service;
import static org.mifosng.platform.Specifications.productThatMatches;
import java.math.BigDecimal;
import org.mifosng.data.EntityIdentifier;
import org.mifosng.data.command.LoanProductCommand;
import org.mifosng.platform.currency.domain.MonetaryCurrency;
import org.mifosng.platform.exceptions.PlatformResourceNotFoundException;
import org.mifosng.platform.loan.domain.AmortizationMethod;
import org.mifosng.platform.loan.domain.InterestCalculationPeriodMethod;
import org.mifosng.platform.loan.domain.InterestMethod;
import org.mifosng.platform.loan.domain.LoanProduct;
import org.mifosng.platform.loan.domain.LoanProductRepository;
import org.mifosng.platform.loan.domain.PeriodFrequencyType;
import org.mifosng.platform.security.PlatformSecurityContext;
import org.mifosng.platform.user.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanProductWritePlatformService {
private final PlatformSecurityContext context;
private final LoanProductRepository loanProductRepository;
@Autowired
public LoanProductWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final LoanProductRepository loanProductRepository) {
this.context = context;
this.loanProductRepository = loanProductRepository;
}
@Transactional
@Override
public EntityIdentifier createLoanProduct(final LoanProductCommand command) {
AppUser currentUser = this.context.authenticatedUser();
LoanProductCommandValidator validator = new LoanProductCommandValidator();
validator.validateForCreate(command);
// assemble LoanProduct from data
InterestMethod interestMethod = InterestMethod.fromInt(command.getInterestMethod());
InterestCalculationPeriodMethod interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(command.getInterestCalculationPeriodMethod());
AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.getAmortizationMethod());
PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType
.fromInt(command.getRepaymentFrequency());
PeriodFrequencyType interestFrequencyType = PeriodFrequencyType
.fromInt(command.getInterestRateFrequencyMethod());
MonetaryCurrency currency = new MonetaryCurrency(command.getCurrencyCode(), command.getDigitsAfterDecimal());
// apr calculator
BigDecimal annualInterestRate = BigDecimal.ZERO;
switch (interestFrequencyType) {
case DAYS:
break;
case WEEKS:
annualInterestRate = command.getInterestRatePerPeriod().multiply(BigDecimal.valueOf(52));
break;
case MONTHS:
annualInterestRate = command.getInterestRatePerPeriod().multiply(BigDecimal.valueOf(12));
break;
case YEARS:
annualInterestRate = command.getInterestRatePerPeriod().multiply(BigDecimal.valueOf(1));
break;
case INVALID:
break;
}
LoanProduct loanproduct = new LoanProduct(currentUser.getOrganisation(), command.getName(), command.getDescription(),
currency, command.getPrincipal(),
command.getInterestRatePerPeriod(), interestFrequencyType, annualInterestRate, interestMethod, interestCalculationPeriodMethod,
command.getRepaymentEvery(), repaymentFrequencyType, command.getNumberOfRepayments(), amortizationMethod, command.getInArrearsToleranceAmount(),
command.isFlexibleRepaymentSchedule(), command.isInterestRebateAllowed());
this.loanProductRepository.save(loanproduct);
return new EntityIdentifier(loanproduct.getId());
}
@Transactional
@Override
public EntityIdentifier updateLoanProduct(LoanProductCommand command) {
AppUser currentUser = this.context.authenticatedUser();
LoanProductCommandValidator validator = new LoanProductCommandValidator();
validator.validateForUpdate(command);
LoanProduct product = this.loanProductRepository.findOne(productThatMatches(currentUser.getOrganisation(), command.getId()));
if (product == null) {
throw new PlatformResourceNotFoundException("error.msg.loanproduct.id.invalid", "Loan product with identifier {0} does not exist.", command.getId());
}
product.update(command);
this.loanProductRepository.save(product);
return new EntityIdentifier(Long.valueOf(product.getId()));
}
}
@@ -7,6 +7,7 @@ import org.mifosng.platform.exceptions.NoAuthorizationException;
import org.mifosng.platform.exceptions.PlatformDataIntegrityException;
import org.mifosng.platform.organisation.domain.Office;
import org.mifosng.platform.organisation.domain.OfficeRepository;
import org.mifosng.platform.security.PlatformSecurityContext;
import org.mifosng.platform.user.domain.AppUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -12,6 +12,7 @@ import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
import org.mifosng.data.OfficeData;
import org.mifosng.platform.exceptions.PlatformResourceNotFoundException;
import org.mifosng.platform.security.PlatformSecurityContext;
import org.mifosng.platform.user.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
@@ -99,7 +100,7 @@ public class OfficeReadPlatformServiceImpl implements OfficeReadPlatformService
return selectedOffice;
} catch (EmptyResultDataAccessException e) {
throw new PlatformResourceNotFoundException("error.msg.office.id.invalid", "Office with identifier {0} does not exist", officeId);
throw new PlatformResourceNotFoundException("error.msg.office.id.invalid", "Office with identifier {0} does not exist.", officeId);
}
}
}
@@ -19,13 +19,12 @@ import org.mifosng.data.ErrorResponse;
import org.mifosng.data.ErrorResponseList;
import org.mifosng.data.LoanProductData;
import org.mifosng.data.LoanProductList;
import org.mifosng.data.command.CreateLoanProductCommand;
import org.mifosng.data.command.UpdateLoanProductCommand;
import org.mifosng.data.command.LoanProductCommand;
import org.mifosng.platform.ReadPlatformService;
import org.mifosng.platform.WritePlatformService;
import org.mifosng.platform.exceptions.ApplicationDomainRuleException;
import org.mifosng.platform.exceptions.UnAuthenticatedUserException;
import org.mifosng.platform.exceptions.NewDataValidationException;
import org.mifosng.platform.exceptions.UnAuthenticatedUserException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.security.access.AccessDeniedException;
@@ -58,7 +57,7 @@ public class LoanProductResource {
@Path("new")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Response createLoanProduct(final CreateLoanProductCommand command) {
public Response createLoanProduct(final LoanProductCommand command) {
try {
EntityIdentifier entityIdentifier = this.writePlatformService.createLoanProduct(command);
@@ -81,7 +80,7 @@ public class LoanProductResource {
@Path("update")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Response updateLoanProduct(final UpdateLoanProductCommand command) {
public Response updateLoanProduct(final LoanProductCommand command) {
try {
EntityIdentifier entityIdentifier = this.writePlatformService.updateLoanProduct(command);
@@ -1,4 +1,4 @@
package org.mifosng.platform.organisation.service;
package org.mifosng.platform.security;
import org.mifosng.platform.user.domain.AppUser;
@@ -1,4 +1,4 @@
package org.mifosng.platform.organisation.service;
package org.mifosng.platform.security;
import org.mifosng.platform.exceptions.UnAuthenticatedUserException;
import org.mifosng.platform.user.domain.AppUser;