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)) { if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.DESCRIPTION.getValue(), element)) {
final String description = this.fromApiJsonHelper.extractStringNamed(CALENDAR_SUPPORTED_PARAMETERS.DESCRIPTION.getValue(), final String description = this.fromApiJsonHelper.extractStringNamed(CALENDAR_SUPPORTED_PARAMETERS.DESCRIPTION.getValue(),
element); 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); .notExceedingLengthOf(100);
} }
if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.LOCATION.getValue(), element)) { if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.LOCATION.getValue(), element)) {
final String location = this.fromApiJsonHelper.extractStringNamed(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); .notExceedingLengthOf(50);
} }
final String startDateStr = this.fromApiJsonHelper.extractStringNamed(CALENDAR_SUPPORTED_PARAMETERS.START_DATE.getValue(), element); 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(); baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.START_DATE.getValue()).value(startDateStr).notBlank();
final LocalDate startDate = this.fromApiJsonHelper.extractLocalDateNamed(CALENDAR_SUPPORTED_PARAMETERS.START_DATE.getValue(), if(!StringUtils.isBlank(startDateStr)){
element); 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(); baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.START_DATE.getValue()).value(startDate).notNull();
}
if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.END_DATE.getValue(), element)) { if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.END_DATE.getValue(), element)) {
final String endDateStr = this.fromApiJsonHelper.extractStringNamed(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)) { if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.REMIND_BY_ID.getValue(), element)) {
final Integer remindById = this.fromApiJsonHelper.extractIntegerSansLocaleNamed( final Integer remindById = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(
CALENDAR_SUPPORTED_PARAMETERS.REMIND_BY_ID.getValue(), element); 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()); .inMinMaxRange(CalendarRemindBy.getMinValue(), CalendarRemindBy.getMaxValue());
} }
@@ -190,13 +191,13 @@ public class CalendarCommandFromApiJsonDeserializer extends AbstractFromApiJsonD
if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.DESCRIPTION.getValue(), element)) { if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.DESCRIPTION.getValue(), element)) {
final String description = this.fromApiJsonHelper.extractStringNamed(CALENDAR_SUPPORTED_PARAMETERS.DESCRIPTION.getValue(), final String description = this.fromApiJsonHelper.extractStringNamed(CALENDAR_SUPPORTED_PARAMETERS.DESCRIPTION.getValue(),
element); 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); .notExceedingLengthOf(100);
} }
if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.LOCATION.getValue(), element)) { if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.LOCATION.getValue(), element)) {
final String location = this.fromApiJsonHelper.extractStringNamed(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); .notExceedingLengthOf(50);
} }
@@ -242,20 +243,20 @@ public class CalendarCommandFromApiJsonDeserializer extends AbstractFromApiJsonD
if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.REMIND_BY_ID.getValue(), element)) { if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.REMIND_BY_ID.getValue(), element)) {
final Integer remindById = this.fromApiJsonHelper.extractIntegerSansLocaleNamed( final Integer remindById = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(
CALENDAR_SUPPORTED_PARAMETERS.REMIND_BY_ID.getValue(), element); 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()); .inMinMaxRange(CalendarRemindBy.getMinValue(), CalendarRemindBy.getMaxValue());
} }
if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.FIRST_REMINDER.getValue(), element)) { if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.FIRST_REMINDER.getValue(), element)) {
final Integer firstReminder = this.fromApiJsonHelper.extractIntegerSansLocaleNamed( final Integer firstReminder = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(
CALENDAR_SUPPORTED_PARAMETERS.FIRST_REMINDER.getValue(), element); 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)) { if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.SECOND_REMINDER.getValue(), element)) {
final Integer secondReminder = this.fromApiJsonHelper.extractIntegerSansLocaleNamed( final Integer secondReminder = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(
CALENDAR_SUPPORTED_PARAMETERS.SECOND_REMINDER.getValue(), element); 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", if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
@@ -1,6 +1,8 @@
package org.mifosplatform.portfolio.calendar.service; package org.mifosplatform.portfolio.calendar.service;
import java.text.DateFormat;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
@@ -52,8 +54,15 @@ public class CalendarHelper {
final Recur recur = CalendarHelper.getICalRecur(recurringRule); final Recur recur = CalendarHelper.getICalRecur(recurringRule);
if (recur == null) { return null; } if (recur == null) { return null; }
final DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
final Date seed = new Date(seedDate.toDate()); 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 periodStart = new DateTime(periodStartDate.toDate());
final DateTime periodEnd = new DateTime(periodEndDate.toDate()); final DateTime periodEnd = new DateTime(periodEndDate.toDate());
@@ -135,7 +144,7 @@ public class CalendarHelper {
for (@SuppressWarnings("rawtypes") for (@SuppressWarnings("rawtypes")
final Iterator iterator = weekDayList.iterator(); iterator.hasNext();) { final Iterator iterator = weekDayList.iterator(); iterator.hasNext();) {
final WeekDay weekDay = (WeekDay) iterator.next(); final WeekDay weekDay = (WeekDay) iterator.next();
humanReadable += weekDay.getDay(); humanReadable += DayNameEnum.from(weekDay.getDay()).getValue();
} }
} else if (recur.getFrequency().equals(Recur.MONTHLY)) { } 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); final Collection<LocalDate> recurDate = getRecurringDates(recurringRule, seedDate, date, date.plusDays(1), 1);
return (recurDate == null || recurDate.isEmpty()) ? false : true; 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 String recurrence = rs.getString("recurrence");
final Integer remindById = rs.getInt("remindById"); final Integer remindById = rs.getInt("remindById");
EnumOptionData remindBy = null; 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 firstReminder = rs.getInt("firstReminder");
final Integer secondReminder = rs.getInt("secondReminder"); final Integer secondReminder = rs.getInt("secondReminder");
final String humanReadable = CalendarHelper.getRRuleReadable(startDate, recurrence); final String humanReadable = CalendarHelper.getRRuleReadable(startDate, recurrence);
@@ -111,8 +111,8 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
String parentHeirarchyCondition = getParentHierarchyCondition(ceType); String parentHeirarchyCondition = getParentHierarchyCondition(ceType);
final String sql = rm.schema() + " " + parentHeirarchyCondition final String sql = rm.schema() + " " + parentHeirarchyCondition
+ " and ci.entity_type_enum = ? order by c.start_date "; + " and ci.entity_type_enum = ? order by c.start_date ";
//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.GROUPS.getValue() }); return this.jdbcTemplate.query(sql, rm, new Object[] { entityId, CalendarEntityType.CENTERS.getValue() });
} }
@Override @Override
@@ -15,14 +15,16 @@ public class GroupAccountSummaryData {
private final Long productId; private final Long productId;
private final String productName; private final String productName;
private final Integer accountStatusId; private final Integer accountStatusId;
private final String accountNo;
public GroupAccountSummaryData(final Long id, final String externalId, final Long productId, final String productName, 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.id = id;
this.externalId = externalId; this.externalId = externalId;
this.productId = productId; this.productId = productId;
this.productName = productName; this.productName = productName;
this.accountStatusId = accountStatusId; this.accountStatusId = accountStatusId;
this.accountNo = accountNo;
} }
public Long getId() { public Long getId() {
@@ -264,8 +264,8 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService {
public String loanAccountSummarySchema() { public String loanAccountSummarySchema() {
final StringBuilder accountsSummary = new StringBuilder("l.id as id, l.external_id as externalId,"); 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 ") 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 "); .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(); return accountsSummary.toString();
} }
@@ -278,8 +278,8 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService {
final Long productId = JdbcSupport.getLong(rs, "productId"); final Long productId = JdbcSupport.getLong(rs, "productId");
final String loanProductName = rs.getString("productName"); final String loanProductName = rs.getString("productName");
final Integer loanStatusId = JdbcSupport.getInteger(rs, "statusId"); final Integer loanStatusId = JdbcSupport.getInteger(rs, "statusId");
final String accountNo = rs.getString("accountNo");
return new GroupAccountSummaryData(id, externalId, productId, loanProductName, loanStatusId); 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.LoanRepository;
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus; import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
import org.mifosplatform.portfolio.loanaccount.domain.LoanSummaryWrapper; 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.LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeDeleted;
import org.mifosplatform.portfolio.loanaccount.exception.LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeModified; import org.mifosplatform.portfolio.loanaccount.exception.LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeModified;
import org.mifosplatform.portfolio.loanaccount.exception.LoanNotFoundException; 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) { 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"); 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)) { 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(), throw new NotValidRecurringDateException("loan.expected.disbursement.date", errorMessage, edDate.toString(),
calendar.getTitle()); calendar.getTitle());
} }
@@ -534,10 +541,18 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
} }
final LocalDate repStartingDate = command.localDateValueOfParameterNamed("repaymentsStartingFromDate"); final LocalDate repStartingDate = command.localDateValueOfParameterNamed("repaymentsStartingFromDate");
if (repStartingDate != null) { 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)) { 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(), throw new NotValidRecurringDateException("loan.first.repayment.date", errorMessage, repStartingDate.toString(),
calendar.getTitle()); calendar.getTitle());
} }
@@ -8,6 +8,7 @@ package org.mifosplatform.portfolio.loanaccount.service;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; 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.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money; import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.organisation.staff.domain.Staff; 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.Charge;
import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper; import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper;
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeDeletedException; 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.LoanTransactionRepository;
import org.mifosplatform.portfolio.loanaccount.domain.PaymentDetail; import org.mifosplatform.portfolio.loanaccount.domain.PaymentDetail;
import org.mifosplatform.portfolio.loanaccount.domain.PaymentDetailRepository; 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.LoanNotFoundException;
import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerAssignmentException; import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerAssignmentException;
import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerUnassignmentException; 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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
@Service @Service
public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatformService { public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatformService {
@@ -83,6 +92,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private final LoanSummaryWrapper loanSummaryWrapper; private final LoanSummaryWrapper loanSummaryWrapper;
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory; private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
private final PaymentDetailRepository paymentDetailRepository; private final PaymentDetailRepository paymentDetailRepository;
private final CalendarInstanceRepository calendarInstanceRepository;
@Autowired @Autowired
public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
@@ -93,7 +103,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final LoanChargeRepository loanChargeRepository, final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository, final LoanChargeRepository loanChargeRepository, final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository,
final JournalEntryWritePlatformService journalEntryWritePlatformService, final LoanSummaryWrapper loanSummaryWrapper, final JournalEntryWritePlatformService journalEntryWritePlatformService, final LoanSummaryWrapper loanSummaryWrapper,
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory, final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
final PaymentDetailRepository paymentDetailRepository) { final PaymentDetailRepository paymentDetailRepository, final CalendarInstanceRepository calendarInstanceRepository) {
this.context = context; this.context = context;
this.loanEventApiJsonValidator = loanEventApiJsonValidator; this.loanEventApiJsonValidator = loanEventApiJsonValidator;
this.loanAssembler = loanAssembler; this.loanAssembler = loanAssembler;
@@ -108,6 +118,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.loanSummaryWrapper = loanSummaryWrapper; this.loanSummaryWrapper = loanSummaryWrapper;
this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory; this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
this.paymentDetailRepository = paymentDetailRepository; this.paymentDetailRepository = paymentDetailRepository;
this.calendarInstanceRepository = calendarInstanceRepository;
} }
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() { private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
@@ -124,6 +135,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.loanEventApiJsonValidator.validateDisbursement(command.json()); this.loanEventApiJsonValidator.validateDisbursement(command.json());
final Loan loan = retrieveLoanBy(loanId); 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 MonetaryCurrency currency = loan.getCurrency();
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency); final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
@@ -162,6 +178,35 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
.build(); .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 @Transactional
@Override @Override
public Map<String, Object> bulkLoanDisbursal(final JsonCommand command, final CollectionSheetBulkDisbursalCommand bulkDisbursalCommand) { public Map<String, Object> bulkLoanDisbursal(final JsonCommand command, final CollectionSheetBulkDisbursalCommand bulkDisbursalCommand) {