tidy up state transitions and transactions support through api.

This commit is contained in:
Keith Woodlock
2012-06-06 17:09:08 +01:00
parent 22d20a2273
commit 28b26d2463
19 changed files with 169 additions and 81 deletions
@@ -26,7 +26,7 @@ import org.mifosng.platform.api.commands.SubmitLoanApplicationCommand;
import org.mifosng.platform.api.commands.UndoStateTransitionCommand;
import org.mifosng.platform.api.data.EntityIdentifier;
import org.mifosng.platform.api.data.LoanAccountData;
import org.mifosng.platform.api.data.LoanRepaymentData;
import org.mifosng.platform.api.data.LoanTransactionData;
import org.mifosng.platform.api.data.LoanSchedule;
import org.mifosng.platform.api.data.NewLoanData;
import org.mifosng.platform.api.infrastructure.ApiDataConversionService;
@@ -49,7 +49,7 @@ public class LoansApiResource {
private String loanFilterName = "loanFilter";
private String loanAllowedFieldList = "";
private String loanRepaymentFilterName = "loanRepaymentFilter";
private String loanRepaymentDefaultFieldList = "date,total";
private String loanRepaymentDefaultFieldList = "transactionType,date,total";
private String loanRepaymentAllowedFieldList = "";
@Autowired
@@ -280,13 +280,13 @@ public class LoansApiResource {
String json = "";
String selectedFields = loanRepaymentDefaultFieldList;
if (is(commandParam, "repayment")) {
LoanRepaymentData loanRepaymentData = this.loanReadPlatformService
LoanTransactionData loanRepaymentData = this.loanReadPlatformService
.retrieveNewLoanRepaymentDetails(loanId);
json = this.jsonFormattingService.convertRequest(loanRepaymentData,
loanRepaymentFilterName, loanRepaymentAllowedFieldList, selectedFields,
uriInfo.getQueryParameters());
} else if (is(commandParam, "waiver")) {
LoanRepaymentData loanWaiverData = this.loanReadPlatformService
LoanTransactionData loanWaiverData = this.loanReadPlatformService
.retrieveNewLoanWaiverDetails(loanId);
json = this.jsonFormattingService.convertRequest(loanWaiverData,
loanRepaymentFilterName, loanRepaymentAllowedFieldList, selectedFields,
@@ -304,15 +304,15 @@ public class LoansApiResource {
@Path("{loanId}/transactions/{transactionId}")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Produces({ MediaType.APPLICATION_JSON})
public String retrieveRepaymentDetails(
public String retrieveTransaction(
@PathParam("loanId") final Long loanId,
@PathParam("transactionId") final Long transactionId,
@Context UriInfo uriInfo) {
LoanRepaymentData loanRepaymentData = this.loanReadPlatformService
.retrieveLoanRepaymentDetails(loanId, transactionId);
LoanTransactionData loanRepaymentData = this.loanReadPlatformService
.retrieveLoanTransactionDetails(loanId, transactionId);
String selectedFields = "";
String selectedFields = loanRepaymentDefaultFieldList;
return this.jsonFormattingService.convertRequest(loanRepaymentData,
loanRepaymentFilterName, loanRepaymentAllowedFieldList, selectedFields,
uriInfo.getQueryParameters());
@@ -99,7 +99,7 @@ public class ApiGlobalErrorResponse {
public static ApiGlobalErrorResponse dataIntegrityError(final String globalisationMessageCode, final String defaultUserMessage, final String parameterName, final Object... defaultUserMessageArgs) {
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
globalErrorResponse.setHttpStatusCode("400");
globalErrorResponse.setHttpStatusCode("403");
globalErrorResponse.setDeveloperMessage("The request caused a data integrity issue to be fired by the database.");
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
globalErrorResponse.setUserMessageGlobalisationCode(globalisationMessageCode);
@@ -6,13 +6,13 @@ public class DerivedLoanData {
private LoanRepaymentScheduleData repaymentSchedule;
private LoanAccountSummaryData summary;
private List<LoanRepaymentData> loanRepayments;
private List<LoanTransactionData> loanRepayments;
public DerivedLoanData() {
//
}
public DerivedLoanData(LoanRepaymentScheduleData repaymentScheduleData, LoanAccountSummaryData summaryData, List<LoanRepaymentData> loanRepayments) {
public DerivedLoanData(LoanRepaymentScheduleData repaymentScheduleData, LoanAccountSummaryData summaryData, List<LoanTransactionData> loanRepayments) {
this.repaymentSchedule = repaymentScheduleData;
this.summary = summaryData;
this.loanRepayments = loanRepayments;
@@ -34,11 +34,11 @@ public class DerivedLoanData {
this.summary = summary;
}
public List<LoanRepaymentData> getLoanRepayments() {
public List<LoanTransactionData> getLoanRepayments() {
return loanRepayments;
}
public void setLoanRepayments(List<LoanRepaymentData> loanRepayments) {
public void setLoanRepayments(List<LoanTransactionData> loanRepayments) {
this.loanRepayments = loanRepayments;
}
}
@@ -41,7 +41,7 @@ public class LoanAccountData {
private LoanAccountSummaryData summary;
private LoanRepaymentScheduleData repaymentSchedule;
private List<LoanRepaymentData> loanRepayments;
private List<LoanTransactionData> loanRepayments;
private LoanPermissionData permissions;
@@ -55,7 +55,7 @@ public class LoanAccountData {
public LoanAccountData(LoanBasicDetailsData basicDetails,
LoanAccountSummaryData summary,
LoanRepaymentScheduleData repaymentSchedule,
List<LoanRepaymentData> loanRepayments, LoanPermissionData permissions) {
List<LoanTransactionData> loanRepayments, LoanPermissionData permissions) {
this.summary = summary;
this.repaymentSchedule = repaymentSchedule;
this.loanRepayments = loanRepayments;
@@ -130,11 +130,11 @@ public class LoanAccountData {
this.repaymentSchedule = repaymentSchedule;
}
public List<LoanRepaymentData> getLoanRepayments() {
public List<LoanTransactionData> getLoanRepayments() {
return loanRepayments;
}
public void setLoanRepayments(List<LoanRepaymentData> loanRepayments) {
public void setLoanRepayments(List<LoanTransactionData> loanRepayments) {
this.loanRepayments = loanRepayments;
}
@@ -4,9 +4,10 @@ import org.codehaus.jackson.map.annotate.JsonFilter;
import org.joda.time.LocalDate;
@JsonFilter("loanRepaymentFilter")
public class LoanRepaymentData {
public class LoanTransactionData {
private Long id;
private EnumOptionData transactionType;
private LocalDate date;
private MoneyData principal;
private MoneyData interest;
@@ -14,16 +15,17 @@ public class LoanRepaymentData {
private MoneyData totalWaived;
private MoneyData overpaid;
public LoanRepaymentData() {
public LoanTransactionData() {
//
}
public LoanRepaymentData(
Long id, final LocalDate date,
public LoanTransactionData(
Long id, EnumOptionData transactionType, final LocalDate date,
final MoneyData principal,
final MoneyData interest,
final MoneyData total, final MoneyData overpaid) {
this.id = id;
this.transactionType = transactionType;
this.date = date;
this.principal = principal;
this.interest = interest;
@@ -38,15 +40,19 @@ public class LoanRepaymentData {
public void setId(Long id) {
this.id = id;
}
public EnumOptionData getTransactionType() {
return transactionType;
}
public void setTransactionType(EnumOptionData transactionType) {
this.transactionType = transactionType;
}
public LocalDate getDate() {
return date;
}
// public int getTransactionOffsetFromToday() {
// return Days.daysBetween(new DateMidnight().toDateTime(), this.date.toDateMidnight().toDateTime()).getDays();
// }
public void setDate(LocalDate date) {
this.date = date;
}
@@ -26,6 +26,6 @@ public class PlatformDataIntegrityExceptionMapper implements ExceptionMapper<Pla
ApiGlobalErrorResponse dataIntegrityError = ApiGlobalErrorResponse.dataIntegrityError(exception.getGlobalisationMessageCode(), exception.getDefaultUserMessage(),
exception.getParameterName(), exception.getDefaultUserMessageArgs());
return Response.status(Status.BAD_REQUEST).entity(dataIntegrityError).build();
return Response.status(Status.FORBIDDEN).entity(dataIntegrityError).build();
}
}
@@ -6,6 +6,6 @@ package org.mifosng.platform.exceptions;
public class InvalidLoanStateTransitionException extends AbstractPlatformDomainRuleException {
public InvalidLoanStateTransitionException(final String action, String postFix, String defaultUserMessage, Object... defaultUserMessageArgs) {
super("error.msg.loan." + action + postFix, defaultUserMessage, defaultUserMessageArgs);
super("error.msg.loan." + action + "." + postFix, defaultUserMessage, defaultUserMessageArgs);
}
}
@@ -0,0 +1,11 @@
package org.mifosng.platform.exceptions;
/**
* {@link AbstractPlatformDomainRuleException} thrown an action to transition a loan from one state to another violates a domain rule.
*/
public class InvalidLoanTransactionTypeException extends AbstractPlatformDomainRuleException {
public InvalidLoanTransactionTypeException(final String action, String postFix, String defaultUserMessage, Object... defaultUserMessageArgs) {
super("error.msg.loan." + action + "." + postFix, defaultUserMessage, defaultUserMessageArgs);
}
}
@@ -6,6 +6,10 @@ package org.mifosng.platform.exceptions;
public class LoanTransactionNotFoundException extends AbstractPlatformResourceNotFoundException {
public LoanTransactionNotFoundException(Long id) {
super("error.msg.loan.id.invalid", "Loan with identifier " + id + " does not exist", id);
super("error.msg.loan.id.invalid", "Transaction with identifier " + id + " does not exist", id);
}
public LoanTransactionNotFoundException(Long id, Long loanId) {
super("error.msg.loan.id.invalid", "Transaction with identifier " + id + " does not exist for loan with identifier " + loanId + "." , id, loanId);
}
}
@@ -7,13 +7,15 @@ import java.util.List;
import org.joda.time.LocalDate;
import org.mifosng.platform.api.data.CurrencyData;
import org.mifosng.platform.api.data.DerivedLoanData;
import org.mifosng.platform.api.data.EnumOptionData;
import org.mifosng.platform.api.data.LoanAccountSummaryData;
import org.mifosng.platform.api.data.LoanRepaymentData;
import org.mifosng.platform.api.data.LoanTransactionData;
import org.mifosng.platform.api.data.LoanRepaymentPeriodData;
import org.mifosng.platform.api.data.LoanRepaymentScheduleData;
import org.mifosng.platform.api.data.MoneyData;
import org.mifosng.platform.currency.domain.MonetaryCurrency;
import org.mifosng.platform.currency.domain.Money;
import org.mifosng.platform.loanproduct.service.LoanEnumerations;
// FIXME - The derived details of the loan schedule are now updated on the fly when someone does a transaction against a loan. So this is not fully needed.
// - we still use this to figure out how much of a given transactions amount was principal versus interest but might not need this and we should probably
@@ -28,7 +30,7 @@ public class DerivedLoanDataProcessor {
List<LoanRepaymentPeriodData> loanRepaymentPeriods = repaymentScheduleDetails.getPeriods();
// break up payments based on principal and interest
List<LoanRepaymentData> loanRepayments = new ArrayList<LoanRepaymentData>();
List<LoanTransactionData> loanRepayments = new ArrayList<LoanTransactionData>();
int repaymentScheduleIndex = 0;
for (LoanTransaction transaction : loanTransactions) {
if (transaction.isRepayment() || transaction.isWaiver()) {
@@ -40,7 +42,7 @@ public class DerivedLoanDataProcessor {
.get(repaymentScheduleIndex);
if (transaction.isRepayment()) {
LoanRepaymentData repaymentData = processLoanRepayment(
LoanTransactionData repaymentData = processLoanRepayment(
transaction, scheduledRepaymentPeriod,
repaymentScheduleIndex, loanRepaymentPeriods,
arrearsTolerance, currencyDetail);
@@ -48,7 +50,7 @@ public class DerivedLoanDataProcessor {
}
if (transaction.isWaiver()) {
LoanRepaymentData repaymentData = processWaiver(transaction, scheduledRepaymentPeriod, currencyDetail);
LoanTransactionData repaymentData = processWaiver(transaction, scheduledRepaymentPeriod, currencyDetail);
loanRepayments.add(repaymentData);
}
@@ -73,7 +75,7 @@ public class DerivedLoanDataProcessor {
return new DerivedLoanData(processRepaymentScheduleData, summaryData, loanRepayments);
}
private LoanRepaymentData processWaiver(LoanTransaction transaction,
private LoanTransactionData processWaiver(LoanTransaction transaction,
LoanRepaymentPeriodData scheduledRepaymentPeriod, CurrencyData currencyData) {
MonetaryCurrency currency = new MonetaryCurrency(currencyData.getCode(), currencyData.getDecimalPlaces());
@@ -125,7 +127,8 @@ public class DerivedLoanDataProcessor {
Money remainingOutstanding = totalOutstanding.minus(moneyFrom(totalWaived));
scheduledRepaymentPeriod.setTotalOutstanding(moneyDataFrom(currencyData, remainingOutstanding));
LoanRepaymentData loanRepaymentData = new LoanRepaymentData(transaction.getId(), transaction.getTransactionDate(), moneyDataFrom(currencyData, principalWaived),
EnumOptionData transactionType = LoanEnumerations.transactionType(LoanTransactionType.WAIVED);
LoanTransactionData loanRepaymentData = new LoanTransactionData(transaction.getId(), transactionType, transaction.getTransactionDate(), moneyDataFrom(currencyData, principalWaived),
moneyDataFrom(currencyData, interestWaived), totalWaived, zero);
loanRepaymentData.setTotalWaived(totalWaived);
return loanRepaymentData;
@@ -270,7 +273,7 @@ public class DerivedLoanDataProcessor {
/**
* TODO - pays off interest first then principal so should make this configurable when generating 'derived view of loan account'
*/
private LoanRepaymentData processLoanRepayment(LoanTransaction repayment,
private LoanTransactionData processLoanRepayment(LoanTransaction repayment,
LoanRepaymentPeriodData scheduledRepayment,
int repaymentScheduleIndex,
List<LoanRepaymentPeriodData> repaymentSchedulePeriods,
@@ -443,7 +446,8 @@ public class DerivedLoanDataProcessor {
MoneyData totalPaid = moneyDataFrom(currencyDetail, totalPrincipalComponent.plus(totalInterestComponent));
LoanRepaymentData loanRepaymentData = new LoanRepaymentData(repayment.getId(), repayment.getTransactionDate(), cumulativePrincipalPaid, cumulativeInterestPaid, totalPaid, overpaid);
EnumOptionData transactionType = LoanEnumerations.transactionType(LoanTransactionType.REPAYMENT);
LoanTransactionData loanRepaymentData = new LoanTransactionData(repayment.getId(), transactionType, repayment.getTransactionDate(), cumulativePrincipalPaid, cumulativeInterestPaid, totalPaid, overpaid);
return loanRepaymentData;
}
@@ -32,13 +32,14 @@ import org.mifosng.platform.api.data.LoanAccountData;
import org.mifosng.platform.api.data.LoanAccountSummaryData;
import org.mifosng.platform.api.data.LoanBasicDetailsData;
import org.mifosng.platform.api.data.LoanPermissionData;
import org.mifosng.platform.api.data.LoanRepaymentData;
import org.mifosng.platform.api.data.LoanRepaymentScheduleData;
import org.mifosng.platform.api.data.LoanTransactionData;
import org.mifosng.platform.api.data.MoneyData;
import org.mifosng.platform.client.domain.Client;
import org.mifosng.platform.currency.domain.MonetaryCurrency;
import org.mifosng.platform.currency.domain.Money;
import org.mifosng.platform.exceptions.InvalidLoanStateTransitionException;
import org.mifosng.platform.exceptions.InvalidLoanTransactionTypeException;
import org.mifosng.platform.infrastructure.AbstractAuditableCustom;
import org.mifosng.platform.loanproduct.service.LoanEnumerations;
import org.mifosng.platform.organisation.domain.Organisation;
@@ -336,6 +337,17 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
throw new InvalidLoanStateTransitionException("waive", "cannot.be.a.futre.date", errorMessage, loanTransactionDate);
}
if (getTotalOutstanding().isGreaterThan(this.getInArrearsTolerance())) {
final String errorMessage = "Waiver is only allowed when the total outstanding amount left on loan (" + getTotalOutstanding() +") is less than thethe in arrears tolerance setting of " + getInArrearsTolerance().getAmount();
throw new InvalidLoanStateTransitionException("waive", "cannot.exceed.in.arrears.tolerance.setting", errorMessage, getTotalOutstanding(), getInArrearsTolerance());
}
Money waived = Money.of(getCurrency(), loanTransaction.getAmount());
if (waived.isGreaterThan(this.getInArrearsTolerance())) {
final String errorMessage = "The amount being waived cannot exceed the in arrears tolerance setting of " + getInArrearsTolerance().getAmount();
throw new InvalidLoanStateTransitionException("waive", "cannot.exceed.in.arrears.tolerance.setting", errorMessage, waived, getInArrearsTolerance());
}
if (this.isRepaidInFull()) {
this.loanStatus = loanLifecycleStateMachine.transition(LoanEvent.REPAID_IN_FULL, this.loanStatus);
this.closedOnDate = loanTransaction.getTransactionDate().toDate();
@@ -361,8 +373,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
deriveLoanRepaymentScheduleCompletedData();
if (loanTransaction.isNotRepayment()) {
throw new IllegalArgumentException(
"Only repayment transactions can be passed to makeRepayment.");
final String errorMessage = "A transaction of type repayment was expected but not received.";
throw new InvalidLoanTransactionTypeException("transaction", "is.not.a.repayment.transaction", errorMessage);
}
LocalDate loanTransactionDate = loanTransaction.getTransactionDate();
@@ -469,7 +481,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
LoanTransaction newTransactionDetail, LoanLifecycleStateMachine loanLifecycleStateMachine) {
if (transactionForAdjustment.isNotRepayment() && transactionForAdjustment.isNotWaiver()) {
throw new IllegalArgumentException("Only repayment and waiver transactions can be adjusted.");
final String errorMessage = "A transaction of type repayment or waiver was expected but not received.";
throw new InvalidLoanTransactionTypeException("transaction", "is.not.a.repayment.or.waiver.transaction", errorMessage);
}
transactionForAdjustment.contra();
@@ -982,7 +995,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
}
public LoanAccountData toLoanAccountData(LoanAccountSummaryData summary, LoanRepaymentScheduleData repaymentSchedule,
List<LoanRepaymentData> loanRepayments,
List<LoanTransactionData> loanRepayments,
CurrencyData currencyData) {
LoanBasicDetailsData basicDetails = toBasicDetailsData(currencyData);
@@ -2,13 +2,13 @@ package org.mifosng.platform.loan.domain;
import java.util.Comparator;
import org.mifosng.platform.api.data.LoanRepaymentData;
import org.mifosng.platform.api.data.LoanTransactionData;
public class LoanRepaymentDataComparator implements Comparator<LoanRepaymentData> {
public class LoanRepaymentDataComparator implements Comparator<LoanTransactionData> {
@Override
public int compare(final LoanRepaymentData o1, final LoanRepaymentData o2) {
public int compare(final LoanTransactionData o1, final LoanTransactionData o2) {
return o2.getDate().compareTo(o1.getDate());
}
@@ -140,6 +140,14 @@ public class LoanTransaction extends AbstractAuditableCustom<AppUser, Long> {
public boolean isIdentifiedBy(Long identifier) {
return this.getId().equals(identifier);
}
public boolean isBelongingToLoanOf(Loan check) {
return this.loan.getId().equals(check.getId());
}
public boolean isNotBelongingToLoanOf(Loan check) {
return !isBelongingToLoanOf(check);
}
public void contra() {
this.contra = LoanTransaction.contra(this);
@@ -1,22 +1,28 @@
package org.mifosng.platform.loan.domain;
public enum LoanTransactionType {
UNKNOWN(0), DISBURSEMENT(1), REPAYMENT(2), REVERSAL(3), WAIVED(4);
INVALID(0, "loanTransactionType.invalid"), DISBURSEMENT(1, "loanTransactionType.disbursement"), REPAYMENT(2, "loanTransactionType.repayment"), REVERSAL(3, "loanTransactionType.reversal"), WAIVED(4, "loanTransactionType.waiver");
private final Integer value;
private final String code;
private LoanTransactionType(final Integer value) {
private LoanTransactionType(final Integer value, final String code) {
this.value = value;
this.code = code;
}
public Integer getValue() {
return this.value;
}
public String getCode() {
return code;
}
public static LoanTransactionType fromInt(final Integer transactionType) {
if (transactionType == null) {
return LoanTransactionType.UNKNOWN;
return LoanTransactionType.INVALID;
}
LoanTransactionType loanTransactionType = null;
@@ -34,7 +40,7 @@ public enum LoanTransactionType {
loanTransactionType = LoanTransactionType.WAIVED;
break;
default:
loanTransactionType = LoanTransactionType.UNKNOWN;
loanTransactionType = LoanTransactionType.INVALID;
break;
}
return loanTransactionType;
@@ -1,7 +1,7 @@
package org.mifosng.platform.loan.service;
import org.mifosng.platform.api.data.LoanAccountData;
import org.mifosng.platform.api.data.LoanRepaymentData;
import org.mifosng.platform.api.data.LoanTransactionData;
import org.mifosng.platform.api.data.NewLoanData;
public interface LoanReadPlatformService {
@@ -10,9 +10,9 @@ public interface LoanReadPlatformService {
NewLoanData retrieveClientAndProductDetails(Long clientId, Long productId);
LoanRepaymentData retrieveNewLoanRepaymentDetails(Long loanId);
LoanTransactionData retrieveNewLoanRepaymentDetails(Long loanId);
LoanRepaymentData retrieveNewLoanWaiverDetails(Long loanId);
LoanTransactionData retrieveNewLoanWaiverDetails(Long loanId);
LoanRepaymentData retrieveLoanRepaymentDetails(Long loanId, Long transactionId);
LoanTransactionData retrieveLoanTransactionDetails(Long loanId, Long transactionId);
}
@@ -13,7 +13,7 @@ import org.mifosng.platform.api.data.DerivedLoanData;
import org.mifosng.platform.api.data.LoanAccountData;
import org.mifosng.platform.api.data.LoanProductData;
import org.mifosng.platform.api.data.LoanProductLookup;
import org.mifosng.platform.api.data.LoanRepaymentData;
import org.mifosng.platform.api.data.LoanTransactionData;
import org.mifosng.platform.api.data.MoneyData;
import org.mifosng.platform.api.data.NewLoanData;
import org.mifosng.platform.client.service.ClientReadPlatformService;
@@ -27,6 +27,8 @@ import org.mifosng.platform.loan.domain.Loan;
import org.mifosng.platform.loan.domain.LoanRepository;
import org.mifosng.platform.loan.domain.LoanTransaction;
import org.mifosng.platform.loan.domain.LoanTransactionRepository;
import org.mifosng.platform.loan.domain.LoanTransactionType;
import org.mifosng.platform.loanproduct.service.LoanEnumerations;
import org.mifosng.platform.loanproduct.service.LoanProductReadPlatformService;
import org.mifosng.platform.security.PlatformSecurityContext;
import org.mifosng.platform.user.domain.AppUser;
@@ -137,7 +139,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
}
@Override
public LoanRepaymentData retrieveNewLoanRepaymentDetails(Long loanId) {
public LoanTransactionData retrieveNewLoanRepaymentDetails(Long loanId) {
AppUser currentUser = context.authenticatedUser();
@@ -167,7 +169,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
MoneyData possibleNextRepayment = MoneyData.of(currencyData,
possibleNextRepaymentAmount.getAmount());
LoanRepaymentData newRepaymentDetails = new LoanRepaymentData();
LoanTransactionData newRepaymentDetails = new LoanTransactionData();
newRepaymentDetails.setTransactionType(LoanEnumerations.transactionType(LoanTransactionType.REPAYMENT));
newRepaymentDetails.setDate(earliestUnpaidInstallmentDate);
newRepaymentDetails.setTotal(possibleNextRepayment);
@@ -175,7 +178,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
}
@Override
public LoanRepaymentData retrieveNewLoanWaiverDetails(Long loanId) {
public LoanTransactionData retrieveNewLoanWaiverDetails(Long loanId) {
AppUser currentUser = context.authenticatedUser();
@@ -203,7 +206,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
MoneyData totalOutstandingData = MoneyData.of(currencyData,
totalOutstanding.getAmount());
LoanRepaymentData newWaiverDetails = new LoanRepaymentData();
LoanTransactionData newWaiverDetails = new LoanTransactionData();
newWaiverDetails.setTransactionType(LoanEnumerations.transactionType(LoanTransactionType.WAIVED));
newWaiverDetails.setDate(new LocalDate());
newWaiverDetails.setTotal(totalOutstandingData);
@@ -211,7 +215,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
}
@Override
public LoanRepaymentData retrieveLoanRepaymentDetails(Long loanId,
public LoanTransactionData retrieveLoanTransactionDetails(Long loanId,
Long transactionId) {
AppUser currentUser = context.authenticatedUser();
@@ -236,6 +240,10 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
if (transaction == null) {
throw new LoanTransactionNotFoundException(transactionId);
}
if (transaction.isNotBelongingToLoanOf(loan)) {
throw new LoanTransactionNotFoundException(transactionId, loanId);
}
CurrencyData currencyData = new CurrencyData(currency.getCode(),
currency.getName(), currency.getDecimalPlaces(),
@@ -243,7 +251,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
MoneyData total = MoneyData.of(currencyData, transaction.getAmount());
LocalDate date = transaction.getTransactionDate();
LoanRepaymentData loanRepaymentData = new LoanRepaymentData();
LoanTransactionData loanRepaymentData = new LoanTransactionData();
loanRepaymentData.setTransactionType(LoanEnumerations.transactionType(transaction.getTypeOf()));
loanRepaymentData.setId(transactionId);
loanRepaymentData.setTotal(total);
loanRepaymentData.setDate(date);
@@ -152,7 +152,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.noteRepository.save(note);
}
return new EntityIdentifier(loan.getClient().getId());
return new EntityIdentifier(loan.getId());
}
@Transactional
@@ -175,7 +175,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.noteRepository.save(note);
}
return new EntityIdentifier(loan.getClient().getId());
return new EntityIdentifier(loan.getId());
}
@Transactional
@@ -206,7 +206,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.noteRepository.save(note);
}
return new EntityIdentifier(loan.getClient().getId());
return new EntityIdentifier(loan.getId());
}
@Transactional
@@ -237,7 +237,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.noteRepository.save(note);
}
return new EntityIdentifier(loan.getClient().getId());
return new EntityIdentifier(loan.getId());
}
@Transactional
@@ -324,7 +324,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.noteRepository.save(note);
}
return new EntityIdentifier(loan.getClient().getId());
return new EntityIdentifier(loan.getId());
}
@Transactional
@@ -352,7 +352,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.noteRepository.save(note);
}
return new EntityIdentifier(loan.getClient().getId());
return new EntityIdentifier(loan.getId());
}
@Transactional
@@ -389,7 +389,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.noteRepository.save(note);
}
return new EntityIdentifier(loan.getClient().getId());
return new EntityIdentifier(loan.getId());
}
@Transactional
@@ -435,7 +435,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.noteRepository.save(note);
}
return new EntityIdentifier(loan.getClient().getId());
return new EntityIdentifier(loan.getId());
}
@Transactional
@@ -470,6 +470,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.noteRepository.save(note);
}
return new EntityIdentifier(loan.getClient().getId());
return new EntityIdentifier(loan.getId());
}
}
@@ -4,6 +4,7 @@ import org.mifosng.platform.api.data.EnumOptionData;
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.LoanTransactionType;
import org.mifosng.platform.loan.domain.PeriodFrequencyType;
public class LoanEnumerations {
@@ -87,7 +88,7 @@ public class LoanEnumerations {
optionData = new EnumOptionData(InterestMethod.DECLINING_BALANCE.getValue().longValue(), InterestMethod.DECLINING_BALANCE.getCode(), "Declining Balance");
break;
default:
optionData = new EnumOptionData(AmortizationMethod.INVALID.getValue().longValue(), AmortizationMethod.INVALID.getCode(), "Invalid");
optionData = new EnumOptionData(InterestMethod.INVALID.getValue().longValue(), InterestMethod.INVALID.getCode(), "Invalid");
break;
}
return optionData;
@@ -107,7 +108,33 @@ public class LoanEnumerations {
optionData = new EnumOptionData(InterestCalculationPeriodMethod.SAME_AS_REPAYMENT_PERIOD.getValue().longValue(), InterestCalculationPeriodMethod.SAME_AS_REPAYMENT_PERIOD.getCode(), "Same as repayment period");
break;
default:
optionData = new EnumOptionData(AmortizationMethod.INVALID.getValue().longValue(), AmortizationMethod.INVALID.getCode(), "Invalid");
optionData = new EnumOptionData(InterestCalculationPeriodMethod.INVALID.getValue().longValue(), InterestCalculationPeriodMethod.INVALID.getCode(), "Invalid");
break;
}
return optionData;
}
public static EnumOptionData transactionType(Integer id) {
return transactionType(LoanTransactionType.fromInt(id));
}
public static EnumOptionData transactionType(LoanTransactionType type) {
EnumOptionData optionData = null;
switch (type) {
case DISBURSEMENT:
optionData= new EnumOptionData(LoanTransactionType.DISBURSEMENT.getValue().longValue(), LoanTransactionType.DISBURSEMENT.getCode(), "Dibursement");
break;
case REPAYMENT:
optionData = new EnumOptionData(LoanTransactionType.REPAYMENT.getValue().longValue(), LoanTransactionType.REPAYMENT.getCode(), "Repayment");
break;
case REVERSAL:
optionData = new EnumOptionData(LoanTransactionType.REVERSAL.getValue().longValue(), LoanTransactionType.REVERSAL.getCode(), "Reversal");
break;
case WAIVED:
optionData = new EnumOptionData(LoanTransactionType.WAIVED.getValue().longValue(), LoanTransactionType.WAIVED.getCode(), "Waiver");
break;
default:
optionData = new EnumOptionData(LoanTransactionType.INVALID.getValue().longValue(), LoanTransactionType.INVALID.getCode(), "Invalid");
break;
}
return optionData;
@@ -12,7 +12,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mifosng.platform.api.data.CurrencyData;
import org.mifosng.platform.api.data.DerivedLoanData;
import org.mifosng.platform.api.data.LoanRepaymentData;
import org.mifosng.platform.api.data.LoanTransactionData;
import org.mifosng.platform.api.data.LoanRepaymentPeriodData;
import org.mifosng.platform.api.data.LoanRepaymentScheduleData;
import org.mifosng.platform.api.data.MoneyData;
@@ -81,11 +81,11 @@ public class DerivedLoanDataProcessorTest {
assertThat(periodData.getInterestOutstanding(), is(expectedInterestOutstanding));
// assert repayments are ok
List<LoanRepaymentData> loanRepayments = derivedData.getLoanRepayments();
List<LoanTransactionData> loanRepayments = derivedData.getLoanRepayments();
assertThat(loanRepayments, is(notNullValue()));
assertThat(loanRepayments.size(), is(1));
LoanRepaymentData firstRepayment = loanRepayments.get(0);
LoanTransactionData firstRepayment = loanRepayments.get(0);
assertThat(firstRepayment.getPrincipal(), is(expectedPrincipalPaid));
assertThat(firstRepayment.getInterest(), is(expectedInterestPaid));
assertThat(firstRepayment.getTotal(), is(expectedTotal));
@@ -147,11 +147,11 @@ public class DerivedLoanDataProcessorTest {
assertThat(periodData.getInterestOutstanding(), is(expectedInterestOutstanding));
// assert repayments are ok
List<LoanRepaymentData> loanRepayments = derivedData.getLoanRepayments();
List<LoanTransactionData> loanRepayments = derivedData.getLoanRepayments();
assertThat(loanRepayments, is(notNullValue()));
assertThat(loanRepayments.size(), is(1));
LoanRepaymentData firstRepayment = loanRepayments.get(0);
LoanTransactionData firstRepayment = loanRepayments.get(0);
assertThat(firstRepayment.getPrincipal(), is(expectedPrincipalPaid));
assertThat(firstRepayment.getInterest(), is(expectedInterestPaid));
assertThat(firstRepayment.getTotal(), is(expectedTotal));
@@ -210,11 +210,11 @@ public class DerivedLoanDataProcessorTest {
assertThat(periodData.getInterestOutstanding(), is(expectedInterestOutstanding));
// assert repayments are ok
List<LoanRepaymentData> loanRepayments = derivedData.getLoanRepayments();
List<LoanTransactionData> loanRepayments = derivedData.getLoanRepayments();
assertThat(loanRepayments, is(notNullValue()));
assertThat(loanRepayments.size(), is(1));
LoanRepaymentData firstRepayment = loanRepayments.get(0);
LoanTransactionData firstRepayment = loanRepayments.get(0);
assertThat(firstRepayment.getPrincipal(), is(expectedPrincipalPaid));
assertThat(firstRepayment.getInterest(), is(expectedInterestPaid));
assertThat(firstRepayment.getTotal(), is(expectedTotal));
@@ -273,11 +273,11 @@ public class DerivedLoanDataProcessorTest {
assertThat(periodData.getInterestOutstanding(), is(expectedInterestOutstanding));
// assert repayments are ok
List<LoanRepaymentData> loanRepayments = derivedData.getLoanRepayments();
List<LoanTransactionData> loanRepayments = derivedData.getLoanRepayments();
assertThat(loanRepayments, is(notNullValue()));
assertThat(loanRepayments.size(), is(1));
LoanRepaymentData firstRepayment = loanRepayments.get(0);
LoanTransactionData firstRepayment = loanRepayments.get(0);
assertThat(firstRepayment.getPrincipal(), is(expectedPrincipalPaid));
assertThat(firstRepayment.getInterest(), is(expectedInterestPaid));
assertThat(firstRepayment.getTotal(), is(expectedTotal));
@@ -359,11 +359,11 @@ public class DerivedLoanDataProcessorTest {
assertThat(secondPeriod.getInterestOutstanding(), is(expectedInterestOutstanding));
// assert repayments are ok
List<LoanRepaymentData> loanRepayments = derivedData.getLoanRepayments();
List<LoanTransactionData> loanRepayments = derivedData.getLoanRepayments();
assertThat(loanRepayments, is(notNullValue()));
assertThat(loanRepayments.size(), is(1));
LoanRepaymentData firstRepayment = loanRepayments.get(0);
LoanTransactionData firstRepayment = loanRepayments.get(0);
assertThat(firstRepayment.getPrincipal(), is(moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("1180").build())));
assertThat(firstRepayment.getInterest(), is(moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("20").build())));
assertThat(firstRepayment.getTotal(), is(moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("1200").build())));