MIFOSX-256: Added calendar meeting date validation for expected disbursment date and first repayment date

This commit is contained in:
ashok-conflux
2013-03-20 21:03:38 +05:30
parent 7ae32b346d
commit eec727db5b
12 changed files with 329 additions and 224 deletions
@@ -365,7 +365,7 @@ public class DataValidatorBuilder {
return this;
}
public DataValidatorBuilder isValidateRecurringRule(final String recurringRule) {
public DataValidatorBuilder isValidRecurringRule(final String recurringRule) {
if (StringUtils.isNotBlank(recurringRule)) {
try {
RRule rRule = new RRule(recurringRule);
@@ -40,7 +40,7 @@ import org.mifosplatform.portfolio.calendar.domain.Calendar;
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
import org.mifosplatform.portfolio.calendar.service.CalendarDropdownReadPlatformService;
import org.mifosplatform.portfolio.calendar.service.CalendarReadPlatformService;
import org.mifosplatform.portfolio.calendar.service.CalendarWrapperService;
import org.mifosplatform.portfolio.calendar.service.CalendarHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@@ -54,9 +54,9 @@ public class CalendarsApiResource {
* The set of parameters that are supported in response for {@link Calendar}
*/
private final Set<String> RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "entityId", "entityType", "title",
"description", "location", "startDate", "endDate", "duration", "type", "repeating", "recurrence", "remindBy",
"firstReminder", "secondReminder", "humanReadable", "createdDate", "lastUpdatedDate", "createdByUserId", "createdByUsername", "lastUpdatedByUserId",
"lastUpdatedByUsername", "recurringDates"));
"description", "location", "startDate", "endDate", "duration", "type", "repeating", "recurrence", "remindBy", "firstReminder",
"secondReminder", "humanReadable", "createdDate", "lastUpdatedDate", "createdByUserId", "createdByUsername",
"lastUpdatedByUserId", "lastUpdatedByUsername", "recurringDates"));
private final String resourceNameForPermissions = "CALENDAR";
private final PlatformSecurityContext context;
@@ -65,38 +65,37 @@ public class CalendarsApiResource {
private final ApiRequestParameterHelper apiRequestParameterHelper;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
private final CalendarDropdownReadPlatformService dropdownReadPlatformService;
private final CalendarWrapperService calendarWrapperService;
@Autowired
public CalendarsApiResource(final PlatformSecurityContext context, final CalendarReadPlatformService readPlatformService,
final DefaultToApiJsonSerializer<CalendarData> toApiJsonSerializer, final ApiRequestParameterHelper apiRequestParameterHelper,
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
final CalendarDropdownReadPlatformService dropdownReadPlatformService, final CalendarWrapperService calendarWrapperService) {
final CalendarDropdownReadPlatformService dropdownReadPlatformService) {
this.context = context;
this.readPlatformService = readPlatformService;
this.toApiJsonSerializer = toApiJsonSerializer;
this.apiRequestParameterHelper = apiRequestParameterHelper;
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
this.dropdownReadPlatformService = dropdownReadPlatformService;
this.calendarWrapperService = calendarWrapperService;
}
@GET
@Path("{calendarId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveCalendar(@PathParam("calendarId") final Long calendarId, @PathParam("entityType") final String entityType, @PathParam("entityId") final Long entityId, @Context final UriInfo uriInfo) {
public String retrieveCalendar(@PathParam("calendarId") final Long calendarId, @PathParam("entityType") final String entityType,
@PathParam("entityId") final Long entityId, @Context final UriInfo uriInfo) {
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
final Integer entityTypeId = CalendarEntityType.valueOf(entityType.toUpperCase()).getValue();
CalendarData calendarData = this.readPlatformService.retrieveCalendar(calendarId, entityId, entityTypeId);
//Include recurring date details
calendarData = handleRecurringDate(calendarData);
// Include recurring date details
calendarData = handleRecurringDate(calendarData);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
if(settings.isTemplate()){
calendarData = handleTemplate(calendarData);
if (settings.isTemplate()) {
calendarData = handleTemplate(calendarData);
}
return this.toApiJsonSerializer.serialize(settings, calendarData, this.RESPONSE_DATA_PARAMETERS);
}
@@ -108,11 +107,11 @@ public class CalendarsApiResource {
@Context final UriInfo uriInfo) {
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
final Set<String> associationParameters = ApiParameterHelper.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters());
Collection<CalendarData> calendarsData = new ArrayList<CalendarData>();
if (!associationParameters.isEmpty()) {
if (associationParameters.contains("parentCalendars")) {
calendarsData.addAll(this.readPlatformService.retrieveParentCalendarsByEntity(entityId,
@@ -120,12 +119,12 @@ public class CalendarsApiResource {
}
}
calendarsData.addAll(this.readPlatformService.retrieveCalendarsByEntity(entityId, CalendarEntityType.valueOf(entityType.toUpperCase())
.getValue()));
calendarsData.addAll(this.readPlatformService.retrieveCalendarsByEntity(entityId,
CalendarEntityType.valueOf(entityType.toUpperCase()).getValue()));
//Add recurring dates
// Add recurring dates
calendarsData = handleRecurringDates(calendarsData);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, calendarsData, this.RESPONSE_DATA_PARAMETERS);
}
@@ -198,17 +197,18 @@ public class CalendarsApiResource {
private CalendarData handleRecurringDate(final CalendarData calendarData){
if(!calendarData.isRepeating()) return calendarData;
final Collection<LocalDate> recurringDates = this.calendarWrapperService.getNextRecurrencesList(calendarData);
final Collection<LocalDate> recurringDates = CalendarHelper.getRecurringDates(calendarData.getRecurrence(), calendarData.getStartDate(), calendarData.getEndDate());
return new CalendarData(calendarData, recurringDates);
}
private Collection<CalendarData> handleRecurringDates(final Collection<CalendarData> calendarsData){
private Collection<CalendarData> handleRecurringDates(final Collection<CalendarData> calendarsData) {
Collection<CalendarData> recuCalendarsData = new ArrayList<CalendarData>();
for (CalendarData calendarData : calendarsData) {
recuCalendarsData.add(handleRecurringDate(calendarData));
}
return recuCalendarsData;
}
}
@@ -267,7 +267,7 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
return this.secondReminder;
}
private LocalDate getStartDateLocalDate() {
public LocalDate getStartDateLocalDate() {
LocalDate startDateLocalDate = null;
if (this.startDate != null) {
startDateLocalDate = LocalDate.fromDateFields(this.startDate);
@@ -275,7 +275,7 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
return startDateLocalDate;
}
private LocalDate getEndDateLocalDate() {
public LocalDate getEndDateLocalDate() {
LocalDate endDateLocalDate = null;
if (this.endDate != null) {
endDateLocalDate = LocalDate.fromDateFields(this.endDate);
@@ -29,12 +29,20 @@ public class CalendarInstance extends AbstractPersistable<Long> {
this.entityTypeId = entityTypeId;
}
protected CalendarInstance(){
}
public static CalendarInstance fromJson(final Calendar calendar, final JsonCommand command) {
final Long entityId = command.getSupportedEntityId();
final Integer entityTypeId = CalendarEntityType.valueOf(command.getSupportedEntityType().toUpperCase()).getValue();
return new CalendarInstance(calendar, entityId, entityTypeId);
}
public void updateCalendar(final Calendar calendar){
this.calendar = calendar;
}
public Calendar getCalendar() {
return this.calendar;
}
@@ -1,5 +1,7 @@
package org.mifosplatform.portfolio.calendar.domain;
import java.util.Collection;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
@@ -7,4 +9,6 @@ public interface CalendarInstanceRepository extends JpaRepository<CalendarInstan
CalendarInstance findByCalendarAndEntityIdAndEntityTypeId(Long calendarId, Long entityId, Integer entityTypeId);
Collection<CalendarInstance> findByEntityIdAndEntityTypeId(Long entityId, Integer entityTypeId);
}
@@ -0,0 +1,18 @@
/**
* 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.calendar.exception;
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
/**
* A {@link RuntimeException} thrown when Calendar resources are not found.
*/
public class NotValidRecurringDateException extends AbstractPlatformDomainRuleException {
public NotValidRecurringDateException(String postFix, String defaultUserMessage, Object... defaultUserMessageArgs) {
super("error.msg.calendar." + postFix + ".not.valid.recurring.date", defaultUserMessage, defaultUserMessageArgs);
}
}
@@ -142,7 +142,7 @@ public class CalendarCommandFromApiJsonDeserializer extends AbstractFromApiJsonD
if(repeating){
final String recurrence = this.fromApiJsonHelper.extractStringNamed(CALENDAR_SUPPORTED_PARAMETERS.RECURRENCE.getValue(), element);
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.RECURRENCE.getValue()).value(recurrence).notNull()
.notExceedingLengthOf(100).isValidateRecurringRule(recurrence);
.notExceedingLengthOf(100).isValidRecurringRule(recurrence);
}
}
@@ -235,7 +235,7 @@ public class CalendarCommandFromApiJsonDeserializer extends AbstractFromApiJsonD
if(repeating){
final String recurrence = this.fromApiJsonHelper.extractStringNamed(CALENDAR_SUPPORTED_PARAMETERS.RECURRENCE.getValue(), element);
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.RECURRENCE.getValue()).value(recurrence).notNull()
.notExceedingLengthOf(100).isValidateRecurringRule(recurrence);
.notExceedingLengthOf(100).isValidRecurringRule(recurrence);
}
}
@@ -0,0 +1,178 @@
package org.mifosplatform.portfolio.calendar.service;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import net.fortuna.ical4j.model.Date;
import net.fortuna.ical4j.model.DateList;
import net.fortuna.ical4j.model.DateTime;
import net.fortuna.ical4j.model.Recur;
import net.fortuna.ical4j.model.ValidationException;
import net.fortuna.ical4j.model.WeekDay;
import net.fortuna.ical4j.model.WeekDayList;
import net.fortuna.ical4j.model.parameter.Value;
import net.fortuna.ical4j.model.property.RRule;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
import org.mifosplatform.infrastructure.core.service.DateUtils;
public class CalendarHelper {
public static LocalDate getNextRecurringDate(final String recurringRule, final LocalDate seedDate, final LocalDate startDate) {
final Recur recur = CalendarHelper.getICalRecur(recurringRule);
if (recur == null) { return null; }
final Date nextRecDate = recur.getNextDate(new Date(seedDate.toDate()), new Date(startDate.toDate()));
return nextRecDate == null ? null : new LocalDate(nextRecDate);
}
public static Collection<LocalDate> getRecurringDates(final String recurringRule, final LocalDate seedDate, final LocalDate endDate) {
final LocalDate periodStartDate = DateUtils.getLocalDateOfTenant();
final LocalDate periodEndDate = (endDate == null) ? DateUtils.getLocalDateOfTenant().plusYears(5) : endDate;
return getRecurringDates(recurringRule, seedDate, periodStartDate, periodEndDate);
}
public static Collection<LocalDate> getRecurringDates(final String recurringRule, final LocalDate seedDate,
final LocalDate periodStartDate, final LocalDate periodEndDate) {
final int maxCount = 15;// Default number of recurring dates
return getRecurringDates(recurringRule, seedDate, periodStartDate, periodEndDate, maxCount);
}
public static Collection<LocalDate> getRecurringDates(final String recurringRule, final LocalDate seedDate,
final LocalDate periodStartDate, final LocalDate periodEndDate, final int maxCount) {
final Recur recur = CalendarHelper.getICalRecur(recurringRule);
if (recur == null) { return null; }
final Date seed = new Date(seedDate.toDate());
final DateTime periodStart = new DateTime(periodStartDate.toDate());
final DateTime periodEnd = new DateTime(periodEndDate.toDate());
final Value value = new Value(Value.DATE.getValue());
final DateList recurringDates = recur.getDates(seed, periodStart, periodEnd, value, maxCount);
return convertToLocalDateList(recurringDates);
}
private static Collection<LocalDate> convertToLocalDateList(final DateList dates) {
final Collection<LocalDate> recurringDates = new ArrayList<LocalDate>();
for (@SuppressWarnings("rawtypes")
final Iterator iterator = dates.iterator(); iterator.hasNext();) {
final Date date = (Date) iterator.next();
recurringDates.add(new LocalDate(date));
}
return recurringDates;
}
public static Recur getICalRecur(final String recurringRule) {
// Construct RRule
try {
final RRule rrule = new RRule(recurringRule);
rrule.validate();
final Recur recur = rrule.getRecur();
return recur;
} catch (final ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (final ValidationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static String getRRuleReadable(final LocalDate startDate, final String recurringRule) {
String humanReadable = "";
RRule rrule;
Recur recur = null;
try {
rrule = new RRule(recurringRule);
rrule.validate();
recur = rrule.getRecur();
} catch (final ValidationException e) {
throw new PlatformDataIntegrityException("error.msg.invalid.recurring.rule", "The Recurring Rule value: " + recurringRule
+ " is not valid.", "recurrence", recurringRule);
} catch (final ParseException e) {
throw new PlatformDataIntegrityException("error.msg.recurring.rule.parsing.error",
"Error in pasring the Recurring Rule value: " + recurringRule, "recurrence", recurringRule);
}
if (recur == null) { return humanReadable; }
if (recur.getFrequency().equals(Recur.DAILY)) {
if (recur.getInterval() == 1) {
humanReadable = "Daily";
} else {
humanReadable = "Every " + recur.getInterval() + " days";
}
} else if (recur.getFrequency().equals(Recur.WEEKLY)) {
if (recur.getInterval() == 1 || recur.getInterval() == -1) {
humanReadable = "Weekly";
} else {
humanReadable = "Every " + recur.getInterval() + " weeks";
}
humanReadable += " on ";
final WeekDayList weekDayList = recur.getDayList();
for (@SuppressWarnings("rawtypes")
final Iterator iterator = weekDayList.iterator(); iterator.hasNext();) {
final WeekDay weekDay = (WeekDay) iterator.next();
humanReadable += weekDay.getDay();
}
} else if (recur.getFrequency().equals(Recur.MONTHLY)) {
if (recur.getInterval() == 1) {
humanReadable = "Monthly on day " + startDate.getDayOfMonth();
} else {
humanReadable = "Every " + recur.getInterval() + " months on day " + startDate.getDayOfMonth();
}
} else if (recur.getFrequency().equals(Recur.YEARLY)) {
if (recur.getInterval() == 1) {
humanReadable = "Annually on " + startDate.toString("MMM") + " " + startDate.getDayOfMonth();
} else {
humanReadable = "Every " + recur.getInterval() + " years on " + startDate.toString("MMM") + " " + startDate.getDayOfMonth();
}
}
if (recur.getCount() > 0) {
if (recur.getCount() == 1) {
humanReadable = "Once";
}
humanReadable += ", " + recur.getCount() + " times";
}
final Date endDate = recur.getUntil();
final LocalDate date = new LocalDate(endDate);
final DateTimeFormatter fmt = DateTimeFormat.forPattern("dd MMMM YY");
final String formattedDate = date.toString(fmt);
if (endDate != null) {
humanReadable += ", until " + formattedDate;
}
return humanReadable;
}
public static boolean isValidRedurringDate(final String recurringRule, final LocalDate seedDate, final LocalDate date){
final Collection<LocalDate> recurDate = getRecurringDates(recurringRule, seedDate, date, date.plusDays(1), 1);
return (recurDate == null || recurDate.isEmpty()) ? false : true;
}
}
@@ -67,7 +67,7 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
if(remindById != null) remindBy = CalendarEnumerations.calendarRemindBy(remindById);
final Integer firstReminder = rs.getInt("firstReminder");
final Integer secondReminder = rs.getInt("secondReminder");
final String humanReadable = CalendarWrapperService.getRRuleReadable(startDate, recurrence);
final String humanReadable = CalendarHelper.getRRuleReadable(startDate, recurrence);
final LocalDate createdDate = JdbcSupport.getLocalDate(rs, "createdDate");
final LocalDate lastUpdatedDate = JdbcSupport.getLocalDate(rs, "updatedDate");
@@ -1,187 +0,0 @@
package org.mifosplatform.portfolio.calendar.service;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Iterator;
import net.fortuna.ical4j.model.Date;
import net.fortuna.ical4j.model.DateList;
import net.fortuna.ical4j.model.DateTime;
import net.fortuna.ical4j.model.Recur;
import net.fortuna.ical4j.model.ValidationException;
import net.fortuna.ical4j.model.WeekDay;
import net.fortuna.ical4j.model.WeekDayList;
import net.fortuna.ical4j.model.parameter.Value;
import net.fortuna.ical4j.model.property.RRule;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
import org.mifosplatform.portfolio.calendar.data.CalendarData;
import org.springframework.stereotype.Service;
@Service
public class CalendarWrapperService {
public CalendarWrapperService() {
}
public LocalDate getNextRecurrence(final CalendarData calendar) {
final Recur recur = getRecur(calendar);
if (recur == null) { return null; }
final Date nextRecDate = recur.getNextDate(new Date(calendar.getStartDate().toDate()), new Date(calendar.getStartDate().toDate()));
final LocalDate lNextRecDate = new LocalDate(nextRecDate);
return lNextRecDate;
}
public Collection<LocalDate> getNextRecurrencesList(final CalendarData calendarData) {
int maxCount = 10;//Default number of recurring dates
LocalDate periodStartDate = new LocalDate(Calendar.getInstance().getTime());
return getNextRecurrencesList(calendarData, maxCount, periodStartDate);
}
public Collection<LocalDate> getNextRecurrencesList(final CalendarData calendarData, int maxCount, final LocalDate psDate) {
final Recur recur = getRecur(calendarData);
if (recur == null) { return null; }
final Date seed = new Date(calendarData.getStartDate().toDate());
final DateTime periodStart = new DateTime(psDate.toDate());
Calendar endDate = Calendar.getInstance();
endDate.setTime(calendarData.getStartDate().toDate());
if(calendarData.getEndDate() != null){
endDate.setTime(calendarData.getEndDate().toDate());
}else{
endDate.add(Calendar.YEAR, 5);
}
final DateTime periodEnd = new DateTime(endDate.getTime());
final Value value = new Value(Value.DATE.getValue());
return getRecurringDates(recur.getDates(seed, periodStart, periodEnd, value, maxCount));
}
private Collection<LocalDate> getRecurringDates(final DateList dates) {
Collection<LocalDate> recurringDates = new ArrayList<LocalDate>();
for (@SuppressWarnings("rawtypes")
final Iterator iterator = dates.iterator(); iterator.hasNext();) {
final Date date = (Date) iterator.next();
recurringDates.add(new LocalDate(date));
}
return recurringDates;
}
private Recur getRecur(final CalendarData calendar) {
if (!calendar.isRepeating()) {
// throw exception or return null
// throw new CalendarNotReccuring();
return null;
}
// Construct RRule
try {
final RRule rrule = new RRule(calendar.getRecurrence());
rrule.validate();
final Recur recur = rrule.getRecur();
return recur;
} catch (final ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (final ValidationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static String getRRuleReadable(final LocalDate startDate, final String recurringRule){
String humanReadable = "";
RRule rrule;
Recur recur = null;
try {
rrule = new RRule(recurringRule);
rrule.validate();
recur = rrule.getRecur();
} catch (ValidationException e) {
throw new PlatformDataIntegrityException("error.msg.invalid.recurring.rule",
"The Recurring Rule value: " + recurringRule + " is not valid.", "recurrence", recurringRule);
} catch (ParseException e) {
throw new PlatformDataIntegrityException("error.msg.recurring.rule.parsing.error",
"Error in pasring the Recurring Rule value: " + recurringRule , "recurrence", recurringRule);
}
if(recur == null) return humanReadable;
if(recur.getFrequency().equals(Recur.DAILY)){
if(recur.getInterval() == 1){
humanReadable = "Daily";
}else{
humanReadable = "Every " + recur.getInterval() + " days";
}
}else if(recur.getFrequency().equals(Recur.WEEKLY)){
if(recur.getInterval() == 1 || recur.getInterval() == -1){
humanReadable = "Weekly";
}else{
humanReadable = "Every " + recur.getInterval() + " weeks";
}
humanReadable += " on ";
WeekDayList weekDayList = recur.getDayList();
for (@SuppressWarnings("rawtypes")
Iterator iterator = weekDayList.iterator(); iterator.hasNext();) {
WeekDay weekDay = (WeekDay) iterator.next();
humanReadable += weekDay.getDay();
}
}else if(recur.getFrequency().equals(Recur.MONTHLY)){
if(recur.getInterval() == 1){
humanReadable = "Monthly on day " + startDate.getDayOfMonth();
}else{
humanReadable = "Every " + recur.getInterval() + " months on day " + startDate.getDayOfMonth();
}
}else if(recur.getFrequency().equals(Recur.YEARLY)){
if(recur.getInterval() == 1){
humanReadable = "Annually on " + startDate.toString("MMM") + " " + startDate.getDayOfMonth();
}else{
humanReadable = "Every " + recur.getInterval() + " years on " + startDate.toString("MMM") + " " + startDate.getDayOfMonth();
}
}
if(recur.getCount() > 0){
if(recur.getCount() == 1){
humanReadable = "Once";
}
humanReadable += ", " + recur.getCount() + " times";
}
Date endDate = recur.getUntil();
LocalDate date = new LocalDate(endDate);
DateTimeFormatter fmt = DateTimeFormat.forPattern("dd MMMM YY");
String formattedDate = date.toString( fmt );
if(endDate != null){
humanReadable += ", until " + formattedDate;
}
return humanReadable;
}
}
@@ -483,6 +483,12 @@ public final class LoanApplicationCommandFromApiJsonHelper {
.notExceedingLengthOf(500);
}
final String calendarIdParameterName = "calendarId";
if (fromApiJsonHelper.parameterExists(calendarIdParameterName, element)) {
final Long calendarId = fromApiJsonHelper.extractLongNamed(calendarIdParameterName, element);
baseDataValidator.reset().parameter(calendarIdParameterName).value(calendarId).ignoreIfNull().integerGreaterThanZero();
}
// charges
final String chargesParameterName = "charges";
if (element.isJsonObject() && fromApiJsonHelper.parameterExists(chargesParameterName, element)) {
@@ -11,6 +11,7 @@ import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.codes.domain.CodeValue;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.api.JsonQuery;
@@ -20,6 +21,14 @@ import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityExce
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
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.domain.CalendarRepository;
import org.mifosplatform.portfolio.calendar.exception.CalendarNotFoundException;
import org.mifosplatform.portfolio.calendar.exception.NotValidRecurringDateException;
import org.mifosplatform.portfolio.calendar.service.CalendarHelper;
import org.mifosplatform.portfolio.client.domain.AccountNumberGenerator;
import org.mifosplatform.portfolio.client.domain.AccountNumberGeneratorFactory;
import org.mifosplatform.portfolio.client.domain.Client;
@@ -80,6 +89,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
private final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory;
private final LoanSummaryWrapper loanSummaryWrapper;
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
private final CalendarRepository calendarRepository;
private final CalendarInstanceRepository calendarInstanceRepository;
@Autowired
public LoanApplicationWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final FromJsonHelper fromJsonHelper,
@@ -90,7 +101,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
final NoteRepository noteRepository, final LoanScheduleCalculationPlatformService calculationPlatformService,
final ClientRepository clientRepository, final LoanProductRepository loanProductRepository,
final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory, final LoanSummaryWrapper loanSummaryWrapper,
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory) {
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
final CalendarRepository calendarRepository, final CalendarInstanceRepository calendarInstanceRepository) {
this.context = context;
this.fromJsonHelper = fromJsonHelper;
this.loanApplicationTransitionApiJsonValidator = loanApplicationTransitionApiJsonValidator;
@@ -107,6 +119,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
this.accountIdentifierGeneratorFactory = accountIdentifierGeneratorFactory;
this.loanSummaryWrapper = loanSummaryWrapper;
this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
this.calendarRepository = calendarRepository;
this.calendarInstanceRepository = calendarInstanceRepository;
}
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
@@ -122,6 +136,17 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
this.fromApiJsonDeserializer.validateForCreate(command.json());
//validate dates against calendar recurring dates
//get calendar
final Long calendarId = command.longValueOfParameterNamed("calendarId");
Calendar calendar = null;
if(calendarId != null && calendarId != 0){
calendar = this.calendarRepository.findOne(calendarId);
if(calendar == null) { throw new CalendarNotFoundException(calendarId); }
validateCalendarDates(command, calendar);
}
final Loan newLoanApplication = loanAssembler.assembleFrom(command, currentUser);
this.loanRepository.save(newLoanApplication);
@@ -138,11 +163,11 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
Note note = Note.loanNote(newLoanApplication, submittedOnNote);
this.noteRepository.save(note);
}
//get calendar
final Long calendarId = command.longValueOfParameterNamed("calendarId");
if(calendarId != null && calendarId != 0){
//Save calendar instance
//Save calendar instance
if(calendar != null){
CalendarInstance calendarInstance = new CalendarInstance(calendar, newLoanApplication.getId(), CalendarEntityType.LOANS.getValue());
this.calendarInstanceRepository.save(calendarInstance);
}
return new CommandProcessingResultBuilder() //
@@ -164,6 +189,14 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
this.fromApiJsonDeserializer.validateForModify(command.json());
final Long calendarId = command.longValueOfParameterNamed("calendarId");
Calendar calendar = null;
if(calendarId != null && calendarId != 0){
calendar = this.calendarRepository.findOne(calendarId);
if(calendar == null) { throw new CalendarNotFoundException(calendarId); }
validateCalendarDates(command, calendar);
}
final Loan existingLoanApplication = retrieveLoanBy(loanId);
if (!existingLoanApplication.isSubmittedAndPendingApproval()) { throw new LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeModified(
@@ -254,6 +287,23 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
this.noteRepository.save(note);
}
List<CalendarInstance> ciList = (List<CalendarInstance>) this.calendarInstanceRepository.findByEntityIdAndEntityTypeId(loanId, CalendarEntityType.LOANS.getValue());
if(calendar != null){
//For loans, allow to attach only one calendar instance per loan
if(ciList != null && !ciList.isEmpty()){
CalendarInstance calendarInstance = ciList.get(0);
if(calendarInstance.getCalendar().getId() != calendar.getId()){
calendarInstance.updateCalendar(calendar);
this.calendarInstanceRepository.saveAndFlush(calendarInstance);
}
}
}else if(ciList != null && !ciList.isEmpty()){
CalendarInstance calendarInstance = ciList.get(0);
this.calendarInstanceRepository.delete(calendarInstance);
}
return new CommandProcessingResultBuilder() //
.withEntityId(loanId) //
.withOfficeId(existingLoanApplication.getOfficeId()) //
@@ -454,4 +504,32 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
loan.setHelpers(defaultLoanLifecycleStateMachine(), this.loanSummaryWrapper, this.loanRepaymentScheduleTransactionProcessorFactory);
return loan;
}
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 (!CalendarHelper.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(), edDate)) {
final String errorMessage = "The expected disbursement date :" + (edDate.toString()) + " does not fall on a meeting date.";
throw new NotValidRecurringDateException("loan.expected.disbursement.date", errorMessage, edDate.toString(),
calendar.getTitle());
}
}
final LocalDate repStartingDate = command.localDateValueOfParameterNamed("repaymentsStartingFromDate");
if (repStartingDate != null) {
if (!CalendarHelper.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(), repStartingDate)) {
final String errorMessage = "The First repayment date :" + (repStartingDate.toString()) + " do not fall a meeting date.";
throw new NotValidRecurringDateException("loan.first.repayment.date", errorMessage, repStartingDate.toString(),
calendar.getTitle());
}
}
}
}