Fixed MIFOSX-301, modified validation conditions for calendar fields and loan disbursement date

This commit is contained in:
ashok-conflux
2013-04-23 13:48:19 +05:30
parent a46c9be5b8
commit db35e26d0a
8 changed files with 137 additions and 28 deletions
@@ -96,22 +96,23 @@ public class CalendarCommandFromApiJsonDeserializer extends AbstractFromApiJsonD
if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.DESCRIPTION.getValue(), element)) {
final String description = this.fromApiJsonHelper.extractStringNamed(CALENDAR_SUPPORTED_PARAMETERS.DESCRIPTION.getValue(),
element);
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.DESCRIPTION.getValue()).value(description).notNull()
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.DESCRIPTION.getValue()).value(description).ignoreIfNull()
.notExceedingLengthOf(100);
}
if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.LOCATION.getValue(), element)) {
final String location = this.fromApiJsonHelper.extractStringNamed(CALENDAR_SUPPORTED_PARAMETERS.LOCATION.getValue(), element);
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.LOCATION.getValue()).value(location).notNull()
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.LOCATION.getValue()).value(location).ignoreIfNull()
.notExceedingLengthOf(50);
}
final String startDateStr = this.fromApiJsonHelper.extractStringNamed(CALENDAR_SUPPORTED_PARAMETERS.START_DATE.getValue(), element);
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.START_DATE.getValue()).value(startDateStr).notBlank();
final LocalDate startDate = this.fromApiJsonHelper.extractLocalDateNamed(CALENDAR_SUPPORTED_PARAMETERS.START_DATE.getValue(),
element);
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.START_DATE.getValue()).value(startDate).notNull();
if(!StringUtils.isBlank(startDateStr)){
final LocalDate startDate = this.fromApiJsonHelper.extractLocalDateNamed(CALENDAR_SUPPORTED_PARAMETERS.START_DATE.getValue(), element);
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.START_DATE.getValue()).value(startDate).notNull();
}
if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.END_DATE.getValue(), element)) {
final String endDateStr = this.fromApiJsonHelper.extractStringNamed(CALENDAR_SUPPORTED_PARAMETERS.END_DATE.getValue(), element);
@@ -149,7 +150,7 @@ public class CalendarCommandFromApiJsonDeserializer extends AbstractFromApiJsonD
if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.REMIND_BY_ID.getValue(), element)) {
final Integer remindById = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(
CALENDAR_SUPPORTED_PARAMETERS.REMIND_BY_ID.getValue(), element);
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.REMIND_BY_ID.getValue()).value(remindById).notNull()
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.REMIND_BY_ID.getValue()).value(remindById).ignoreIfNull()
.inMinMaxRange(CalendarRemindBy.getMinValue(), CalendarRemindBy.getMaxValue());
}
@@ -190,13 +191,13 @@ public class CalendarCommandFromApiJsonDeserializer extends AbstractFromApiJsonD
if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.DESCRIPTION.getValue(), element)) {
final String description = this.fromApiJsonHelper.extractStringNamed(CALENDAR_SUPPORTED_PARAMETERS.DESCRIPTION.getValue(),
element);
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.DESCRIPTION.getValue()).value(description).notNull()
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.DESCRIPTION.getValue()).value(description).ignoreIfNull()
.notExceedingLengthOf(100);
}
if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.LOCATION.getValue(), element)) {
final String location = this.fromApiJsonHelper.extractStringNamed(CALENDAR_SUPPORTED_PARAMETERS.LOCATION.getValue(), element);
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.LOCATION.getValue()).value(location).notNull()
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.LOCATION.getValue()).value(location).ignoreIfNull()
.notExceedingLengthOf(50);
}
@@ -242,20 +243,20 @@ public class CalendarCommandFromApiJsonDeserializer extends AbstractFromApiJsonD
if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.REMIND_BY_ID.getValue(), element)) {
final Integer remindById = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(
CALENDAR_SUPPORTED_PARAMETERS.REMIND_BY_ID.getValue(), element);
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.REMIND_BY_ID.getValue()).value(remindById).notNull()
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.REMIND_BY_ID.getValue()).value(remindById).ignoreIfNull()
.inMinMaxRange(CalendarRemindBy.getMinValue(), CalendarRemindBy.getMaxValue());
}
if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.FIRST_REMINDER.getValue(), element)) {
final Integer firstReminder = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(
CALENDAR_SUPPORTED_PARAMETERS.FIRST_REMINDER.getValue(), element);
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.FIRST_REMINDER.getValue()).value(firstReminder).notNull();
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.FIRST_REMINDER.getValue()).value(firstReminder).ignoreIfNull();
}
if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.SECOND_REMINDER.getValue(), element)) {
final Integer secondReminder = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(
CALENDAR_SUPPORTED_PARAMETERS.SECOND_REMINDER.getValue(), element);
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.SECOND_REMINDER.getValue()).value(secondReminder).notNull();
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.SECOND_REMINDER.getValue()).value(secondReminder).ignoreIfNull();
}
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
@@ -1,6 +1,8 @@
package org.mifosplatform.portfolio.calendar.service;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
@@ -52,8 +54,15 @@ public class CalendarHelper {
final Recur recur = CalendarHelper.getICalRecur(recurringRule);
if (recur == null) { return null; }
final Date seed = new Date(seedDate.toDate());
final DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
final String seedDateStr = df.format(seedDate.toDateTimeAtStartOfDay().toDate());
Date seed = null;
try {
seed = new Date(seedDateStr, "yyyy-MM-dd");
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
final DateTime periodStart = new DateTime(periodStartDate.toDate());
final DateTime periodEnd = new DateTime(periodEndDate.toDate());
@@ -135,7 +144,7 @@ public class CalendarHelper {
for (@SuppressWarnings("rawtypes")
final Iterator iterator = weekDayList.iterator(); iterator.hasNext();) {
final WeekDay weekDay = (WeekDay) iterator.next();
humanReadable += weekDay.getDay();
humanReadable += DayNameEnum.from(weekDay.getDay()).getValue();
}
} else if (recur.getFrequency().equals(Recur.MONTHLY)) {
@@ -175,4 +184,24 @@ public class CalendarHelper {
final Collection<LocalDate> recurDate = getRecurringDates(recurringRule, seedDate, date, date.plusDays(1), 1);
return (recurDate == null || recurDate.isEmpty()) ? false : true;
}
public static enum DayNameEnum{
MO("Monday"),TU("Tuesday"),WE("Wednesday"),TH("Thursday"),FR("Friday"),SA("Saturday"),SU("Sunday");
private final String value;
private DayNameEnum(String value){
this.value = value;
}
public String getValue(){
return this.value;
}
public static DayNameEnum from(String code){
for (DayNameEnum dayName : DayNameEnum.values()){
if(dayName.toString().equals(code)) return dayName;
}
return DayNameEnum.MO;//Default it to Monday
}
}
}
@@ -64,7 +64,7 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
final String recurrence = rs.getString("recurrence");
final Integer remindById = rs.getInt("remindById");
EnumOptionData remindBy = null;
if(remindById != null) remindBy = CalendarEnumerations.calendarRemindBy(remindById);
if(remindById != null && remindById != 0) remindBy = CalendarEnumerations.calendarRemindBy(remindById);
final Integer firstReminder = rs.getInt("firstReminder");
final Integer secondReminder = rs.getInt("secondReminder");
final String humanReadable = CalendarHelper.getRRuleReadable(startDate, recurrence);
@@ -111,8 +111,8 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
String parentHeirarchyCondition = getParentHierarchyCondition(ceType);
final String sql = rm.schema() + " " + parentHeirarchyCondition
+ " and ci.entity_type_enum = ? order by c.start_date ";
return this.jdbcTemplate.query(sql, rm, new Object[] { entityId, CalendarEntityType.GROUPS.getValue() });
//FIXME :AA center is the parent entity of group, change this code to support more parent entity types.
return this.jdbcTemplate.query(sql, rm, new Object[] { entityId, CalendarEntityType.CENTERS.getValue() });
}
@Override
@@ -15,14 +15,16 @@ public class GroupAccountSummaryData {
private final Long productId;
private final String productName;
private final Integer accountStatusId;
private final String accountNo;
public GroupAccountSummaryData(final Long id, final String externalId, final Long productId, final String productName,
final Integer accountStatusId) {
final Integer accountStatusId, final String accountNo) {
this.id = id;
this.externalId = externalId;
this.productId = productId;
this.productName = productName;
this.accountStatusId = accountStatusId;
this.accountNo = accountNo;
}
public Long getId() {
@@ -264,8 +264,8 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService {
public String loanAccountSummarySchema() {
final StringBuilder accountsSummary = new StringBuilder("l.id as id, l.external_id as externalId,");
accountsSummary.append("l.product_id as productId, lp.name as productName,").append("l.loan_status_id as statusId ")
.append("from m_loan l ").append("LEFT JOIN m_product_loan AS lp ON lp.id = l.product_id ");
accountsSummary.append("l.product_id as productId, lp.name as productName,").append("l.loan_status_id as statusId, ")
.append("l.account_no as accountNo ").append("from m_loan l ").append("LEFT JOIN m_product_loan AS lp ON lp.id = l.product_id ");
return accountsSummary.toString();
}
@@ -278,8 +278,8 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService {
final Long productId = JdbcSupport.getLong(rs, "productId");
final String loanProductName = rs.getString("productName");
final Integer loanStatusId = JdbcSupport.getInteger(rs, "statusId");
return new GroupAccountSummaryData(id, externalId, productId, loanProductName, loanStatusId);
final String accountNo = rs.getString("accountNo");
return new GroupAccountSummaryData(id, externalId, productId, loanProductName, loanStatusId, accountNo);
}
}
}
@@ -0,0 +1,17 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.portfolio.loanaccount.exception;
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
public class LoanApplicationDateException extends AbstractPlatformDomainRuleException {
public LoanApplicationDateException(String postFix, String defaultUserMessage,
Object... defaultUserMessageArgs) {
super("error.msg.loan.application." + postFix, defaultUserMessage, defaultUserMessageArgs);
}
}
@@ -44,6 +44,7 @@ import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleTrans
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
import org.mifosplatform.portfolio.loanaccount.domain.LoanSummaryWrapper;
import org.mifosplatform.portfolio.loanaccount.exception.LoanApplicationDateException;
import org.mifosplatform.portfolio.loanaccount.exception.LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeDeleted;
import org.mifosplatform.portfolio.loanaccount.exception.LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeModified;
import org.mifosplatform.portfolio.loanaccount.exception.LoanNotFoundException;
@@ -520,13 +521,19 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
private void validateCalendarDates(final JsonCommand command, final Calendar calendar) {
// Validate disbursement date and first repayment dates matches calendar
// date
final LocalDate edDate = command.localDateValueOfParameterNamed("expectedDisbursementDate");
if (edDate != null) {
if (edDate != null) {
//Expected disbursement date should not be before Meeting start date
if(edDate.isBefore(calendar.getStartDateLocalDate())){
final String errorMessage = "Expected disbursement date '" + edDate.toString() + "' cannot be before meeting start date '"
+ calendar.getStartDate().toString() + "' ";
throw new LoanApplicationDateException("disbursement.date.cannot.be.before.meeting.start.date", errorMessage, edDate, calendar.getStartDate());
}
//Disbursement date should fall on a meeting date
if (!CalendarHelper.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(), edDate)) {
final String errorMessage = "The expected disbursement date :" + (edDate.toString()) + " does not fall on a meeting date.";
final String errorMessage = "Expected disbursement date '" + edDate.toString() + "' does not fall on a meeting date.";
throw new NotValidRecurringDateException("loan.expected.disbursement.date", errorMessage, edDate.toString(),
calendar.getTitle());
}
@@ -534,10 +541,18 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
}
final LocalDate repStartingDate = command.localDateValueOfParameterNamed("repaymentsStartingFromDate");
if (repStartingDate != null) {
//First repayment date should not be before Meeting date
if(repStartingDate.isBefore(calendar.getStartDateLocalDate())){
final String errorMessage = "First repayment date '" + repStartingDate.toString() + "' cannot be before meeting start date '"
+ calendar.getStartDate().toString() + "' ";
throw new LoanApplicationDateException("first.repayment.date.cannot.be.before.meeting.start.date", errorMessage, repStartingDate, calendar.getStartDate());
}
if (!CalendarHelper.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(), repStartingDate)) {
final String errorMessage = "The First repayment date :" + (repStartingDate.toString()) + " do not fall a meeting date.";
final String errorMessage = "The First repayment date '" + repStartingDate.toString() + "' does not fall on a meeting date.";
throw new NotValidRecurringDateException("loan.first.repayment.date", errorMessage, repStartingDate.toString(),
calendar.getTitle());
}
@@ -8,6 +8,7 @@ package org.mifosplatform.portfolio.loanaccount.service;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -24,6 +25,12 @@ import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyReposit
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.organisation.staff.domain.Staff;
import org.mifosplatform.portfolio.calendar.domain.Calendar;
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
import org.mifosplatform.portfolio.calendar.domain.CalendarInstanceRepository;
import org.mifosplatform.portfolio.calendar.exception.NotValidRecurringDateException;
import org.mifosplatform.portfolio.calendar.service.CalendarHelper;
import org.mifosplatform.portfolio.charge.domain.Charge;
import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper;
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeDeletedException;
@@ -52,6 +59,7 @@ import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionRepository;
import org.mifosplatform.portfolio.loanaccount.domain.PaymentDetail;
import org.mifosplatform.portfolio.loanaccount.domain.PaymentDetailRepository;
import org.mifosplatform.portfolio.loanaccount.exception.LoanApplicationDateException;
import org.mifosplatform.portfolio.loanaccount.exception.LoanNotFoundException;
import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerAssignmentException;
import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerUnassignmentException;
@@ -65,6 +73,7 @@ import org.mifosplatform.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
@Service
public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatformService {
@@ -83,6 +92,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private final LoanSummaryWrapper loanSummaryWrapper;
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
private final PaymentDetailRepository paymentDetailRepository;
private final CalendarInstanceRepository calendarInstanceRepository;
@Autowired
public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
@@ -93,7 +103,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final LoanChargeRepository loanChargeRepository, final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository,
final JournalEntryWritePlatformService journalEntryWritePlatformService, final LoanSummaryWrapper loanSummaryWrapper,
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
final PaymentDetailRepository paymentDetailRepository) {
final PaymentDetailRepository paymentDetailRepository, final CalendarInstanceRepository calendarInstanceRepository) {
this.context = context;
this.loanEventApiJsonValidator = loanEventApiJsonValidator;
this.loanAssembler = loanAssembler;
@@ -108,6 +118,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.loanSummaryWrapper = loanSummaryWrapper;
this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
this.paymentDetailRepository = paymentDetailRepository;
this.calendarInstanceRepository = calendarInstanceRepository;
}
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
@@ -124,6 +135,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.loanEventApiJsonValidator.validateDisbursement(command.json());
final Loan loan = retrieveLoanBy(loanId);
//validate actual disbursement date against meeting date
Collection<CalendarInstance> calendarInstances = this.calendarInstanceRepository.findByEntityIdAndEntityTypeId(loan.getId(), CalendarEntityType.LOANS.getValue());
validateDisbursementDate(command.localDateValueOfParameterNamed("actualDisbursementDate"), calendarInstances);
final MonetaryCurrency currency = loan.getCurrency();
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
@@ -162,6 +178,35 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
.build();
}
private void validateDisbursementDate(LocalDate disbursementDate, Collection<CalendarInstance> calendarInstances) {
if (!CollectionUtils.isEmpty(calendarInstances)) {
Calendar calendar = null;
for (CalendarInstance calendarInstance : calendarInstances) {
calendar = calendarInstance.getCalendar();
break;
}
if (calendar != null && disbursementDate != null) {
// Actual disbursement date cannot be before Meeting start
// date
if (disbursementDate.isBefore(calendar.getStartDateLocalDate())) {
final String errorMessage = "Actual disbursement date '" + disbursementDate.toString()
+ "' cannot be before meeting start date '" + calendar.getStartDate().toString() + "' ";
throw new LoanApplicationDateException("actual.disbursement.date.cannot.be.before.meeting.start.date", errorMessage, disbursementDate.toString(),
calendar.getStartDate());
}
// Disbursement date should fall on a meeting date
if (!CalendarHelper.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(), disbursementDate)) {
final String errorMessage = "Expected disbursement date '" + disbursementDate.toString() + "' does not fall on a meeting date.";
throw new NotValidRecurringDateException("loan.actual.disbursement.date", errorMessage, disbursementDate.toString(),
calendar.getTitle());
}
}
}
}
@Transactional
@Override
public Map<String, Object> bulkLoanDisbursal(final JsonCommand command, final CollectionSheetBulkDisbursalCommand bulkDisbursalCommand) {