Merge pull request #661 from ashok-conflux/MIFOSX-649
added support for capturing calendar history data and generate meeting dates accordingly
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
CREATE TABLE `m_calendar_history` (
|
||||
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
`calendar_id` BIGINT(20) NOT NULL,
|
||||
`title` VARCHAR(50) NOT NULL,
|
||||
`description` VARCHAR(100) NULL DEFAULT NULL,
|
||||
`location` VARCHAR(50) NULL DEFAULT NULL,
|
||||
`start_date` DATE NOT NULL,
|
||||
`end_date` DATE NULL DEFAULT NULL,
|
||||
`duration` SMALLINT(6) NULL DEFAULT NULL,
|
||||
`calendar_type_enum` SMALLINT(5) NOT NULL,
|
||||
`repeating` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
`recurrence` VARCHAR(100) NULL DEFAULT NULL,
|
||||
`remind_by_enum` SMALLINT(5) NULL DEFAULT NULL,
|
||||
`first_reminder` SMALLINT(11) NULL DEFAULT NULL,
|
||||
`second_reminder` SMALLINT(11) NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `FK_m_calendar_m_calendar_history` (`calendar_id`),
|
||||
CONSTRAINT `FK_m_calendar_m_calendar_history` FOREIGN KEY (`calendar_id`) REFERENCES `m_calendar` (`id`)
|
||||
);
|
||||
+1
@@ -10,6 +10,7 @@ import java.util.Set;
|
||||
|
||||
public class CalendarConstants {
|
||||
|
||||
public static final String CALENDAR_RESOURCE_NAME = "calendar";
|
||||
public static enum CALENDAR_SUPPORTED_PARAMETERS {
|
||||
CALENDAR_ID("id"), ENTITY_TYPE("entityType"), ENTITY_ID("entityId"), TITLE("title"), DESCRIPTION("description"), LOCATION(
|
||||
"location"), START_DATE("startDate"), END_DATE("endDate"), CREATED_DATE("createdDate"), DURATION("duration"), TYPE_ID(
|
||||
|
||||
+8
-2
@@ -26,6 +26,7 @@ import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.commands.domain.CommandWrapper;
|
||||
import org.mifosplatform.commands.service.CommandWrapperBuilder;
|
||||
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||
@@ -94,7 +95,12 @@ public class CalendarsApiResource {
|
||||
CalendarData calendarData = this.readPlatformService.retrieveCalendar(calendarId, entityId, entityTypeId);
|
||||
|
||||
// Include recurring date details
|
||||
calendarData = this.readPlatformService.generateRecurringDate(calendarData);
|
||||
final boolean withHistory = true;
|
||||
final LocalDate tillDate = null;
|
||||
final Collection<LocalDate> recurringDates = this.readPlatformService.generateRecurringDates(calendarData, withHistory, tillDate);
|
||||
final Collection<LocalDate> nextTenRecurringDates = this.readPlatformService.generateNextTenRecurringDates(calendarData);
|
||||
final LocalDate recentEligibleMeetingDate = null;
|
||||
calendarData = CalendarData.withRecurringDates(calendarData, recurringDates, nextTenRecurringDates, recentEligibleMeetingDate);
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
if (settings.isTemplate()) {
|
||||
@@ -135,7 +141,7 @@ public class CalendarsApiResource {
|
||||
CalendarEntityType.valueOf(entityType.toUpperCase()).getValue(), calendarTypeOptions));
|
||||
|
||||
// Add recurring dates
|
||||
calendarsData = this.readPlatformService.generateRecurringDates(calendarsData);
|
||||
calendarsData = this.readPlatformService.updateWithRecurringDates(calendarsData);
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.toApiJsonSerializer.serialize(settings, calendarsData, this.RESPONSE_DATA_PARAMETERS);
|
||||
|
||||
+48
-6
@@ -22,6 +22,7 @@ import org.mifosplatform.portfolio.calendar.service.CalendarEnumerations;
|
||||
public class CalendarData {
|
||||
|
||||
private final Long id;
|
||||
private final Long calendarInstanceId;
|
||||
private final Long entityId;
|
||||
private final EnumOptionData entityType;
|
||||
private final String title;
|
||||
@@ -58,7 +59,7 @@ public class CalendarData {
|
||||
final List<EnumOptionData> frequencyOptions;
|
||||
final List<EnumOptionData> repeatsOnDayOptions;
|
||||
|
||||
public static CalendarData instance(final Long id, final Long entityId, final EnumOptionData entityType, final String title,
|
||||
public static CalendarData instance(final Long id, final Long calendarInstanceId, final Long entityId, final EnumOptionData entityType, final String title,
|
||||
final String description, final String location, final LocalDate startDate, final LocalDate endDate, final Integer duration,
|
||||
final EnumOptionData type, final boolean repeating, final String recurrence, final EnumOptionData frequency,
|
||||
final Integer interval, final EnumOptionData repeatsOnDay, final EnumOptionData remindBy, final Integer firstReminder,
|
||||
@@ -75,7 +76,7 @@ public class CalendarData {
|
||||
final List<EnumOptionData> frequencyOptions = null;
|
||||
final List<EnumOptionData> repeatsOnDayOptions = null;
|
||||
|
||||
return new CalendarData(id, entityId, entityType, title, description, location, startDate, endDate, duration, type, repeating,
|
||||
return new CalendarData(id, calendarInstanceId, entityId, entityType, title, description, location, startDate, endDate, duration, type, repeating,
|
||||
recurrence, frequency, interval, repeatsOnDay, remindBy, firstReminder, secondReminder, recurringDates,
|
||||
nextTenRecurringDates, humanReadable, recentEligibleMeetingDate, createdDate, lastUpdatedDate, createdByUserId,
|
||||
createdByUsername, lastUpdatedByUserId, lastUpdatedByUsername, entityTypeOptions, calendarTypeOptions, remindByOptions,
|
||||
@@ -84,7 +85,7 @@ public class CalendarData {
|
||||
|
||||
public static CalendarData withRecurringDates(final CalendarData calendarData, final Collection<LocalDate> recurringDates,
|
||||
final Collection<LocalDate> nextTenRecurringDates, final LocalDate recentEligibleMeetingDate) {
|
||||
return new CalendarData(calendarData.id, calendarData.entityId, calendarData.entityType, calendarData.title,
|
||||
return new CalendarData(calendarData.id, calendarData.calendarInstanceId, calendarData.entityId, calendarData.entityType, calendarData.title,
|
||||
calendarData.description, calendarData.location, calendarData.startDate, calendarData.endDate, calendarData.duration,
|
||||
calendarData.type, calendarData.repeating, calendarData.recurrence, calendarData.frequency, calendarData.interval,
|
||||
calendarData.repeatsOnDay, calendarData.remindBy, calendarData.firstReminder, calendarData.secondReminder, recurringDates,
|
||||
@@ -94,9 +95,22 @@ public class CalendarData {
|
||||
calendarData.calendarTypeOptions, calendarData.remindByOptions, calendarData.frequencyOptions,
|
||||
calendarData.repeatsOnDayOptions);
|
||||
}
|
||||
|
||||
public static CalendarData withRecentEligibleMeetingDate(final CalendarData calendarData, final LocalDate recentEligibleMeetingDate) {
|
||||
return new CalendarData(calendarData.id, calendarData.calendarInstanceId, calendarData.entityId, calendarData.entityType, calendarData.title,
|
||||
calendarData.description, calendarData.location, calendarData.startDate, calendarData.endDate, calendarData.duration,
|
||||
calendarData.type, calendarData.repeating, calendarData.recurrence, calendarData.frequency, calendarData.interval,
|
||||
calendarData.repeatsOnDay, calendarData.remindBy, calendarData.firstReminder, calendarData.secondReminder, calendarData.recurringDates,
|
||||
calendarData.nextTenRecurringDates, calendarData.humanReadable, recentEligibleMeetingDate, calendarData.createdDate,
|
||||
calendarData.lastUpdatedDate, calendarData.createdByUserId, calendarData.createdByUsername,
|
||||
calendarData.lastUpdatedByUserId, calendarData.lastUpdatedByUsername, calendarData.entityTypeOptions,
|
||||
calendarData.calendarTypeOptions, calendarData.remindByOptions, calendarData.frequencyOptions,
|
||||
calendarData.repeatsOnDayOptions);
|
||||
}
|
||||
|
||||
public static CalendarData sensibleDefaultsForNewCalendarCreation() {
|
||||
final Long id = null;
|
||||
final Long calendarInstanceId = null;
|
||||
final Long entityId = null;
|
||||
final EnumOptionData entityType = null;
|
||||
final String title = null;
|
||||
@@ -132,7 +146,7 @@ public class CalendarData {
|
||||
final Long lastUpdatedByUserId = null;
|
||||
final String lastUpdatedByUsername = null;
|
||||
|
||||
return new CalendarData(id, entityId, entityType, title, description, location, startDate, endDate, duration, type, repeating,
|
||||
return new CalendarData(id, calendarInstanceId, entityId, entityType, title, description, location, startDate, endDate, duration, type, repeating,
|
||||
recurrence, frequency, interval, repeatsOnDay, remindBy, firstReminder, secondReminder, recurringDates,
|
||||
nextTenRecurringDates, humanReadable, recentEligibleMeetingDate, createdDate, lastUpdatedDate, createdByUserId,
|
||||
createdByUsername, lastUpdatedByUserId, lastUpdatedByUsername, entityTypeOptions, calendarTypeOptions, remindByOptions,
|
||||
@@ -143,7 +157,7 @@ public class CalendarData {
|
||||
final List<EnumOptionData> calendarTypeOptions, final List<EnumOptionData> remindByOptions,
|
||||
final List<EnumOptionData> repeatsOptions, final List<EnumOptionData> repeatsOnDayOptions) {
|
||||
|
||||
return new CalendarData(calendarData.id, calendarData.entityId, calendarData.entityType, calendarData.title,
|
||||
return new CalendarData(calendarData.id, calendarData.calendarInstanceId, calendarData.entityId, calendarData.entityType, calendarData.title,
|
||||
calendarData.description, calendarData.location, calendarData.startDate, calendarData.endDate, calendarData.duration,
|
||||
calendarData.type, calendarData.repeating, calendarData.recurrence, calendarData.frequency, calendarData.interval,
|
||||
calendarData.repeatsOnDay, calendarData.remindBy, calendarData.firstReminder, calendarData.secondReminder,
|
||||
@@ -153,7 +167,7 @@ public class CalendarData {
|
||||
entityTypeOptions, calendarTypeOptions, remindByOptions, repeatsOptions, repeatsOnDayOptions);
|
||||
}
|
||||
|
||||
private CalendarData(final Long id, final Long entityId, final EnumOptionData entityType, final String title, final String description,
|
||||
private CalendarData(final Long id, final Long calendarInstanceId, final Long entityId, final EnumOptionData entityType, final String title, final String description,
|
||||
final String location, final LocalDate startDate, final LocalDate endDate, final Integer duration, final EnumOptionData type,
|
||||
final boolean repeating, final String recurrence, final EnumOptionData frequency, final Integer interval,
|
||||
final EnumOptionData repeatsOnDay, final EnumOptionData remindBy, final Integer firstReminder, final Integer secondReminder,
|
||||
@@ -164,6 +178,7 @@ public class CalendarData {
|
||||
final List<EnumOptionData> remindByOptions, final List<EnumOptionData> repeatsOptions,
|
||||
final List<EnumOptionData> repeatsOnDayOptions) {
|
||||
this.id = id;
|
||||
this.calendarInstanceId = calendarInstanceId;
|
||||
this.entityId = entityId;
|
||||
this.entityType = entityType;
|
||||
this.title = title;
|
||||
@@ -278,4 +293,31 @@ public class CalendarData {
|
||||
return this.humanReadable;
|
||||
}
|
||||
|
||||
|
||||
public Long getCalendarInstanceId() {
|
||||
return this.calendarInstanceId;
|
||||
}
|
||||
|
||||
public boolean isStartDateBeforeOrEqual(final LocalDate compareDate) {
|
||||
if (this.startDate != null && compareDate != null) {
|
||||
if (this.startDate.isBefore(compareDate) || this.startDate.equals(compareDate)) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isEndDateAfterOrEqual(final LocalDate compareDate) {
|
||||
if (this.endDate != null && compareDate != null) {
|
||||
if (this.endDate.isAfter(compareDate) || this.endDate.isEqual(compareDate)) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isBetweenStartAndEndDate(final LocalDate compareDate){
|
||||
if (isStartDateBeforeOrEqual(compareDate)){
|
||||
if (this.endDate == null || isEndDateAfterOrEqual(compareDate)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+109
-10
@@ -6,12 +6,21 @@
|
||||
|
||||
package org.mifosplatform.portfolio.calendar.domain;
|
||||
|
||||
import static org.mifosplatform.portfolio.calendar.CalendarConstants.CALENDAR_RESOURCE_NAME;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
@@ -19,7 +28,11 @@ import javax.persistence.TemporalType;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.portfolio.calendar.CalendarConstants.CALENDAR_SUPPORTED_PARAMETERS;
|
||||
import org.mifosplatform.portfolio.calendar.exception.CalendarDateException;
|
||||
import org.mifosplatform.portfolio.calendar.exception.CalendarParameterUpdateNotSupportedException;
|
||||
@@ -68,6 +81,10 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
|
||||
@Column(name = "second_reminder", nullable = true)
|
||||
private Integer secondReminder;
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "calendar_id")
|
||||
private Set<CalendarHistory> calendarHistory = new HashSet<CalendarHistory>();
|
||||
|
||||
protected Calendar() {
|
||||
|
||||
}
|
||||
@@ -75,6 +92,17 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
|
||||
public Calendar(final String title, final String description, final String location, final LocalDate startDate,
|
||||
final LocalDate endDate, final Integer duration, final Integer typeId, final boolean repeating, final String recurrence,
|
||||
final Integer remindById, final Integer firstReminder, final Integer secondReminder) {
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(CALENDAR_RESOURCE_NAME);
|
||||
|
||||
final CalendarType calendarType = CalendarType.fromInt(typeId);
|
||||
if (calendarType.isCollection() && !repeating) {
|
||||
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.REPEATING.getValue())
|
||||
.failWithCodeNoParameterAddedToErrorCode("must.repeat.for.collection.calendar");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
this.title = StringUtils.defaultIfEmpty(title, null);
|
||||
this.description = StringUtils.defaultIfEmpty(description, null);
|
||||
this.location = StringUtils.defaultIfEmpty(location, null);
|
||||
@@ -153,17 +181,22 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
final String valueAsInput = command.stringValueOfParameterNamed(startDateParamName);
|
||||
final LocalDate newValue = command.localDateValueOfParameterNamed(startDateParamName);
|
||||
if (isStartDateBefore(newValue)) {
|
||||
final LocalDate currentDate = DateUtils.getLocalDateOfTenant();
|
||||
|
||||
if (newValue.isBefore(currentDate)) {
|
||||
final String defaultUserMessage = "New meeting effective from date cannot be in past";
|
||||
throw new CalendarDateException("new.start.date.cannot.be.in.past", defaultUserMessage, newValue,
|
||||
getStartDateLocalDate());
|
||||
}else if (isStartDateAfter(newValue) && isStartDateBeforeOrEqual(currentDate)) {
|
||||
//new meeting date should be on or after start date or current date
|
||||
final String defaultUserMessage = "New meeting effective from date cannot be a date before existing meeting start date";
|
||||
throw new CalendarDateException("new.start.date.before.existing.date", defaultUserMessage, newValue,
|
||||
getStartDateLocalDate());
|
||||
} else {
|
||||
actualChanges.put(startDateParamName, valueAsInput);
|
||||
actualChanges.put("dateFormat", dateFormatAsInput);
|
||||
actualChanges.put("locale", localeAsInput);
|
||||
this.startDate = newValue.toDate();
|
||||
} else {
|
||||
// new meeting start date should be greater than existing
|
||||
// meeting start date
|
||||
final String defaultUserMessage = "New meeting start on or after date cannot be a date before existing meeting start date";
|
||||
throw new CalendarDateException("new.start.date.before.existing.date", defaultUserMessage, newValue,
|
||||
getStartDateLocalDate());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,8 +244,21 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
|
||||
this.repeating = newValue;
|
||||
}
|
||||
|
||||
//if repeating is false then update recurrence to NULL
|
||||
if(!this.repeating) this.recurrence = null;
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(CALENDAR_RESOURCE_NAME);
|
||||
|
||||
final CalendarType calendarType = CalendarType.fromInt(this.typeId);
|
||||
if (calendarType.isCollection() && !this.repeating) {
|
||||
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.REPEATING.getValue())
|
||||
.failWithCodeNoParameterAddedToErrorCode("must.repeat.for.collection.calendar");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
final String newRecurrence = Calendar.constructRecurrence(command, this);
|
||||
if (this.recurrence != null && !newRecurrence.equalsIgnoreCase(this.recurrence)) {
|
||||
if (!StringUtils.isBlank(this.recurrence) && !newRecurrence.equalsIgnoreCase(this.recurrence)) {
|
||||
|
||||
// FIXME: AA - Is this restriction required only for collection type
|
||||
// meetings or for all?.
|
||||
@@ -319,9 +365,48 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
|
||||
}
|
||||
return endDateLocalDate;
|
||||
}
|
||||
|
||||
public Set<CalendarHistory> history() {
|
||||
return this.calendarHistory;
|
||||
}
|
||||
|
||||
public boolean isStartDateBefore(final LocalDate newStartDate) {
|
||||
if (this.startDate != null && newStartDate != null && getStartDateLocalDate().isBefore(newStartDate)) { return true; }
|
||||
public boolean isStartDateBefore(final LocalDate compareDate) {
|
||||
if (this.startDate != null && compareDate != null && getStartDateLocalDate().isBefore(compareDate)) { return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isStartDateBeforeOrEqual(final LocalDate compareDate) {
|
||||
if (this.startDate != null && compareDate != null) {
|
||||
if (getStartDateLocalDate().isBefore(compareDate) || getStartDateLocalDate().equals(compareDate)) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isStartDateAfter(final LocalDate compareDate) {
|
||||
if (this.startDate != null && compareDate != null && getStartDateLocalDate().isAfter(compareDate)) { return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isStartDateAfterOrEqual(final LocalDate compareDate) {
|
||||
if (this.startDate != null && compareDate != null) {
|
||||
if (getStartDateLocalDate().isAfter(compareDate) || getStartDateLocalDate().isEqual(compareDate)) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isEndDateAfterOrEqual(final LocalDate compareDate) {
|
||||
if (this.endDate != null && compareDate != null) {
|
||||
if (getEndDateLocalDate().isAfter(compareDate) || getEndDateLocalDate().isEqual(compareDate)) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isBetweenStartAndEndDate(final LocalDate compareDate){
|
||||
if (isStartDateBeforeOrEqual(compareDate)){
|
||||
if (getEndDateLocalDate() == null || isEndDateAfterOrEqual(compareDate)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -358,4 +443,18 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public boolean isValidRecurringDate(final LocalDate compareDate) {
|
||||
|
||||
if (isBetweenStartAndEndDate(compareDate)) { return CalendarUtils.isValidRedurringDate(getRecurrence(), getStartDateLocalDate(),
|
||||
compareDate); }
|
||||
|
||||
// validate with history details.
|
||||
for (CalendarHistory history : history()) {
|
||||
if (history.isBetweenStartAndEndDate(compareDate)) { return CalendarUtils.isValidRedurringDate(history.getRecurrence(),
|
||||
history.getStartDateLocalDate(), compareDate); }
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_calendar_history")
|
||||
public class CalendarHistory extends AbstractPersistable<Long>{
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "calendar_id", referencedColumnName = "id", nullable = false)
|
||||
private Calendar calendar;
|
||||
|
||||
@Column(name = "title", length = 50, nullable = false)
|
||||
private String title;
|
||||
|
||||
@Column(name = "description", length = 100, nullable = true)
|
||||
private String description;
|
||||
|
||||
@Column(name = "location", length = 100, nullable = true)
|
||||
private String location;
|
||||
|
||||
@Column(name = "start_date", nullable = false)
|
||||
@Temporal(TemporalType.DATE)
|
||||
private Date startDate;
|
||||
|
||||
@Column(name = "end_date", nullable = true)
|
||||
@Temporal(TemporalType.DATE)
|
||||
private Date endDate;
|
||||
|
||||
@Column(name = "duration", nullable = true)
|
||||
private Integer duration;
|
||||
|
||||
@Column(name = "calendar_type_enum", nullable = false)
|
||||
private Integer typeId;
|
||||
|
||||
@Column(name = "repeating", nullable = false)
|
||||
private boolean repeating = false;
|
||||
|
||||
@Column(name = "recurrence", length = 100, nullable = true)
|
||||
private String recurrence;
|
||||
|
||||
@Column(name = "remind_by_enum", nullable = true)
|
||||
private Integer remindById;
|
||||
|
||||
@Column(name = "first_reminder", nullable = true)
|
||||
private Integer firstReminder;
|
||||
|
||||
@Column(name = "second_reminder", nullable = true)
|
||||
private Integer secondReminder;
|
||||
|
||||
protected CalendarHistory() {
|
||||
|
||||
}
|
||||
|
||||
public CalendarHistory(Calendar calendar, Date startDate) {
|
||||
this.calendar = calendar;
|
||||
this.title = calendar.getTitle();
|
||||
this.description = calendar.getDescription();
|
||||
this.location = calendar.getLocation();
|
||||
this.startDate = startDate;
|
||||
this.endDate = calendar.getStartDate();//Calendar start date become end date for history data.
|
||||
this.duration = calendar.getDuration();
|
||||
this.typeId = calendar.getTypeId();
|
||||
this.repeating = calendar.isRepeating();
|
||||
this.recurrence = calendar.getRecurrence();
|
||||
this.remindById = calendar.getRemindById();
|
||||
this.firstReminder = calendar.getFirstReminder();
|
||||
this.secondReminder = calendar.getSecondReminder();
|
||||
}
|
||||
|
||||
public String getRecurrence() {
|
||||
return this.recurrence;
|
||||
}
|
||||
|
||||
public LocalDate getStartDateLocalDate() {
|
||||
LocalDate startDateLocalDate = null;
|
||||
if (this.startDate != null) {
|
||||
startDateLocalDate = LocalDate.fromDateFields(this.startDate);
|
||||
}
|
||||
return startDateLocalDate;
|
||||
}
|
||||
|
||||
public LocalDate getEndDateLocalDate() {
|
||||
LocalDate endDateLocalDate = null;
|
||||
if (this.endDate != null) {
|
||||
endDateLocalDate = LocalDate.fromDateFields(this.endDate);
|
||||
}
|
||||
return endDateLocalDate;
|
||||
}
|
||||
|
||||
public boolean isEndDateAfterOrEqual(final LocalDate compareDate) {
|
||||
if (this.endDate != null && compareDate != null) {
|
||||
if (getEndDateLocalDate().isAfter(compareDate) || getEndDateLocalDate().isEqual(compareDate)) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isStartDateBeforeOrEqual(final LocalDate compareDate) {
|
||||
if (this.startDate != null && compareDate != null) {
|
||||
if (getStartDateLocalDate().isBefore(compareDate) || getStartDateLocalDate().equals(compareDate)) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isBetweenStartAndEndDate(final LocalDate compareDate){
|
||||
if (isStartDateBeforeOrEqual(compareDate)){
|
||||
if (getEndDateLocalDate() == null || isEndDateAfterOrEqual(compareDate)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void updateEndDate(Date historyCalEndDate){
|
||||
this.endDate = historyCalEndDate;
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
|
||||
public interface CalendarHistoryRepository extends JpaRepository<CalendarHistory, Long>, JpaSpecificationExecutor<CalendarHistory> {
|
||||
|
||||
}
|
||||
+4
@@ -66,4 +66,8 @@ public enum CalendarType {
|
||||
public String toString() {
|
||||
return name().toString();
|
||||
}
|
||||
|
||||
public boolean isCollection(){
|
||||
return this.value.equals(CalendarType.COLLECTION.value);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-3
@@ -10,6 +10,7 @@ import java.util.List;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.portfolio.calendar.data.CalendarData;
|
||||
import org.mifosplatform.portfolio.meeting.data.MeetingData;
|
||||
|
||||
public interface CalendarReadPlatformService {
|
||||
|
||||
@@ -24,14 +25,16 @@ public interface CalendarReadPlatformService {
|
||||
|
||||
CalendarData retrieveNewCalendarDetails();
|
||||
|
||||
CalendarData generateRecurringDate(final CalendarData calendarData);
|
||||
Collection<LocalDate> generateRecurringDates(final CalendarData calendarData, final boolean withHistory, final LocalDate tillDate);
|
||||
|
||||
CalendarData generateRecurringDate(final CalendarData calendarData, final LocalDate tillDate);
|
||||
Collection<LocalDate> generateNextTenRecurringDates(final CalendarData calendarData);
|
||||
|
||||
Collection<CalendarData> generateRecurringDates(final Collection<CalendarData> calendarsData);
|
||||
Collection<CalendarData> updateWithRecurringDates(final Collection<CalendarData> calendarsData);
|
||||
|
||||
CalendarData retrieveLoanCalendar(final Long loanId);
|
||||
|
||||
CalendarData retrieveCollctionCalendarByEntity(final Long entityId, final Integer entityTypeId);
|
||||
|
||||
LocalDate generateNextEligibleMeetingDateForCollection(CalendarData calendarData, MeetingData lastMeetingData);
|
||||
|
||||
}
|
||||
|
||||
+200
-28
@@ -20,6 +20,7 @@ import org.mifosplatform.portfolio.calendar.data.CalendarData;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarType;
|
||||
import org.mifosplatform.portfolio.calendar.exception.CalendarNotFoundException;
|
||||
import org.mifosplatform.portfolio.meeting.data.MeetingData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
@@ -40,7 +41,7 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
|
||||
private static final class CalendarDataMapper implements RowMapper<CalendarData> {
|
||||
|
||||
public String schema() {
|
||||
return " select c.id as id, ci.entity_id as entityId, ci.entity_type_enum as entityTypeId, c.title as title, "
|
||||
return " select c.id as id, ci.id as calendarInstanceId, ci.entity_id as entityId, ci.entity_type_enum as entityTypeId, c.title as title, "
|
||||
+ " c.description as description, c.location as location, c.start_date as startDate, c.end_date as endDate, "
|
||||
+ " c.duration as duration, c.calendar_type_enum as typeId, c.repeating as repeating, "
|
||||
+ " c.recurrence as recurrence, c.remind_by_enum as remindById, c.first_reminder as firstReminder, c.second_reminder as secondReminder, "
|
||||
@@ -54,6 +55,7 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
|
||||
public CalendarData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||
|
||||
final Long id = rs.getLong("id");
|
||||
final Long calendarInstanceId = rs.getLong("calendarInstanceId");
|
||||
final Long entityId = rs.getLong("entityId");
|
||||
final Integer entityTypeId = rs.getInt("entityTypeId");
|
||||
final EnumOptionData entityType = CalendarEnumerations.calendarEntityType(entityTypeId);
|
||||
@@ -89,9 +91,10 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
|
||||
final Long lastUpdatedByUserId = rs.getLong("updatingUserId");
|
||||
final String lastUpdatedByUserName = rs.getString("updatingUserName");
|
||||
|
||||
return CalendarData.instance(id, entityId, entityType, title, description, location, startDate, endDate, duration, type,
|
||||
repeating, recurrence, frequency, interval, repeatsOnDay, remindBy, firstReminder, secondReminder, humanReadable, createdDate,
|
||||
lastUpdatedDate, createdByUserId, createdByUserName, lastUpdatedByUserId, lastUpdatedByUserName);
|
||||
return CalendarData.instance(id, calendarInstanceId, entityId, entityType, title, description, location, startDate, endDate,
|
||||
duration, type, repeating, recurrence, frequency, interval, repeatsOnDay, remindBy, firstReminder, secondReminder,
|
||||
humanReadable, createdDate, lastUpdatedDate, createdByUserId, createdByUserName, lastUpdatedByUserId,
|
||||
lastUpdatedByUserName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,49 +187,139 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
|
||||
}
|
||||
|
||||
@Override
|
||||
public CalendarData generateRecurringDate(final CalendarData calendarData) {
|
||||
return generateRecurringDate(calendarData, null);
|
||||
public Collection<LocalDate> generateRecurringDates(final CalendarData calendarData, final boolean withHistory, final LocalDate tillDate) {
|
||||
final LocalDate fromDate = null;
|
||||
Collection<LocalDate> recurringDates = generateRecurringDate(calendarData, fromDate, tillDate, -1);
|
||||
|
||||
if (withHistory) {
|
||||
final Collection<CalendarData> calendarHistorys = this.retrieveCalendarsFromHistory(calendarData.getId());
|
||||
for (CalendarData calendarHistory : calendarHistorys) {
|
||||
recurringDates.addAll(generateRecurringDate(calendarHistory, fromDate, tillDate, -1));
|
||||
}
|
||||
}
|
||||
|
||||
return recurringDates;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CalendarData generateRecurringDate(final CalendarData calendarData, final LocalDate tillDate) {
|
||||
if (!calendarData.isRepeating()) { return calendarData; }
|
||||
public Collection<LocalDate> generateNextTenRecurringDates(CalendarData calendarData) {
|
||||
final LocalDate tillDate = null;
|
||||
return generateRecurringDate(calendarData, DateUtils.getLocalDateOfTenant(), tillDate, 10);
|
||||
}
|
||||
|
||||
private Collection<LocalDate> generateRecurringDate(final CalendarData calendarData, final LocalDate fromDate, final LocalDate tillDate, final int maxCount) {
|
||||
|
||||
if (!calendarData.isRepeating()) { return null; }
|
||||
final String rrule = calendarData.getRecurrence();
|
||||
final LocalDate currentDate = DateUtils.getLocalDateOfTenant();
|
||||
final LocalDate seedDate = calendarData.getStartDate();
|
||||
LocalDate endDate = calendarData.getEndDate();
|
||||
LocalDate startDate = calendarData.getStartDate();
|
||||
if (seedDate.isBefore(currentDate.minusYears(1))) {
|
||||
startDate = currentDate.minusYears(1);
|
||||
/**
|
||||
* Start date or effective from date of calendar recurrence.
|
||||
*/
|
||||
final LocalDate seedDate = this.getSeedDate(calendarData.getStartDate());
|
||||
/**
|
||||
* periodStartDate date onwards recurring dates will be generated.
|
||||
*/
|
||||
final LocalDate periodStartDate = this.getPeriodStartDate(seedDate, calendarData.getStartDate(), fromDate);
|
||||
/**
|
||||
* till periodEndDate recurring dates will be generated.
|
||||
*/
|
||||
final LocalDate periodEndDate = this.getPeriodEndDate(calendarData.getEndDate(), tillDate);
|
||||
|
||||
final Collection<LocalDate> recurringDates = CalendarUtils.getRecurringDates(rrule, seedDate, periodStartDate, periodEndDate,
|
||||
maxCount);
|
||||
return recurringDates;
|
||||
}
|
||||
|
||||
private LocalDate getSeedDate(LocalDate date) {
|
||||
return date;
|
||||
}
|
||||
|
||||
private LocalDate getPeriodStartDate(final LocalDate seedDate, final LocalDate recurrenceStartDate, final LocalDate fromDate) {
|
||||
LocalDate periodStartDate = null;
|
||||
if(fromDate != null) {
|
||||
periodStartDate = fromDate;
|
||||
}else {
|
||||
final LocalDate currentDate = DateUtils.getLocalDateOfTenant();
|
||||
if (seedDate.isBefore(currentDate.minusYears(1))) {
|
||||
periodStartDate = currentDate.minusYears(1);
|
||||
}else{
|
||||
periodStartDate = recurrenceStartDate;
|
||||
}
|
||||
}
|
||||
return periodStartDate;
|
||||
}
|
||||
|
||||
private LocalDate getPeriodEndDate(LocalDate endDate, LocalDate tillDate) {
|
||||
LocalDate periodEndDate = endDate;
|
||||
final LocalDate currentDate = DateUtils.getLocalDateOfTenant();
|
||||
|
||||
if (tillDate != null) {
|
||||
if (endDate != null) {
|
||||
if (endDate.isAfter(tillDate)) {
|
||||
endDate = tillDate;// to retrieve meeting dates till
|
||||
// specified date (tillDate)
|
||||
// to retrieve meeting dates tillspecified date (tillDate)
|
||||
periodEndDate = tillDate;
|
||||
}
|
||||
} else {
|
||||
endDate = tillDate;// end date is null then fetch meeting dates
|
||||
// tillDate
|
||||
// end date is null then fetch meeting dates tillDate
|
||||
periodEndDate = tillDate;
|
||||
}
|
||||
} else if (endDate == null || endDate.isAfter(currentDate.plusYears(1))) {
|
||||
endDate = currentDate.plusYears(1);
|
||||
periodEndDate = currentDate.plusYears(1);
|
||||
}
|
||||
|
||||
final Collection<LocalDate> recurringDates = CalendarUtils.getRecurringDates(rrule, seedDate, startDate, endDate, -1);
|
||||
final Collection<LocalDate> nextTenRecurringDates = CalendarUtils.getRecurringDates(rrule, seedDate, endDate);
|
||||
final LocalDate recentEligibleMeetingDate = CalendarUtils.getRecentEligibleMeetingDate(rrule, seedDate);
|
||||
return CalendarData.withRecurringDates(calendarData, recurringDates, nextTenRecurringDates, recentEligibleMeetingDate);
|
||||
|
||||
return periodEndDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<CalendarData> generateRecurringDates(final Collection<CalendarData> calendarsData) {
|
||||
final Collection<CalendarData> recuCalendarsData = new ArrayList<CalendarData>();
|
||||
public LocalDate generateNextEligibleMeetingDateForCollection(final CalendarData calendarData, final MeetingData lastMeetingData) {
|
||||
|
||||
final LocalDate lastMeetingDate = (lastMeetingData == null) ? null : lastMeetingData.getMeetingDate();
|
||||
// get applicable calendar based on meeting date
|
||||
CalendarData applicableCalendarData = calendarData;
|
||||
LocalDate nextEligibleMeetingDate = null;
|
||||
/**
|
||||
* The next available meeting date for collection should be taken from
|
||||
* application calendar for that time period. e.g. If the previous
|
||||
* calendar details has weekly meeting starting from 1st of Oct 2013 on
|
||||
* every Tuesday, then meeting dates for collection are 1,8,15,22,29..
|
||||
*
|
||||
* If meeting schedule has changed from Tuesday to Friday with effective
|
||||
* from 15th of Oct (calendar update has made on 2nd of Oct) , then
|
||||
* application should allow to generate collection sheet on 8th of Oct
|
||||
* which is still on Tuesday and next collection sheet date should be on
|
||||
* 18th of Oct as per current calendar
|
||||
*/
|
||||
if (lastMeetingDate != null && !calendarData.isBetweenStartAndEndDate(lastMeetingDate)
|
||||
&& !calendarData.isBetweenStartAndEndDate(DateUtils.getLocalDateOfTenant())) {
|
||||
applicableCalendarData = this.retrieveApplicableCalendarFromHistory(calendarData.getId(), lastMeetingDate);
|
||||
nextEligibleMeetingDate = CalendarUtils.getRecentEligibleMeetingDate(applicableCalendarData.getRecurrence(), lastMeetingDate);
|
||||
}
|
||||
|
||||
/**
|
||||
* If nextEligibleMeetingDate is on or after current calendar startdate
|
||||
* then regenerate the nextEligible meeting date based on
|
||||
*/
|
||||
if (nextEligibleMeetingDate == null) {
|
||||
final LocalDate seedDate = (lastMeetingDate != null) ? lastMeetingDate : calendarData.getStartDate();
|
||||
nextEligibleMeetingDate = CalendarUtils.getRecentEligibleMeetingDate(applicableCalendarData.getRecurrence(), seedDate);
|
||||
} else if (calendarData.isBetweenStartAndEndDate(nextEligibleMeetingDate)) {
|
||||
nextEligibleMeetingDate = CalendarUtils.getRecentEligibleMeetingDate(applicableCalendarData.getRecurrence(),
|
||||
calendarData.getStartDate());
|
||||
}
|
||||
|
||||
return nextEligibleMeetingDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<CalendarData> updateWithRecurringDates(final Collection<CalendarData> calendarsData) {
|
||||
final Collection<CalendarData> recuCalendarsData = new ArrayList<CalendarData>();
|
||||
final boolean withHistory = true;
|
||||
final LocalDate tillDate = null;
|
||||
for (final CalendarData calendarData : calendarsData) {
|
||||
recuCalendarsData.add(generateRecurringDate(calendarData));
|
||||
final Collection<LocalDate> recurringDates = this.generateRecurringDates(calendarData, withHistory, tillDate);
|
||||
final Collection<LocalDate> nextTenRecurringDates = this.generateNextTenRecurringDates(calendarData);
|
||||
final LocalDate recentEligibleMeetingDate = null;
|
||||
final CalendarData updatedCalendarData = CalendarData.withRecurringDates(calendarData, recurringDates, nextTenRecurringDates,
|
||||
recentEligibleMeetingDate);
|
||||
recuCalendarsData.add(updatedCalendarData);
|
||||
}
|
||||
|
||||
return recuCalendarsData;
|
||||
@@ -279,4 +372,83 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
|
||||
return conditionSql;
|
||||
}
|
||||
|
||||
private CalendarData retrieveApplicableCalendarFromHistory(Long calendarId, LocalDate compareDate) {
|
||||
try {
|
||||
final CalendarDataFromHistoryMapper rm = new CalendarDataFromHistoryMapper();
|
||||
|
||||
final String sql = rm.schema() + " where c.calendar_id = ? and date(?) between c.start_date and c.end_date limit 1";
|
||||
|
||||
return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { calendarId, compareDate.toDate() });
|
||||
} catch (final EmptyResultDataAccessException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<CalendarData> retrieveCalendarsFromHistory(Long calendarId) {
|
||||
try {
|
||||
final CalendarDataFromHistoryMapper rm = new CalendarDataFromHistoryMapper();
|
||||
|
||||
final String sql = rm.schema() + " where c.calendar_id = ? ";
|
||||
|
||||
final Collection<CalendarData> calendars = this.jdbcTemplate.query(sql, rm, new Object[] { calendarId });
|
||||
return calendars;
|
||||
} catch (final EmptyResultDataAccessException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class CalendarDataFromHistoryMapper implements RowMapper<CalendarData> {
|
||||
|
||||
public String schema() {
|
||||
return " select c.calendar_id as id, c.title as title, c.description as description, c.location as location, c.start_date as startDate, "
|
||||
+ " c.end_date as endDate, c.duration as duration, c.calendar_type_enum as typeId, c.repeating as repeating, "
|
||||
+ " c.recurrence as recurrence, c.remind_by_enum as remindById, c.first_reminder as firstReminder, c.second_reminder as secondReminder "
|
||||
+ " from m_calendar_history c ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CalendarData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||
|
||||
final Long id = rs.getLong("id");
|
||||
final Long calendarInstanceId = null;
|
||||
final Long entityId = null;
|
||||
final EnumOptionData entityType = null;
|
||||
final String title = rs.getString("title");
|
||||
final String description = rs.getString("description");
|
||||
final String location = rs.getString("location");
|
||||
final LocalDate startDate = JdbcSupport.getLocalDate(rs, "startDate");
|
||||
final LocalDate endDate = JdbcSupport.getLocalDate(rs, "endDate");
|
||||
final Integer duration = rs.getInt("duration");
|
||||
final Integer typeId = rs.getInt("typeId");
|
||||
final EnumOptionData type = CalendarEnumerations.calendarType(typeId);
|
||||
final boolean repeating = rs.getBoolean("repeating");
|
||||
final String recurrence = rs.getString("recurrence");
|
||||
final EnumOptionData frequency = CalendarEnumerations.calendarFrequencyType(CalendarUtils.getFrequency(recurrence));
|
||||
final Integer interval = new Integer(CalendarUtils.getInterval(recurrence));
|
||||
final EnumOptionData repeatsOnDay = CalendarEnumerations.calendarWeekDaysType(CalendarUtils.getRepeatsOnDay(recurrence));
|
||||
final Integer remindById = rs.getInt("remindById");
|
||||
EnumOptionData remindBy = null;
|
||||
if (remindById != null && remindById != 0) {
|
||||
remindBy = CalendarEnumerations.calendarRemindBy(remindById);
|
||||
}
|
||||
final Integer firstReminder = rs.getInt("firstReminder");
|
||||
final Integer secondReminder = rs.getInt("secondReminder");
|
||||
String humanReadable = null;
|
||||
if (startDate != null && recurrence != null) {
|
||||
humanReadable = CalendarUtils.getRRuleReadable(startDate, recurrence);
|
||||
}
|
||||
|
||||
final LocalDate createdDate = null;
|
||||
final LocalDate lastUpdatedDate = null;
|
||||
final Long createdByUserId = null;
|
||||
final String createdByUserName = null;
|
||||
final Long lastUpdatedByUserId = null;
|
||||
final String lastUpdatedByUserName = null;
|
||||
|
||||
return CalendarData.instance(id, calendarInstanceId, entityId, entityType, title, description, location, startDate, endDate,
|
||||
duration, type, repeating, recurrence, frequency, interval, repeatsOnDay, remindBy, firstReminder, secondReminder,
|
||||
humanReadable, createdDate, lastUpdatedDate, createdByUserId, createdByUserName, lastUpdatedByUserId,
|
||||
lastUpdatedByUserName);
|
||||
}
|
||||
}
|
||||
}
|
||||
+69
-42
@@ -7,6 +7,7 @@ package org.mifosplatform.portfolio.calendar.service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -20,18 +21,22 @@ import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.portfolio.calendar.CalendarConstants.CALENDAR_SUPPORTED_PARAMETERS;
|
||||
import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarHistory;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarHistoryRepository;
|
||||
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.domain.CalendarType;
|
||||
import org.mifosplatform.portfolio.calendar.exception.CalendarNotFoundException;
|
||||
import org.mifosplatform.portfolio.calendar.serialization.CalendarCommandFromApiJsonDeserializer;
|
||||
import org.mifosplatform.portfolio.client.domain.Client;
|
||||
import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper;
|
||||
import org.mifosplatform.portfolio.group.domain.Group;
|
||||
import org.mifosplatform.portfolio.group.domain.GroupRepository;
|
||||
import org.mifosplatform.portfolio.group.domain.GroupRepositoryWrapper;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
|
||||
import org.mifosplatform.portfolio.loanaccount.service.LoanWritePlatformService;
|
||||
@@ -43,21 +48,24 @@ import org.springframework.util.CollectionUtils;
|
||||
public class CalendarWritePlatformServiceJpaRepositoryImpl implements CalendarWritePlatformService {
|
||||
|
||||
private final CalendarRepository calendarRepository;
|
||||
private final CalendarHistoryRepository calendarHistoryRepository;
|
||||
private final CalendarCommandFromApiJsonDeserializer fromApiJsonDeserializer;
|
||||
private final CalendarInstanceRepository calendarInstanceRepository;
|
||||
private final LoanWritePlatformService loanWritePlatformService;
|
||||
private final ConfigurationDomainService configurationDomainService;
|
||||
private final GroupRepository groupRepository;
|
||||
private final GroupRepositoryWrapper groupRepository;
|
||||
private final LoanRepository loanRepository;
|
||||
private final ClientRepositoryWrapper clientRepository;
|
||||
|
||||
@Autowired
|
||||
public CalendarWritePlatformServiceJpaRepositoryImpl(final CalendarRepository calendarRepository,
|
||||
final CalendarHistoryRepository calendarHistoryRepository,
|
||||
final CalendarCommandFromApiJsonDeserializer fromApiJsonDeserializer,
|
||||
final CalendarInstanceRepository calendarInstanceRepository, final LoanWritePlatformService loanWritePlatformService,
|
||||
final ConfigurationDomainService configurationDomainService, final GroupRepository groupRepository,
|
||||
final ConfigurationDomainService configurationDomainService, final GroupRepositoryWrapper groupRepository,
|
||||
final LoanRepository loanRepository, final ClientRepositoryWrapper clientRepository) {
|
||||
this.calendarRepository = calendarRepository;
|
||||
this.calendarHistoryRepository = calendarHistoryRepository;
|
||||
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
||||
this.calendarInstanceRepository = calendarInstanceRepository;
|
||||
this.loanWritePlatformService = loanWritePlatformService;
|
||||
@@ -71,25 +79,58 @@ public class CalendarWritePlatformServiceJpaRepositoryImpl implements CalendarWr
|
||||
public CommandProcessingResult createCalendar(final JsonCommand command) {
|
||||
|
||||
this.fromApiJsonDeserializer.validateForCreate(command.json());
|
||||
|
||||
final LocalDate entityActivationDate = getEntityActivationDate(command);
|
||||
final Long entityId = command.getSupportedEntityId();
|
||||
final CalendarEntityType entityType = CalendarEntityType.valueOf(command.getSupportedEntityType().toUpperCase());
|
||||
|
||||
LocalDate entityActivationDate = null;
|
||||
Group centerOrGroup = null;
|
||||
if (entityType.isCenter() || entityType.isGroup()) {
|
||||
centerOrGroup = this.groupRepository.findOneWithNotFoundDetection(entityId);
|
||||
entityActivationDate = centerOrGroup.getActivationLocalDate();
|
||||
} else if (entityType.isLoan()) {
|
||||
final Loan loan = this.loanRepository.findOne(entityId);
|
||||
entityActivationDate = (loan.getApprovedOnDate() == null) ? loan.getSubmittedOnDate() : loan.getApprovedOnDate();
|
||||
} else if (entityType.isLoan()) {
|
||||
final Client client = this.clientRepository.findOneWithNotFoundDetection(entityId);
|
||||
entityActivationDate = client.getActivationLocalDate();
|
||||
}
|
||||
|
||||
final Calendar newCalendar = Calendar.fromJson(command);
|
||||
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource("calendar");
|
||||
if(entityActivationDate == null || newCalendar.getStartDateLocalDate().isBefore(entityActivationDate)){
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("calendar");
|
||||
if (entityActivationDate == null || newCalendar.getStartDateLocalDate().isBefore(entityActivationDate)) {
|
||||
final DateTimeFormatter formatter = DateTimeFormat.forPattern(command.dateFormat()).withLocale(command.extractLocale());
|
||||
String dateAsString = "";
|
||||
if(entityActivationDate != null) dateAsString = formatter.print(entityActivationDate);
|
||||
|
||||
if (entityActivationDate != null) dateAsString = formatter.print(entityActivationDate);
|
||||
|
||||
final String errorMessage = "cannot.be.before." + entityType.name().toLowerCase() + ".activation.date";
|
||||
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.START_DATE.getValue()).value(dateAsString)
|
||||
.failWithCodeNoParameterAddedToErrorCode(errorMessage);
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
if (entityType.isCenter() || entityType.isGroup()) {
|
||||
Long centerOrGroupId = entityId;
|
||||
Integer centerOrGroupEntityTypeId = entityType.getValue();
|
||||
|
||||
if (entityType.isGroup()) {
|
||||
@SuppressWarnings("null")
|
||||
final Group parent = centerOrGroup.getParent();
|
||||
if (parent != null) {
|
||||
centerOrGroupId = parent.getId();
|
||||
centerOrGroupEntityTypeId = CalendarEntityType.CENTERS.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
final CalendarInstance collectionCalendarInstance = this.calendarInstanceRepository
|
||||
.findByEntityIdAndEntityTypeIdAndCalendarTypeId(centerOrGroupId, centerOrGroupEntityTypeId,
|
||||
CalendarType.COLLECTION.getValue());
|
||||
if (collectionCalendarInstance != null) {
|
||||
final String errorMessage = "multiple.collection.calendar.not.supported";
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
|
||||
this.calendarRepository.save(newCalendar);
|
||||
|
||||
@@ -103,25 +144,6 @@ public class CalendarWritePlatformServiceJpaRepositoryImpl implements CalendarWr
|
||||
|
||||
}
|
||||
|
||||
private LocalDate getEntityActivationDate(JsonCommand command) {
|
||||
final Long entityId = command.getSupportedEntityId();
|
||||
final CalendarEntityType entityType = CalendarEntityType.valueOf(command.getSupportedEntityType().toUpperCase());
|
||||
LocalDate entityActivationDate = null;
|
||||
|
||||
if(entityType.isCenter() || entityType.isGroup()){
|
||||
final Group centerOrGroup = this.groupRepository.findOne(entityId);
|
||||
entityActivationDate = centerOrGroup.getActivationLocalDate();
|
||||
} else if (entityType.isLoan()){
|
||||
final Loan loan = this.loanRepository.findOne(entityId);
|
||||
entityActivationDate = (loan.getApprovedOnDate() == null) ? loan.getSubmittedOnDate() : loan.getApprovedOnDate();
|
||||
} else if (entityType.isLoan()){
|
||||
final Client client = this.clientRepository.findOneWithNotFoundDetection(entityId);
|
||||
entityActivationDate = client.getActivationLocalDate();
|
||||
}
|
||||
|
||||
return entityActivationDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult updateCalendar(final JsonCommand command) {
|
||||
|
||||
@@ -130,25 +152,30 @@ public class CalendarWritePlatformServiceJpaRepositoryImpl implements CalendarWr
|
||||
final Long calendarId = command.entityId();
|
||||
final Calendar calendarForUpdate = this.calendarRepository.findOne(calendarId);
|
||||
if (calendarForUpdate == null) { throw new CalendarNotFoundException(calendarId); }
|
||||
|
||||
final Date oldStartDate = calendarForUpdate.getStartDate();
|
||||
final LocalDate currentDate = DateUtils.getLocalDateOfTenant();
|
||||
//create calendar history before updating calendar
|
||||
final CalendarHistory calendarHistory = new CalendarHistory(calendarForUpdate, oldStartDate);
|
||||
final Map<String, Object> changes = calendarForUpdate.update(command);
|
||||
|
||||
|
||||
if (!changes.isEmpty()) {
|
||||
//update calendar history table only if there is a change in calendar start date.
|
||||
if(currentDate.isAfter(new LocalDate(oldStartDate))){
|
||||
final Date endDate = calendarForUpdate.getStartDateLocalDate().minusDays(1).toDate();
|
||||
calendarHistory.updateEndDate(endDate);
|
||||
this.calendarHistoryRepository.save(calendarHistory);
|
||||
}
|
||||
|
||||
this.calendarRepository.saveAndFlush(calendarForUpdate);
|
||||
|
||||
if (this.configurationDomainService.isRescheduleFutureRepaymentsEnabled()) {
|
||||
// In this approach loans following this meeting calendar will
|
||||
// be affected immediately.
|
||||
// get all calendar instances following this meeting calendar
|
||||
// and calendar entity type is loan
|
||||
if (this.configurationDomainService.isRescheduleFutureRepaymentsEnabled() && calendarForUpdate.isRepeating()) {
|
||||
//fetch all loan calendar instances associated with modifying calendar.
|
||||
final Collection<CalendarInstance> loanCalendarInstances = this.calendarInstanceRepository.findByCalendarIdAndEntityTypeId(
|
||||
calendarId, CalendarEntityType.LOANS.getValue());
|
||||
|
||||
if (!CollectionUtils.isEmpty(loanCalendarInstances)) {
|
||||
// update all loans which are following this meeting
|
||||
// calendar
|
||||
//update all loans associated with modifying calendar
|
||||
this.loanWritePlatformService.applyMeetingDateChanges(calendarForUpdate, loanCalendarInstances);
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -30,7 +30,6 @@ import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarRepositoryWrapper;
|
||||
import org.mifosplatform.portfolio.calendar.exception.NotValidRecurringDateException;
|
||||
import org.mifosplatform.portfolio.calendar.service.CalendarUtils;
|
||||
import org.mifosplatform.portfolio.collectionsheet.data.JLGClientData;
|
||||
import org.mifosplatform.portfolio.collectionsheet.data.JLGCollectionSheetData;
|
||||
import org.mifosplatform.portfolio.collectionsheet.data.JLGCollectionSheetFlatData;
|
||||
@@ -304,9 +303,11 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
|
||||
final String transactionDateStr = df.format(transactionDate.toDate());
|
||||
|
||||
final Calendar calendar = this.calendarRepositoryWrapper.findOneWithNotFoundDetection(calendarId);
|
||||
if (!CalendarUtils.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(), transactionDate)) { throw new NotValidRecurringDateException(
|
||||
"collectionsheet", "The date '" + transactionDate + "' is not a valid meeting date.", transactionDate); }
|
||||
// check if transaction against calendar effective from date
|
||||
|
||||
if (!calendar.isValidRecurringDate(transactionDate)) { throw new NotValidRecurringDateException("collectionsheet", "The date '"
|
||||
+ transactionDate + "' is not a valid meeting date.", transactionDate); }
|
||||
|
||||
final AppUser currentUser = this.context.authenticatedUser();
|
||||
final String hierarchy = currentUser.getOffice().getHierarchy();
|
||||
final String officeHierarchy = hierarchy + "%";
|
||||
@@ -360,5 +361,4 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
|
||||
|
||||
return buildJLGCollectionSheet(transactionDate, collectionSheetFlatDatas);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+13
-2
@@ -25,6 +25,7 @@ import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.commands.domain.CommandWrapper;
|
||||
import org.mifosplatform.commands.service.CommandWrapperBuilder;
|
||||
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||
@@ -49,6 +50,8 @@ import org.mifosplatform.portfolio.group.data.CenterData;
|
||||
import org.mifosplatform.portfolio.group.data.GroupGeneralData;
|
||||
import org.mifosplatform.portfolio.group.service.CenterReadPlatformService;
|
||||
import org.mifosplatform.portfolio.group.service.SearchParameters;
|
||||
import org.mifosplatform.portfolio.meeting.data.MeetingData;
|
||||
import org.mifosplatform.portfolio.meeting.service.MeetingReadPlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -71,6 +74,7 @@ public class CentersApiResource {
|
||||
private final FromJsonHelper fromJsonHelper;
|
||||
private final AccountDetailsReadPlatformService accountDetailsReadPlatformService;
|
||||
private final CalendarReadPlatformService calendarReadPlatformService;
|
||||
private final MeetingReadPlatformService meetingReadPlatformService;
|
||||
|
||||
@Autowired
|
||||
public CentersApiResource(final PlatformSecurityContext context, final CenterReadPlatformService centerReadPlatformService,
|
||||
@@ -80,7 +84,7 @@ public class CentersApiResource {
|
||||
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
|
||||
final CollectionSheetReadPlatformService collectionSheetReadPlatformService, final FromJsonHelper fromJsonHelper,
|
||||
final AccountDetailsReadPlatformService accountDetailsReadPlatformService,
|
||||
final CalendarReadPlatformService calendarReadPlatformService) {
|
||||
final CalendarReadPlatformService calendarReadPlatformService, final MeetingReadPlatformService meetingReadPlatformService) {
|
||||
this.context = context;
|
||||
this.centerReadPlatformService = centerReadPlatformService;
|
||||
this.centerApiJsonSerializer = centerApiJsonSerializer;
|
||||
@@ -92,6 +96,7 @@ public class CentersApiResource {
|
||||
this.fromJsonHelper = fromJsonHelper;
|
||||
this.accountDetailsReadPlatformService = accountDetailsReadPlatformService;
|
||||
this.calendarReadPlatformService = calendarReadPlatformService;
|
||||
this.meetingReadPlatformService = meetingReadPlatformService;
|
||||
}
|
||||
|
||||
@GET
|
||||
@@ -164,7 +169,13 @@ public class CentersApiResource {
|
||||
collectionMeetingCalendar = this.calendarReadPlatformService.retrieveCollctionCalendarByEntity(centerId,
|
||||
CalendarEntityType.CENTERS.getValue());
|
||||
if (collectionMeetingCalendar != null) {
|
||||
collectionMeetingCalendar = this.calendarReadPlatformService.generateRecurringDate(collectionMeetingCalendar);
|
||||
final boolean withHistory = true;
|
||||
final LocalDate tillDate = null;
|
||||
final Collection<LocalDate> recurringDates = this.calendarReadPlatformService.generateRecurringDates(collectionMeetingCalendar, withHistory, tillDate);
|
||||
final Collection<LocalDate> nextTenRecurringDates = this.calendarReadPlatformService.generateNextTenRecurringDates(collectionMeetingCalendar);
|
||||
final MeetingData lastMeeting = this.meetingReadPlatformService.retrieveLastMeeting(collectionMeetingCalendar.getCalendarInstanceId());
|
||||
final LocalDate recentEligibleMeetingDate = this.calendarReadPlatformService.generateNextEligibleMeetingDateForCollection(collectionMeetingCalendar, lastMeeting);
|
||||
collectionMeetingCalendar = CalendarData.withRecurringDates(collectionMeetingCalendar, recurringDates, nextTenRecurringDates, recentEligibleMeetingDate);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
-2
@@ -26,6 +26,7 @@ import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.commands.domain.CommandWrapper;
|
||||
import org.mifosplatform.commands.service.CommandWrapperBuilder;
|
||||
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||
@@ -55,6 +56,8 @@ import org.mifosplatform.portfolio.group.service.CenterReadPlatformService;
|
||||
import org.mifosplatform.portfolio.group.service.GroupReadPlatformService;
|
||||
import org.mifosplatform.portfolio.group.service.GroupRolesReadPlatformService;
|
||||
import org.mifosplatform.portfolio.group.service.SearchParameters;
|
||||
import org.mifosplatform.portfolio.meeting.data.MeetingData;
|
||||
import org.mifosplatform.portfolio.meeting.service.MeetingReadPlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -81,6 +84,7 @@ public class GroupsApiResource {
|
||||
private final GroupRolesReadPlatformService groupRolesReadPlatformService;
|
||||
private final AccountDetailsReadPlatformService accountDetailsReadPlatformService;
|
||||
private final CalendarReadPlatformService calendarReadPlatformService;
|
||||
private final MeetingReadPlatformService meetingReadPlatformService;
|
||||
|
||||
@Autowired
|
||||
public GroupsApiResource(final PlatformSecurityContext context, final GroupReadPlatformService groupReadPlatformService,
|
||||
@@ -93,7 +97,7 @@ public class GroupsApiResource {
|
||||
final CollectionSheetReadPlatformService collectionSheetReadPlatformService, final FromJsonHelper fromJsonHelper,
|
||||
final GroupRolesReadPlatformService groupRolesReadPlatformService,
|
||||
final AccountDetailsReadPlatformService accountDetailsReadPlatformService,
|
||||
final CalendarReadPlatformService calendarReadPlatformService) {
|
||||
final CalendarReadPlatformService calendarReadPlatformService, final MeetingReadPlatformService meetingReadPlatformService) {
|
||||
|
||||
this.context = context;
|
||||
this.groupReadPlatformService = groupReadPlatformService;
|
||||
@@ -109,6 +113,7 @@ public class GroupsApiResource {
|
||||
this.groupRolesReadPlatformService = groupRolesReadPlatformService;
|
||||
this.accountDetailsReadPlatformService = accountDetailsReadPlatformService;
|
||||
this.calendarReadPlatformService = calendarReadPlatformService;
|
||||
this.meetingReadPlatformService = meetingReadPlatformService;
|
||||
}
|
||||
|
||||
@GET
|
||||
@@ -216,7 +221,13 @@ public class GroupsApiResource {
|
||||
CalendarEntityType.GROUPS.getValue());
|
||||
}
|
||||
if (collectionMeetingCalendar != null) {
|
||||
collectionMeetingCalendar = this.calendarReadPlatformService.generateRecurringDate(collectionMeetingCalendar);
|
||||
final boolean withHistory = true;
|
||||
final LocalDate tillDate = null;
|
||||
final Collection<LocalDate> recurringDates = this.calendarReadPlatformService.generateRecurringDates(collectionMeetingCalendar, withHistory, tillDate);
|
||||
final Collection<LocalDate> nextTenRecurringDates = this.calendarReadPlatformService.generateNextTenRecurringDates(collectionMeetingCalendar);
|
||||
final MeetingData lastMeeting = this.meetingReadPlatformService.retrieveLastMeeting(collectionMeetingCalendar.getCalendarInstanceId());
|
||||
final LocalDate recentEligibleMeetingDate = this.calendarReadPlatformService.generateNextEligibleMeetingDateForCollection(collectionMeetingCalendar, lastMeeting);
|
||||
collectionMeetingCalendar = CalendarData.withRecurringDates(collectionMeetingCalendar, recurringDates, nextTenRecurringDates, recentEligibleMeetingDate);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -207,7 +207,7 @@ public class LoanScheduleAssembler {
|
||||
|
||||
private void validateDisbursementDateWithMeetingDates(final LocalDate expectedDisbursementDate, final Calendar calendar) {
|
||||
// disbursement date should fall on a meeting date
|
||||
if (!CalendarUtils.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(), expectedDisbursementDate)) {
|
||||
if (!calendar.isValidRecurringDate(expectedDisbursementDate)) {
|
||||
final String errorMessage = "Expected disbursement date '" + expectedDisbursementDate + "' do not fall on a meeting date";
|
||||
throw new LoanApplicationDateException("disbursement.date.do.not.match.meeting.date", errorMessage, expectedDisbursementDate);
|
||||
}
|
||||
@@ -229,7 +229,7 @@ public class LoanScheduleAssembler {
|
||||
if (repaymentInterval % meetingInterval != 0) {
|
||||
// throw exception: Loan product frequency/interval
|
||||
throw new MeetingFrequencyMismatchException("loanapplication.repayment.interval",
|
||||
"Loan repayment repaid every # must equal or multiple of meeting interval", repaymentInterval);
|
||||
"Loan repayment repaid every # must equal or multiple of meeting interval " + meetingInterval, meetingInterval, repaymentInterval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-4
@@ -74,15 +74,12 @@ public final class LoanEventApiJsonValidator {
|
||||
public void validateDisbursementDateWithMeetingDate(final LocalDate actualDisbursementDate, final CalendarInstance calendarInstance) {
|
||||
if (null != calendarInstance) {
|
||||
final Calendar calendar = calendarInstance.getCalendar();
|
||||
if (calendar != null && actualDisbursementDate != null) {
|
||||
if (!calendar.isValidRecurringDate(actualDisbursementDate)) {
|
||||
// Disbursement date should fall on a meeting date
|
||||
if (!CalendarUtils.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(), actualDisbursementDate)) {
|
||||
final String errorMessage = "Expected disbursement date '" + actualDisbursementDate.toString()
|
||||
+ "' does not fall on a meeting date.";
|
||||
throw new NotValidRecurringDateException("loan.actual.disbursement.date", errorMessage,
|
||||
actualDisbursementDate.toString(), calendar.getTitle());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1080,7 +1080,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
CalendarEntityType.GROUPS.getValue(), null));
|
||||
calendarsData
|
||||
.addAll(this.calendarReadPlatformService.retrieveCalendarsByEntity(groupId, CalendarEntityType.GROUPS.getValue(), null));
|
||||
calendarsData = this.calendarReadPlatformService.generateRecurringDates(calendarsData);
|
||||
calendarsData = this.calendarReadPlatformService.updateWithRecurringDates(calendarsData);
|
||||
return calendarsData;
|
||||
}
|
||||
|
||||
|
||||
+6
-1
@@ -24,6 +24,7 @@ import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.commands.domain.CommandWrapper;
|
||||
import org.mifosplatform.commands.service.CommandWrapperBuilder;
|
||||
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||
@@ -107,7 +108,11 @@ public class MeetingsApiResource {
|
||||
|
||||
if (calendarId != null) {
|
||||
calendarData = this.calendarReadPlatformService.retrieveCalendar(calendarId, entityId, entityTypeId);
|
||||
calendarData = this.calendarReadPlatformService.generateRecurringDate(calendarData, DateUtils.getLocalDateOfTenant());
|
||||
final boolean withHistory = true;
|
||||
final Collection<LocalDate> recurringDates = this.calendarReadPlatformService.generateRecurringDates(calendarData, withHistory, DateUtils.getLocalDateOfTenant());
|
||||
final Collection<LocalDate> nextTenRecurringDates = this.calendarReadPlatformService.generateNextTenRecurringDates(calendarData);
|
||||
final LocalDate recentEligibleMeetingDate = null;
|
||||
calendarData = CalendarData.withRecurringDates(calendarData, recurringDates, nextTenRecurringDates, recentEligibleMeetingDate);
|
||||
}
|
||||
|
||||
final MeetingData meetingData = MeetingData.template(clients, calendarData,
|
||||
|
||||
+5
@@ -66,4 +66,9 @@ public class MeetingData {
|
||||
this.calendarData = calendarData;
|
||||
this.attendanceTypeOptions = attendanceTypeOptions;
|
||||
}
|
||||
|
||||
public LocalDate getMeetingDate() {
|
||||
return this.meetingDate;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-1
@@ -172,8 +172,9 @@ public class Meeting extends AbstractPersistable<Long> {
|
||||
if (meetingDate != null) {
|
||||
meetingDateLocalDate = LocalDate.fromDateFields(meetingDate);
|
||||
}
|
||||
|
||||
if (meetingDateLocalDate == null
|
||||
|| !CalendarUtils.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(), meetingDateLocalDate)) { return false; }
|
||||
|| !calendar.isValidRecurringDate(meetingDateLocalDate)) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -18,4 +18,6 @@ public interface MeetingReadPlatformService {
|
||||
|
||||
Collection<MeetingData> retrieveMeetingsByEntityByCalendarType(final Long entityId, final Integer entityTypeId,
|
||||
final List<Integer> calendarTypeOptions);
|
||||
|
||||
MeetingData retrieveLastMeeting(Long calendarInstanceId);
|
||||
}
|
||||
|
||||
+15
-1
@@ -36,7 +36,8 @@ public class MeetingReadPlatformServiceImpl implements MeetingReadPlatformServic
|
||||
|
||||
public String schema() {
|
||||
|
||||
return " select m.id as id, m.meeting_date as meetingDate from m_meeting m inner join m_calendar_instance ci on m.calendar_instance_id = ci.id ";
|
||||
return " select m.id as id, m.meeting_date as meetingDate from m_meeting m " +
|
||||
"inner join m_calendar_instance ci on m.calendar_instance_id = ci.id ";
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -86,4 +87,17 @@ public class MeetingReadPlatformServiceImpl implements MeetingReadPlatformServic
|
||||
return this.jdbcTemplate.query(sql, rm, new Object[] { entityId, entityTypeId });
|
||||
}
|
||||
|
||||
@Override
|
||||
public MeetingData retrieveLastMeeting(Long calendarInstanceId) {
|
||||
try {
|
||||
final MeetingDataMapper rm = new MeetingDataMapper();
|
||||
|
||||
final String sql = rm.schema() + " where ci.id = ? order by m.meeting_date desc, m.id desc limit 1";
|
||||
|
||||
return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { calendarInstanceId });
|
||||
} catch (final EmptyResultDataAccessException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user