From db35e26d0a3bac5280d28e85112ef07460f72bda Mon Sep 17 00:00:00 2001 From: ashok-conflux Date: Tue, 23 Apr 2013 13:07:37 +0530 Subject: [PATCH] Fixed MIFOSX-301, modified validation conditions for calendar fields and loan disbursement date --- ...alendarCommandFromApiJsonDeserializer.java | 23 ++++----- .../calendar/service/CalendarHelper.java | 35 ++++++++++++-- .../CalendarReadPlatformServiceImpl.java | 6 +-- .../group/data/GroupAccountSummaryData.java | 4 +- .../service/GroupReadPlatformServiceImpl.java | 8 ++-- .../LoanApplicationDateException.java | 17 +++++++ ...WritePlatformServiceJpaRepositoryImpl.java | 25 ++++++++-- ...WritePlatformServiceJpaRepositoryImpl.java | 47 ++++++++++++++++++- 8 files changed, 137 insertions(+), 28 deletions(-) create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/exception/LoanApplicationDateException.java diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/serialization/CalendarCommandFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/serialization/CalendarCommandFromApiJsonDeserializer.java index e545a4071..a02b6b1a4 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/serialization/CalendarCommandFromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/serialization/CalendarCommandFromApiJsonDeserializer.java @@ -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", diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/service/CalendarHelper.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/service/CalendarHelper.java index e0b827590..13516c36a 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/service/CalendarHelper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/service/CalendarHelper.java @@ -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 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 + } + } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/service/CalendarReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/service/CalendarReadPlatformServiceImpl.java index 147766737..62cabeb6e 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/service/CalendarReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/service/CalendarReadPlatformServiceImpl.java @@ -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 diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/data/GroupAccountSummaryData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/data/GroupAccountSummaryData.java index 7695d50ee..18493e3c7 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/data/GroupAccountSummaryData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/data/GroupAccountSummaryData.java @@ -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() { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupReadPlatformServiceImpl.java index e296b0d4b..a23746b13 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupReadPlatformServiceImpl.java @@ -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); } } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/exception/LoanApplicationDateException.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/exception/LoanApplicationDateException.java new file mode 100644 index 000000000..944e32c9b --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/exception/LoanApplicationDateException.java @@ -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); + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java index e557671d5..7ed175398 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java @@ -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()); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java index 8c7c17704..5461994a5 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java @@ -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 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 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 bulkLoanDisbursal(final JsonCommand command, final CollectionSheetBulkDisbursalCommand bulkDisbursalCommand) {