MIFOSX-244: Added recurring rule to calendar and added calendar to Groups

This commit is contained in:
ashok-conflux
2013-03-18 16:10:35 +05:30
parent c5e40ab744
commit 4caa564c4e
11 changed files with 548 additions and 83 deletions
@@ -0,0 +1,32 @@
DROP TABLE IF EXISTS `m_calendar`;
CREATE TABLE IF NOT EXISTS `m_calendar` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`title` varchar(50) NOT NULL,
`description` varchar(100) DEFAULT NULL,
`location` varchar(50) DEFAULT NULL,
`start_date` date NOT NULL,
`end_date` date DEFAULT NULL,
`duration` smallint(6) DEFAULT NULL,
`calendar_type_enum` smallint(5) NOT NULL,
`repeating` tinyint(1) NOT NULL DEFAULT '0',
`recurrence` varchar(100) DEFAULT NULL,
`remind_by_enum` smallint(5) DEFAULT NULL,
`first_reminder` smallint(11) DEFAULT NULL,
`second_reminder` smallint(11) DEFAULT NULL,
`createdby_id` bigint(20) DEFAULT NULL,
`lastmodifiedby_id` bigint(20) DEFAULT NULL,
`created_date` datetime DEFAULT NULL,
`lastmodified_date` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
DROP TABLE IF EXISTS `m_calendar_instance`;
CREATE TABLE IF NOT EXISTS `m_calendar_instance` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`calendar_id` bigint(20) NOT NULL,
`entity_id` bigint(20) NOT NULL,
`entity_type_enum` smallint(5) NOT NULL,
PRIMARY KEY (`id`),
KEY `FK_m_calendar_m_calendar_instance` (`calendar_id`),
CONSTRAINT `FK_m_calendar_m_calendar_instance` FOREIGN KEY (`calendar_id`) REFERENCES `m_calendar` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
@@ -365,21 +365,23 @@ public class DataValidatorBuilder {
return this;
}
public DataValidatorBuilder isValidateRecurringRule(final String recurringRule){
if(StringUtils.isNotBlank(recurringRule)){
try {
RRule rRule = new RRule(recurringRule);
rRule.validate();
} catch (ValidationException e) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.recurring.rule", "The Recurring Rule value: " + recurringRule + " is not valid.", parameter, recurringRule );
dataValidationErrors.add(error);
public DataValidatorBuilder isValidateRecurringRule(final String recurringRule) {
if (StringUtils.isNotBlank(recurringRule)) {
try {
RRule rRule = new RRule(recurringRule);
rRule.validate();
} catch (ValidationException e) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.recurring.rule",
"The Recurring Rule value: " + recurringRule + " is not valid.", parameter, recurringRule);
dataValidationErrors.add(error);
return this;
} catch (ParseException e) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.recurring.rule", "The Recurring Rule value: " + recurringRule + " is not valid.", parameter, recurringRule );
dataValidationErrors.add(error);
} catch (ParseException e) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.recurring.rule.parsing.error",
"Error in pasring the Recurring Rule value: " + recurringRule + ".", parameter, recurringRule);
dataValidationErrors.add(error);
return this;
}
}
return this;
}
}
return this;
}
}
@@ -5,6 +5,7 @@
*/
package org.mifosplatform.portfolio.calendar.api;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
@@ -23,6 +24,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;
@@ -37,6 +39,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.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@@ -50,8 +53,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", "createdDate", "duration", "type", "repeating", "recurrence", "remindBy",
"firstReminder", "secondReminder"));
"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;
@@ -60,18 +64,20 @@ 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 CalendarDropdownReadPlatformService dropdownReadPlatformService, final CalendarWrapperService calendarWrapperService) {
this.context = context;
this.readPlatformService = readPlatformService;
this.toApiJsonSerializer = toApiJsonSerializer;
this.apiRequestParameterHelper = apiRequestParameterHelper;
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
this.dropdownReadPlatformService = dropdownReadPlatformService;
this.calendarWrapperService = calendarWrapperService;
}
@GET
@@ -82,13 +88,16 @@ public class CalendarsApiResource {
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
final Integer entityTypeId = CalendarEntityType.valueOf(entityType.toUpperCase()).getValue();
CalendarData calendar = this.readPlatformService.retrieveCalendar(calendarId, entityId, entityTypeId);
CalendarData calendarData = this.readPlatformService.retrieveCalendar(calendarId, entityId, entityTypeId);
//Include recurring date details
calendarData = handleRecurringDate(calendarData);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
if(settings.isTemplate()){
calendar = handleTemplate(calendar);
calendarData = handleTemplate(calendarData);
}
return this.toApiJsonSerializer.serialize(settings, calendar, this.RESPONSE_DATA_PARAMETERS);
return this.toApiJsonSerializer.serialize(settings, calendarData, this.RESPONSE_DATA_PARAMETERS);
}
@GET
@@ -99,11 +108,13 @@ public class CalendarsApiResource {
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
final Collection<CalendarData> calendars = this.readPlatformService.retrieveCalendarsByEntity(entityId,
Collection<CalendarData> calendarsData = this.readPlatformService.retrieveCalendarsByEntity(entityId,
CalendarEntityType.valueOf(entityType.toUpperCase()).getValue());
//Add recurring dates
calendarsData = handleRecurringDates(calendarsData);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, calendars, this.RESPONSE_DATA_PARAMETERS);
return this.toApiJsonSerializer.serialize(settings, calendarsData, this.RESPONSE_DATA_PARAMETERS);
}
@GET
@@ -172,4 +183,19 @@ public class CalendarsApiResource {
return new CalendarData(calendarData, entityTypeOptions, calendarTypeOptions, remindByOptions);
}
private CalendarData handleRecurringDate(final CalendarData calendarData){
if(!calendarData.isRepeating()) return calendarData;
final Collection<LocalDate> recurringDates = this.calendarWrapperService.getNextRecurrencesList(calendarData);
return new CalendarData(calendarData, recurringDates);
}
private Collection<CalendarData> handleRecurringDates(final Collection<CalendarData> calendarsData){
Collection<CalendarData> recuCalendarsData = new ArrayList<CalendarData>();
for (CalendarData calendarData : calendarsData) {
recuCalendarsData.add(handleRecurringDate(calendarData));
}
return recuCalendarsData;
}
}
@@ -5,6 +5,7 @@
*/
package org.mifosplatform.portfolio.calendar.data;
import java.util.Collection;
import java.util.List;
import org.joda.time.LocalDate;
@@ -26,7 +27,6 @@ public class CalendarData {
private final String location;
private final LocalDate startDate;
private final LocalDate endDate;
private final LocalDate createdDate;
private final Integer duration;
private final EnumOptionData type;
private final boolean repeating;
@@ -34,6 +34,15 @@ public class CalendarData {
private final EnumOptionData remindBy;
private final Integer firstReminder;
private final Integer secondReminder;
private final Collection<LocalDate> recurringDates;
private final String humanReadable;
private final LocalDate createdDate;
private final LocalDate lastUpdatedDate;
private final Long createdByUserId;
private final String createdByUsername;
private final Long lastUpdatedByUserId;
private final String lastUpdatedByUsername;
// template related
final List<EnumOptionData> entityTypeOptions;
@@ -41,9 +50,10 @@ public class CalendarData {
final List<EnumOptionData> remindByOptions;
public CalendarData(final Long id, final Long entityId, final EnumOptionData entityType, final String title, final String description,
final String location, final LocalDate startDate, final LocalDate endDate, final LocalDate createdDate, final Integer duration,
final EnumOptionData type, final boolean repeating, final String recurrence, final EnumOptionData remindBy,
final Integer firstReminder, final Integer secondReminder) {
final String location, final LocalDate startDate, final LocalDate endDate, final Integer duration, final EnumOptionData type,
final boolean repeating, final String recurrence, final EnumOptionData remindBy, final Integer firstReminder,
final Integer secondReminder, final String humanReadable, final LocalDate createdDate, final LocalDate lastUpdatedDate,
final Long createdByUserId, final String createdByUsername, final Long lastUpdatedByUserId, final String lastUpdatedByUsername) {
this.id = id;
this.entityId = entityId;
@@ -53,7 +63,6 @@ public class CalendarData {
this.location = location;
this.startDate = startDate;
this.endDate = endDate;
this.createdDate = createdDate;
this.duration = duration;
this.type = type;
this.repeating = repeating;
@@ -64,6 +73,15 @@ public class CalendarData {
this.entityTypeOptions = null;
this.calendarTypeOptions = null;
this.remindByOptions = null;
this.recurringDates = null;
this.humanReadable = humanReadable;
this.createdDate = createdDate;
this.lastUpdatedDate = lastUpdatedDate;
this.createdByUserId = createdByUserId;
this.createdByUsername = createdByUsername;
this.lastUpdatedByUserId = lastUpdatedByUserId;
this.lastUpdatedByUsername = lastUpdatedByUsername;
}
public CalendarData(final CalendarData calendarData, final List<EnumOptionData> entityTypeOptions,
@@ -76,7 +94,6 @@ public class CalendarData {
this.location = calendarData.location;
this.startDate = calendarData.startDate;
this.endDate = calendarData.endDate;
this.createdDate = calendarData.createdDate;
this.duration = calendarData.duration;
this.type = calendarData.type;
this.repeating = calendarData.repeating;
@@ -87,6 +104,44 @@ public class CalendarData {
this.entityTypeOptions = entityTypeOptions;
this.calendarTypeOptions = calendarTypeOptions;
this.remindByOptions = remindByOptions;
this.recurringDates = calendarData.recurringDates;
this.humanReadable = calendarData.humanReadable;
this.createdDate = calendarData.createdDate;
this.lastUpdatedDate = calendarData.lastUpdatedDate;
this.createdByUserId = calendarData.createdByUserId;
this.createdByUsername = calendarData.createdByUsername;
this.lastUpdatedByUserId = calendarData.lastUpdatedByUserId;
this.lastUpdatedByUsername = calendarData.lastUpdatedByUsername;
}
public CalendarData(final CalendarData calendarData, final Collection<LocalDate> recurringDates) {
this.id = calendarData.id;
this.entityId = calendarData.entityId;
this.entityType = calendarData.entityType;
this.title = calendarData.title;
this.description = calendarData.description;
this.location = calendarData.location;
this.startDate = calendarData.startDate;
this.endDate = calendarData.endDate;
this.duration = calendarData.duration;
this.type = calendarData.type;
this.repeating = calendarData.repeating;
this.recurrence = calendarData.recurrence;
this.remindBy = calendarData.remindBy;
this.firstReminder = calendarData.firstReminder;
this.secondReminder = calendarData.secondReminder;
this.entityTypeOptions = null;
this.calendarTypeOptions = null;
this.remindByOptions = null;
this.recurringDates = recurringDates;
this.humanReadable = calendarData.humanReadable;
this.createdDate = calendarData.createdDate;
this.lastUpdatedDate = calendarData.lastUpdatedDate;
this.createdByUserId = calendarData.createdByUserId;
this.createdByUsername = calendarData.createdByUsername;
this.lastUpdatedByUserId = calendarData.lastUpdatedByUserId;
this.lastUpdatedByUsername = calendarData.lastUpdatedByUsername;
}
public static CalendarData sensibleDefaultsForNewCalendarCreation() {
@@ -98,7 +153,6 @@ public class CalendarData {
final String location = null;
final LocalDate startDate = null;
final LocalDate endDate = null;
final LocalDate createdDate = null;
final Integer duration = new Integer(0);
final EnumOptionData type = CalendarEnumerations.calendarType(CalendarType.COLLECTION);
final boolean repeating = false;
@@ -106,8 +160,90 @@ public class CalendarData {
final EnumOptionData remindBy = CalendarEnumerations.calendarRemindBy(CalendarRemindBy.EMAIL);
final Integer firstReminder = new Integer(0);
final Integer secondReminder = new Integer(0);
final String humanReadable = null;
return new CalendarData(id, entityId, entityType, title, description, location, startDate, endDate, createdDate, duration, type,
repeating, recurrence, remindBy, firstReminder, secondReminder);
return new CalendarData(id, entityId, entityType, title, description, location, startDate, endDate, duration, type, repeating,
recurrence, remindBy, firstReminder, secondReminder, humanReadable, null, null, null, null, null, null);
}
public Long getId() {
return this.id;
}
public Long getEntityId() {
return this.entityId;
}
public EnumOptionData getEntityType() {
return this.entityType;
}
public String getTitle() {
return this.title;
}
public String getDescription() {
return this.description;
}
public String getLocation() {
return this.location;
}
public LocalDate getStartDate() {
return this.startDate;
}
public LocalDate getEndDate() {
return this.endDate;
}
public LocalDate getCreatedDate() {
return this.createdDate;
}
public Integer getDuration() {
return this.duration;
}
public EnumOptionData getType() {
return this.type;
}
public boolean isRepeating() {
return this.repeating;
}
public String getRecurrence() {
return this.recurrence;
}
public EnumOptionData getRemindBy() {
return this.remindBy;
}
public Integer getFirstReminder() {
return this.firstReminder;
}
public Integer getSecondReminder() {
return this.secondReminder;
}
public List<EnumOptionData> getEntityTypeOptions() {
return this.entityTypeOptions;
}
public List<EnumOptionData> getCalendarTypeOptions() {
return this.calendarTypeOptions;
}
public List<EnumOptionData> getRemindByOptions() {
return this.remindByOptions;
}
public String getHumanReadable() {
return this.humanReadable;
}
}
@@ -19,18 +19,13 @@ 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.domain.AbstractAuditableCustom;
import org.mifosplatform.portfolio.calendar.CalendarConstants.CALENDAR_SUPPORTED_PARAMETERS;
import org.springframework.data.jpa.domain.AbstractPersistable;
import org.mifosplatform.useradministration.domain.AppUser;
@Entity
@Table(name = "m_calendar")
public class Calendar extends AbstractPersistable<Long> {
@Column(name = "entity_id", nullable = false)
private Long entityId;
@Column(name = "entity_type_enum", nullable = false)
private Integer entityTypeId;
public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
@Column(name = "title", length = 50, nullable = false)
private String title;
@@ -49,10 +44,6 @@ public class Calendar extends AbstractPersistable<Long> {
@Temporal(TemporalType.DATE)
private Date endDate;
@Column(name = "created_date", nullable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date createdDate;
@Column(name = "duration", nullable = true)
private Integer duration;
@@ -78,12 +69,9 @@ public class Calendar extends AbstractPersistable<Long> {
}
public Calendar(final Long entityId, final Integer entityTypeId, final String title, final String description, final String location,
final LocalDate startDate, final LocalDate endDate, final LocalDate createdDate, final Integer duration, final Integer typeId,
final boolean repeating, final String recurrence, final Integer remindById, final Integer firstReminder,
final Integer secondReminder) {
this.entityId = entityId;
this.entityTypeId = entityTypeId;
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) {
this.title = StringUtils.defaultIfEmpty(title, null);
this.description = StringUtils.defaultIfEmpty(description, null);
this.location = StringUtils.defaultIfEmpty(location, null);
@@ -100,12 +88,6 @@ public class Calendar extends AbstractPersistable<Long> {
this.endDate = null;
}
if (null != createdDate) {
this.createdDate = createdDate.toDateMidnight().toDate();
} else {
this.createdDate = null;
}
this.duration = duration;
this.typeId = typeId;
this.repeating = repeating;
@@ -117,14 +99,14 @@ public class Calendar extends AbstractPersistable<Long> {
public static Calendar fromJson(final JsonCommand command) {
final Long entityId = command.getSupportedEntityId();
final Integer entityTypeId = CalendarEntityType.valueOf(command.getSupportedEntityType().toUpperCase()).getValue();
// final Long entityId = command.getSupportedEntityId();
// final Integer entityTypeId =
// CalendarEntityType.valueOf(command.getSupportedEntityType().toUpperCase()).getValue();
final String title = command.stringValueOfParameterNamed(CALENDAR_SUPPORTED_PARAMETERS.TITLE.getValue());
final String description = command.stringValueOfParameterNamed(CALENDAR_SUPPORTED_PARAMETERS.DESCRIPTION.getValue());
final String location = command.stringValueOfParameterNamed(CALENDAR_SUPPORTED_PARAMETERS.LOCATION.getValue());
final LocalDate startDate = command.localDateValueOfParameterNamed(CALENDAR_SUPPORTED_PARAMETERS.START_DATE.getValue());
final LocalDate endDate = command.localDateValueOfParameterNamed(CALENDAR_SUPPORTED_PARAMETERS.END_DATE.getValue());
final LocalDate createdDate = command.localDateValueOfParameterNamed(CALENDAR_SUPPORTED_PARAMETERS.CREATED_DATE.getValue());
final Integer duration = command.integerValueSansLocaleOfParameterNamed(CALENDAR_SUPPORTED_PARAMETERS.DURATION.getValue());
final Integer typeId = command.integerValueSansLocaleOfParameterNamed(CALENDAR_SUPPORTED_PARAMETERS.TYPE_ID.getValue());
final boolean repeating = command.booleanPrimitiveValueOfParameterNamed(CALENDAR_SUPPORTED_PARAMETERS.REPEATING.getValue());
@@ -135,8 +117,8 @@ public class Calendar extends AbstractPersistable<Long> {
final Integer secondReminder = command.integerValueSansLocaleOfParameterNamed(CALENDAR_SUPPORTED_PARAMETERS.SECOND_REMINDER
.getValue());
return new Calendar(entityId, entityTypeId, title, description, location, startDate, endDate, createdDate, duration, typeId,
repeating, recurrence, remindById, firstReminder, secondReminder);
return new Calendar(title, description, location, startDate, endDate, duration, typeId, repeating, recurrence,
remindById, firstReminder, secondReminder);
}
public Map<String, Object> update(final JsonCommand command) {
@@ -237,14 +219,6 @@ public class Calendar extends AbstractPersistable<Long> {
return actualChanges;
}
public Long getEntityId() {
return this.entityId;
}
public Integer getEntityTypeId() {
return this.entityTypeId;
}
public String getTitle() {
return this.title;
}
@@ -265,10 +239,6 @@ public class Calendar extends AbstractPersistable<Long> {
return this.endDate;
}
public Date getCreatedDate() {
return this.createdDate;
}
public Integer getDuration() {
return this.duration;
}
@@ -0,0 +1,52 @@
package org.mifosplatform.portfolio.calendar.domain;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.springframework.data.jpa.domain.AbstractPersistable;
@Entity
@Table(name = "m_calendar_instance")
public class CalendarInstance extends AbstractPersistable<Long> {
@ManyToOne
@JoinColumn(name = "calendar_id", nullable = false)
private Calendar calendar;
@Column(name = "entity_id", nullable = false)
private Long entityId;
@Column(name = "entity_type_enum", nullable = false)
private Integer entityTypeId;
public CalendarInstance(Calendar calendar, Long entityId, Integer entityTypeId) {
this.calendar = calendar;
this.entityId = entityId;
this.entityTypeId = entityTypeId;
}
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 Calendar getCalendar() {
return this.calendar;
}
public Long getEntityId() {
return this.entityId;
}
public Integer getEntityTypeId() {
return this.entityTypeId;
}
}
@@ -0,0 +1,10 @@
package org.mifosplatform.portfolio.calendar.domain;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface CalendarInstanceRepository extends JpaRepository<CalendarInstance, Long>, JpaSpecificationExecutor<CalendarInstance> {
CalendarInstance findByCalendarAndEntityIdAndEntityTypeId(Long calendarId, Long entityId, Integer entityTypeId);
}
@@ -34,11 +34,14 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
private static final class CalendarDataMapper implements RowMapper<CalendarData> {
public String schema() {
return " select c.id as id, c.entity_id as entityId, c.entity_type_enum as entityTypeId, c.title as title, "
return " select c.id as id, 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.created_date as createdDate, 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 c ";
+ " 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, "
+ " c.created_date as createdDate, c.lastmodified_date as updatedDate, creatingUser.id as creatingUserId, creatingUser.username as creatingUserName, "
+ " updatingUser.id as updatingUserId, updatingUser.username as updatingUserName "
+ " from m_calendar c join m_calendar_instance ci on ci.calendar_id=c.id, m_appuser as creatingUser, m_appuser as updatingUser"
+ " where c.createdby_id=creatingUser.id and c.lastmodifiedby_id=updatingUser.id ";
}
@Override
@@ -53,7 +56,6 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
final String location = rs.getString("location");
final LocalDate startDate = JdbcSupport.getLocalDate(rs, "startDate");
final LocalDate endDate = JdbcSupport.getLocalDate(rs, "endDate");
final LocalDate createdDate = JdbcSupport.getLocalDate(rs, "createdDate");
final Integer duration = rs.getInt("duration");
final Integer typeId = rs.getInt("typeId");
final EnumOptionData type = CalendarEnumerations.calendarType(typeId);
@@ -64,9 +66,16 @@ 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 LocalDate createdDate = JdbcSupport.getLocalDate(rs, "createdDate");
final LocalDate lastUpdatedDate = JdbcSupport.getLocalDate(rs, "updatedDate");
final Long createdByUserId = rs.getLong("creatingUserId");
final String createdByUserName = rs.getString("creatingUserName");
final Long lastUpdatedByUserId = rs.getLong("updatingUserId");
final String lastUpdatedByUserName = rs.getString("updatingUserName");
return new CalendarData(id, entityId, entityType, title, description, location, startDate, endDate, createdDate, duration,
type, repeating, recurrence, remindBy, firstReminder, secondReminder);
return new CalendarData(id, entityId, entityType, title, description, location, startDate, endDate, duration, type, repeating, recurrence, remindBy, firstReminder, secondReminder, humanReadable, createdDate, lastUpdatedDate, createdByUserId, createdByUserName, lastUpdatedByUserId, lastUpdatedByUserName);
}
}
@@ -76,7 +85,7 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
try {
final CalendarDataMapper rm = new CalendarDataMapper();
final String sql = rm.schema() + "where c.id = ? and c.entity_id = ? and c.entity_type_enum = ?";
final String sql = rm.schema() + " and c.id = ? and ci.entity_id = ? and ci.entity_type_enum = ? ";
return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { calendarId, entityId, entityTypeId });
} catch (final EmptyResultDataAccessException e) {
@@ -88,7 +97,7 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
public Collection<CalendarData> retrieveCalendarsByEntity(final Long entityId, final Integer entityTypeId) {
final CalendarDataMapper rm = new CalendarDataMapper();
final String sql = rm.schema() + "where c.entity_id = ? and c.entity_type_enum = ?";
final String sql = rm.schema() + " and ci.entity_id = ? and ci.entity_type_enum = ? order by c.start_date ";
return this.jdbcTemplate.query(sql, rm, new Object[] { entityId, entityTypeId });
}
@@ -0,0 +1,186 @@
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
return getNextRecurrencesList(calendarData, maxCount);
}
public Collection<LocalDate> getNextRecurrencesList(final CalendarData calendarData, int maxCount) {
final Recur recur = getRecur(calendarData);
if (recur == null) { return null; }
final Date seed = new Date(calendarData.getStartDate().toDate());
final DateTime periodStart = new DateTime(calendarData.getStartDate().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;
}
}
@@ -10,4 +10,8 @@ public interface CalendarWritePlatformService {
CommandProcessingResult updateCalendar(JsonCommand command);
CommandProcessingResult deleteCalendar(Long calendarId);
CommandProcessingResult createCalendarInstance(Long calendarId, Long entityId, Integer entityTypeId);
CommandProcessingResult updateCalendarInstance(Long calendarId, Long entityId, Integer entityTypeId);
}
@@ -11,6 +11,8 @@ import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
import org.mifosplatform.portfolio.calendar.domain.Calendar;
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.serialization.CalendarCommandFromApiJsonDeserializer;
@@ -22,12 +24,15 @@ public class CalendarWritePlatformServiceJpaRepositoryImpl implements CalendarWr
private final CalendarRepository calendarRepository;
private final CalendarCommandFromApiJsonDeserializer fromApiJsonDeserializer;
private final CalendarInstanceRepository calendarInstanceRepository;
@Autowired
public CalendarWritePlatformServiceJpaRepositoryImpl(final CalendarRepository calendarRepository,
final CalendarCommandFromApiJsonDeserializer fromApiJsonDeserializer) {
final CalendarCommandFromApiJsonDeserializer fromApiJsonDeserializer,
final CalendarInstanceRepository calendarInstanceRepository) {
this.calendarRepository = calendarRepository;
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
this.calendarInstanceRepository = calendarInstanceRepository;
}
@Override
@@ -37,6 +42,10 @@ public class CalendarWritePlatformServiceJpaRepositoryImpl implements CalendarWr
final Calendar newCalendar = Calendar.fromJson(command);
this.calendarRepository.save(newCalendar);
final CalendarInstance newCalendarInstance = CalendarInstance.fromJson(newCalendar, command);
this.calendarInstanceRepository.save(newCalendarInstance);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(newCalendar.getId()) //
@@ -78,4 +87,33 @@ public class CalendarWritePlatformServiceJpaRepositoryImpl implements CalendarWr
.build();
}
@Override
public CommandProcessingResult createCalendarInstance(final Long calendarId, final Long entityId, final Integer entityTypeId) {
final Calendar calendarForUpdate = this.calendarRepository.findOne(calendarId);
if (calendarForUpdate == null) { throw new CalendarNotFoundException(calendarId); }
final CalendarInstance newCalendarInstance = new CalendarInstance(calendarForUpdate, entityId, entityTypeId);
this.calendarInstanceRepository.save(newCalendarInstance);
return new CommandProcessingResultBuilder() //
.withCommandId(null) //
.withEntityId(calendarForUpdate.getId()) //
.build();
}
@Override
public CommandProcessingResult updateCalendarInstance(Long calendarId, Long entityId, Integer entityTypeId) {
final Calendar calendarForUpdate = this.calendarRepository.findOne(calendarId);
if (calendarForUpdate == null) { throw new CalendarNotFoundException(calendarId); }
final CalendarInstance calendarInstanceForUpdate = this.calendarInstanceRepository.findByCalendarAndEntityIdAndEntityTypeId(calendarId, entityId, entityTypeId);
this.calendarInstanceRepository.saveAndFlush(calendarInstanceForUpdate);
return new CommandProcessingResultBuilder() //
.withCommandId(null) //
.withEntityId(calendarForUpdate.getId()) //
.build();
}
}