MIFOSX-496: Capture client attendance details
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
CREATE TABLE `m_meeting` (
|
||||
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
`calendar_instance_id` BIGINT(20) NOT NULL,
|
||||
`meeting_date` DATE NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE INDEX `unique_calendar_instance_id_meeting_date` (`calendar_instance_id`, `meeting_date`),
|
||||
CONSTRAINT `FK_m_calendar_instance_m_meeting` FOREIGN KEY (`calendar_instance_id`) REFERENCES `m_calendar_instance` (`id`)
|
||||
)
|
||||
COLLATE='latin1_swedish_ci'
|
||||
ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE `m_client_attendance` (
|
||||
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
`client_id` BIGINT(20) NOT NULL DEFAULT '0',
|
||||
`meeting_id` BIGINT(20) NOT NULL,
|
||||
`attendance_type_enum` SMALLINT(5) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE INDEX `unique_client_meeting_attendance` (`client_id`, `meeting_id`),
|
||||
INDEX `FK_m_meeting_m_client_attendance` (`meeting_id`),
|
||||
CONSTRAINT `FK_m_client_m_client_attendance` FOREIGN KEY (`client_id`) REFERENCES `m_client` (`id`),
|
||||
CONSTRAINT `FK_m_meeting_m_client_attendance` FOREIGN KEY (`meeting_id`) REFERENCES `m_meeting` (`id`)
|
||||
)
|
||||
COLLATE='utf8_general_ci'
|
||||
ENGINE=InnoDB;
|
||||
|
||||
|
||||
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'CREATE_MEETING', 'MEETING', 'CREATE', 0);
|
||||
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'UPDATE_MEETING', 'MEETING', 'UPDATE', 0);
|
||||
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'DELETE_MEETING', 'MEETING', 'DELETE', 0);
|
||||
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'SAVEORUPDATEATTENDANCE_MEETING', 'MEETING', 'SAVEORUPDATEATTENDANCE', 0);
|
||||
@@ -571,4 +571,12 @@ public class CommandWrapper {
|
||||
public boolean isAccountTransferResource() {
|
||||
return this.entityName.equalsIgnoreCase("ACCOUNTTRANSFER");
|
||||
}
|
||||
|
||||
public boolean isMeetingResource() {
|
||||
return this.entityName.equalsIgnoreCase("MEETING");
|
||||
}
|
||||
|
||||
public boolean isSaveOrUpdateAttendance(){
|
||||
return this.actionName.equalsIgnoreCase("SAVEORUPDATEATTENDANCE");
|
||||
}
|
||||
}
|
||||
+35
@@ -1210,4 +1210,39 @@ public class CommandWrapperBuilder {
|
||||
this.href = "/updateJobDetail/" + jobId + "/updateJobDetail";
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder createMeeting(final String supportedEntityType, final Long supportedEntityId) {
|
||||
this.actionName = "CREATE";
|
||||
this.entityName = "MEETING";
|
||||
this.supportedEntityType = supportedEntityType;
|
||||
this.supportedEntityId = supportedEntityId;
|
||||
this.href = "/" + supportedEntityType + "/" + supportedEntityId + "/meetings";
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder updateMeeting(final String supportedEntityType, final Long supportedEntityId, final Long meetingId) {
|
||||
this.actionName = "UPDATE";
|
||||
this.entityName = "MEETING";
|
||||
this.entityId = meetingId;
|
||||
this.href = "/" + supportedEntityType + "/" + supportedEntityId + "/meetings/" + meetingId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder deleteMeeting(final String supportedEntityType, final Long supportedEntityId, final Long meetingId) {
|
||||
this.actionName = "DELETE";
|
||||
this.entityName = "MEETING";
|
||||
this.entityId = meetingId;
|
||||
this.href = "/" + supportedEntityType + "/" + supportedEntityId + "/meetings/" + meetingId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder saveOrUpdateAttendance(final Long entityId, final String supportedEntityType, final Long supportedEntityId) {
|
||||
this.actionName = "SAVEORUPDATEATTENDANCE";
|
||||
this.entityName = "MEETING";
|
||||
this.entityId = entityId;
|
||||
this.supportedEntityType = supportedEntityType;
|
||||
this.supportedEntityId = supportedEntityId;
|
||||
this.href = "/" + supportedEntityType + "/" + supportedEntityId + "/meetings/" + entityId + "?command=saveOrUpdateAttendance";
|
||||
return this;
|
||||
}
|
||||
}
|
||||
+12
@@ -522,6 +522,18 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
||||
} else {
|
||||
throw new UnsupportedCommandException(wrapper.commandName());
|
||||
}
|
||||
} else if (wrapper.isMeetingResource()) {
|
||||
if (wrapper.isCreate()) {
|
||||
handler = this.applicationContext.getBean("createMeetingCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isUpdate()) {
|
||||
handler = this.applicationContext.getBean("updateMeetingCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isDelete()) {
|
||||
handler = this.applicationContext.getBean("deleteMeetingCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isSaveOrUpdateAttendance()) {
|
||||
handler = this.applicationContext.getBean("updateMeetingAttendanceCommandHandler", NewCommandSourceHandler.class);
|
||||
} else {
|
||||
throw new UnsupportedCommandException(wrapper.commandName());
|
||||
}
|
||||
} else {
|
||||
throw new UnsupportedCommandException(wrapper.commandName());
|
||||
}
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@ package org.mifosplatform.organisation.workingdays.service;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.organisation.workingdays.domain.RepaymentRescheduleType;
|
||||
import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
|
||||
import org.mifosplatform.portfolio.calendar.service.CalendarHelper;
|
||||
import org.mifosplatform.portfolio.calendar.service.CalendarUtils;
|
||||
|
||||
public class WorkingDaysUtil {
|
||||
|
||||
@@ -38,6 +38,6 @@ public class WorkingDaysUtil {
|
||||
}
|
||||
|
||||
public static boolean isWorkingDay(WorkingDays workingDays, final LocalDate date){
|
||||
return CalendarHelper.isValidRedurringDate(workingDays.getRecurrence(), date, date);
|
||||
return CalendarUtils.isValidRedurringDate(workingDays.getRecurrence(), date, date);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-34
@@ -20,6 +20,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.CalendarUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -105,7 +106,7 @@ public class CalendarsApiResource {
|
||||
|
||||
Collection<CalendarData> calendarsData = new ArrayList<CalendarData>();
|
||||
|
||||
List<Integer> calendarTypeOptions = createIntegerListFromQueryParameter(calendarType);
|
||||
List<Integer> calendarTypeOptions = CalendarUtils.createIntegerListFromQueryParameter(calendarType);
|
||||
|
||||
|
||||
if (!associationParameters.isEmpty()) {
|
||||
@@ -191,37 +192,4 @@ public class CalendarsApiResource {
|
||||
return new CalendarData(calendarData, entityTypeOptions, calendarTypeOptions, remindByOptions);
|
||||
}
|
||||
|
||||
|
||||
public List<Integer> createIntegerListFromQueryParameter(String calendarTypeQuery) {
|
||||
List<Integer> calendarTypeOptions = new ArrayList<Integer>();
|
||||
// adding all calendar Types if query parameter is "all"
|
||||
if(calendarTypeQuery.equalsIgnoreCase("all")){
|
||||
calendarTypeOptions.add(1);
|
||||
calendarTypeOptions.add(2);
|
||||
calendarTypeOptions.add(3);
|
||||
calendarTypeOptions.add(4);
|
||||
return calendarTypeOptions;
|
||||
}
|
||||
// creating a list of calendar type options from the comma separated query parameter.
|
||||
List<String> calendarTypeOptionsInQuery = new ArrayList<String>();
|
||||
StringTokenizer st = new StringTokenizer(calendarTypeQuery, ",");
|
||||
while (st.hasMoreElements()) {
|
||||
calendarTypeOptionsInQuery.add(st.nextElement().toString());
|
||||
}
|
||||
|
||||
for(String calType : calendarTypeOptionsInQuery){
|
||||
if(calType.equalsIgnoreCase("collection")) {
|
||||
calendarTypeOptions.add(1);
|
||||
} else if(calType.equalsIgnoreCase("training")) {
|
||||
calendarTypeOptions.add(2);
|
||||
} else if(calType.equalsIgnoreCase("audit")) {
|
||||
calendarTypeOptions.add(3);
|
||||
} else if(calType.equalsIgnoreCase("general")) {
|
||||
calendarTypeOptions.add(4);
|
||||
}
|
||||
}
|
||||
|
||||
return calendarTypeOptions;
|
||||
}
|
||||
|
||||
}
|
||||
+3
-3
@@ -23,7 +23,7 @@ import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom;
|
||||
import org.mifosplatform.portfolio.calendar.CalendarConstants.CALENDAR_SUPPORTED_PARAMETERS;
|
||||
import org.mifosplatform.portfolio.calendar.exception.CalendarDateException;
|
||||
import org.mifosplatform.portfolio.calendar.exception.CalendarParameterUpdateNotSupportedException;
|
||||
import org.mifosplatform.portfolio.calendar.service.CalendarHelper;
|
||||
import org.mifosplatform.portfolio.calendar.service.CalendarUtils;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
|
||||
@Entity
|
||||
@@ -213,13 +213,13 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
|
||||
//FIXME: AA - Is this restriction required only for collection type meetings or for all?.
|
||||
//Do not allow to change meeting frequency
|
||||
|
||||
if(!CalendarHelper.isFrequencySame(this.recurrence, newValue)){
|
||||
if(!CalendarUtils.isFrequencySame(this.recurrence, newValue)){
|
||||
final String defaultUserMessage = "Update of meeting frequency is not supported";
|
||||
throw new CalendarParameterUpdateNotSupportedException("meeting.frequency", defaultUserMessage);
|
||||
}
|
||||
|
||||
//Do not allow to change meeting interval
|
||||
if(!CalendarHelper.isIntervalSame(this.recurrence, newValue)){
|
||||
if(!CalendarUtils.isIntervalSame(this.recurrence, newValue)){
|
||||
final String defaultUserMessage = "Update of meeting interval is not supported";
|
||||
throw new CalendarParameterUpdateNotSupportedException("meeting.interval", defaultUserMessage);
|
||||
}
|
||||
|
||||
+16
@@ -66,4 +66,20 @@ public enum CalendarEntityType {
|
||||
public String toString() {
|
||||
return name().toString();
|
||||
}
|
||||
|
||||
public static boolean isGroup(final Integer value) {
|
||||
return CalendarEntityType.GROUPS.value.equals(value) ? true : false;
|
||||
}
|
||||
|
||||
public static boolean isGroup(final String name) {
|
||||
return CalendarEntityType.GROUPS.name().equalsIgnoreCase(name) ? true : false;
|
||||
}
|
||||
|
||||
public static boolean isCenter(final Integer value) {
|
||||
return CalendarEntityType.CENTERS.value.equals(value) ? true : false;
|
||||
}
|
||||
|
||||
public static boolean isCenter(final String name) {
|
||||
return CalendarEntityType.CENTERS.name().equalsIgnoreCase(name) ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface CalendarInstanceRepository extends JpaRepository<CalendarInstance, Long>, JpaSpecificationExecutor<CalendarInstance> {
|
||||
|
||||
CalendarInstance findByCalendarAndEntityIdAndEntityTypeId(Long calendarId, Long entityId, Integer entityTypeId);
|
||||
CalendarInstance findByCalendarIdAndEntityIdAndEntityTypeId(Long calendarId, Long entityId, Integer entityTypeId);
|
||||
|
||||
Collection<CalendarInstance> findByEntityIdAndEntityTypeId(Long entityId, Integer entityTypeId);
|
||||
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* 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.mifosplatform.portfolio.calendar.exception.CalendarInstanceNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Wrapper for {@link CalendarInstanceRepository} that is responsible for checking
|
||||
* if {@link CalendarInstance} is returned when using <code>findOne</code>
|
||||
* repository method and throwing an appropriate not found exception.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This is to avoid need for checking and throwing in multiple areas of code
|
||||
* base where {@link CalendarInstanceRepository} is required.
|
||||
* </p>
|
||||
*/
|
||||
@Service
|
||||
public class CalendarInstanceRepositoryWrapper {
|
||||
|
||||
private final CalendarInstanceRepository repository;
|
||||
|
||||
@Autowired
|
||||
public CalendarInstanceRepositoryWrapper(final CalendarInstanceRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public CalendarInstance findOneWithNotFoundDetection(final Long CalendarInstanceId) {
|
||||
final CalendarInstance calendatInstance = this.repository.findOne(CalendarInstanceId);
|
||||
if (calendatInstance == null) { throw new CalendarInstanceNotFoundException(CalendarInstanceId); }
|
||||
return calendatInstance;
|
||||
}
|
||||
|
||||
public void save(final CalendarInstance calendatInstance) {
|
||||
this.repository.save(calendatInstance);
|
||||
}
|
||||
|
||||
public void delete(final CalendarInstance calendatInstance) {
|
||||
this.repository.delete(calendatInstance);
|
||||
}
|
||||
|
||||
public void saveAndFlush(final CalendarInstance calendatInstance) {
|
||||
this.repository.saveAndFlush(calendatInstance);
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.calendar.exception;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
|
||||
|
||||
/**
|
||||
* A {@link RuntimeException} thrown when CalendarInstance resources are not found.
|
||||
*/
|
||||
public class CalendarInstanceNotFoundException extends AbstractPlatformResourceNotFoundException {
|
||||
|
||||
public CalendarInstanceNotFoundException(final Long id) {
|
||||
super("error.msg.calendar.instance.id.invalid", "Calendar Instance with identifier " + id + " does not exist", id);
|
||||
}
|
||||
|
||||
public CalendarInstanceNotFoundException(final String postFix, final String defaultUserMessage, final Object... defaultUserMessageArgs) {
|
||||
super("error.msg.calendar.instance." + postFix, defaultUserMessage, defaultUserMessageArgs);
|
||||
}
|
||||
}
|
||||
+5
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.calendar.service;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.portfolio.calendar.data.CalendarData;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -23,9 +24,13 @@ public interface CalendarReadPlatformService {
|
||||
CalendarData retrieveNewCalendarDetails();
|
||||
|
||||
CalendarData generateRecurringDate(final CalendarData calendarData);
|
||||
|
||||
CalendarData generateRecurringDate(final CalendarData calendarData, final LocalDate tillDate);
|
||||
|
||||
Collection<CalendarData> generateRecurringDates(final Collection<CalendarData> calendarsData);
|
||||
|
||||
CalendarData retrieveLoanCalendar(final Long loanId);
|
||||
|
||||
CalendarData retrieveCollctionCalendarByEntity(final Long entityId, final Integer entityTypeId);
|
||||
|
||||
}
|
||||
|
||||
+37
-24
@@ -18,6 +18,7 @@ import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
|
||||
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.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
@@ -71,7 +72,7 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
|
||||
if (remindById != null && remindById != 0) remindBy = CalendarEnumerations.calendarRemindBy(remindById);
|
||||
final Integer firstReminder = rs.getInt("firstReminder");
|
||||
final Integer secondReminder = rs.getInt("secondReminder");
|
||||
final String humanReadable = CalendarHelper.getRRuleReadable(startDate, recurrence);
|
||||
final String humanReadable = CalendarUtils.getRRuleReadable(startDate, recurrence);
|
||||
|
||||
final LocalDate createdDate = JdbcSupport.getLocalDate(rs, "createdDate");
|
||||
final LocalDate lastUpdatedDate = JdbcSupport.getLocalDate(rs, "updatedDate");
|
||||
@@ -113,13 +114,27 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
|
||||
sql = rm.schema() + " and ci.entity_id = ? and ci.entity_type_enum = ? order by c.start_date ";
|
||||
result = this.jdbcTemplate.query(sql, rm, new Object[] { entityId, entityTypeId });
|
||||
} else if (!calendarTypeOptions.isEmpty()) {
|
||||
String sqlCalendarTypeOptions = getSqlCalendarTypeOptionsInString(calendarTypeOptions);
|
||||
String sqlCalendarTypeOptions = CalendarUtils.getSqlCalendarTypeOptionsInString(calendarTypeOptions);
|
||||
sql = rm.schema() + " and ci.entity_id = ? and ci.entity_type_enum = ? and c.calendar_type_enum in ( " + sqlCalendarTypeOptions
|
||||
+ " ) order by c.start_date ";
|
||||
result = this.jdbcTemplate.query(sql, rm, new Object[] { entityId, entityTypeId });
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CalendarData retrieveCollctionCalendarByEntity(final Long entityId, final Integer entityTypeId) {
|
||||
final CalendarDataMapper rm = new CalendarDataMapper();
|
||||
|
||||
String sql = rm.schema() + " and ci.entity_id = ? and ci.entity_type_enum = ? and calendar_type_enum = ? order by c.start_date ";
|
||||
List<CalendarData> result = this.jdbcTemplate.query(sql, rm, new Object[] { entityId, entityTypeId, CalendarType.COLLECTION.getValue() });
|
||||
|
||||
if(!result.isEmpty() && result.size() > 0){
|
||||
return result.get(0);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<CalendarData> retrieveParentCalendarsByEntity(final Long entityId, final Integer entityTypeId,
|
||||
@@ -137,7 +152,7 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
|
||||
sql = rm.schema() + " " + parentHeirarchyCondition + " and ci.entity_type_enum = ? order by c.start_date ";
|
||||
result = this.jdbcTemplate.query(sql, rm, new Object[] { entityId, CalendarEntityType.CENTERS.getValue() });
|
||||
} else {
|
||||
String sqlCalendarTypeOptions = getSqlCalendarTypeOptionsInString(calendarTypeOptions);
|
||||
String sqlCalendarTypeOptions = CalendarUtils.getSqlCalendarTypeOptionsInString(calendarTypeOptions);
|
||||
sql = rm.schema() + " " + parentHeirarchyCondition + " and ci.entity_type_enum = ? and c.calendar_type_enum in ("
|
||||
+ sqlCalendarTypeOptions + ") order by c.start_date ";
|
||||
result = this.jdbcTemplate.query(sql, rm, new Object[] { entityId, CalendarEntityType.CENTERS.getValue() });
|
||||
@@ -162,6 +177,11 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
|
||||
|
||||
@Override
|
||||
public CalendarData generateRecurringDate(final CalendarData calendarData) {
|
||||
return generateRecurringDate(calendarData, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CalendarData generateRecurringDate(CalendarData calendarData, LocalDate tillDate) {
|
||||
if (!calendarData.isRepeating()) return calendarData;
|
||||
final String rrule = calendarData.getRecurrence();
|
||||
final LocalDate currentDate = DateUtils.getLocalDateOfTenant();
|
||||
@@ -172,13 +192,22 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
|
||||
startDate = currentDate.minusYears(1);
|
||||
}
|
||||
|
||||
if (endDate == null || endDate.isAfter(currentDate.plusYears(1))) {
|
||||
if(tillDate != null){
|
||||
if(endDate != null){
|
||||
if(endDate.isAfter(tillDate)){
|
||||
endDate = tillDate;//to retrieve meeting dates till specified date (tillDate)
|
||||
}
|
||||
}else{
|
||||
endDate = tillDate;//end date is null then fetch meeting dates tillDate
|
||||
}
|
||||
}else if (endDate == null || endDate.isAfter(currentDate.plusYears(1))) {
|
||||
endDate = currentDate.plusYears(1);
|
||||
}
|
||||
|
||||
final Collection<LocalDate> recurringDates = CalendarHelper.getRecurringDates(rrule, seedDate, startDate, endDate, -1);
|
||||
final Collection<LocalDate> nextTenRecurringDates = CalendarHelper.getRecurringDates(rrule, seedDate, endDate);
|
||||
|
||||
final Collection<LocalDate> recurringDates = CalendarUtils.getRecurringDates(rrule, seedDate, startDate, endDate, -1);
|
||||
final Collection<LocalDate> nextTenRecurringDates = CalendarUtils.getRecurringDates(rrule, seedDate, endDate);
|
||||
return new CalendarData(calendarData, recurringDates, nextTenRecurringDates);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -238,21 +267,5 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
|
||||
|
||||
return conditionSql;
|
||||
}
|
||||
|
||||
/**
|
||||
* function returns a comma separated list of calendar_type_enum values ex.
|
||||
* 1,2,3,4
|
||||
*
|
||||
* @param calendarTypeOptions
|
||||
* @return
|
||||
*/
|
||||
public String getSqlCalendarTypeOptionsInString(final List<Integer> calendarTypeOptions) {
|
||||
String sqlCalendarTypeOptions = "";
|
||||
int size = calendarTypeOptions.size();
|
||||
for (int i = 0; i < size - 1; i++) {
|
||||
sqlCalendarTypeOptions += calendarTypeOptions.get(i).toString() + ",";
|
||||
}
|
||||
sqlCalendarTypeOptions += calendarTypeOptions.get(size - 1).toString();
|
||||
return sqlCalendarTypeOptions;
|
||||
}
|
||||
|
||||
}
|
||||
+60
-9
@@ -11,6 +11,8 @@ import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.fortuna.ical4j.model.Date;
|
||||
import net.fortuna.ical4j.model.DateList;
|
||||
@@ -32,10 +34,10 @@ import org.mifosplatform.organisation.workingdays.service.WorkingDaysUtil;
|
||||
import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
|
||||
|
||||
public class CalendarHelper {
|
||||
public class CalendarUtils {
|
||||
|
||||
public static LocalDate getNextRecurringDate(final String recurringRule, final LocalDate seedDate, final LocalDate startDate) {
|
||||
final Recur recur = CalendarHelper.getICalRecur(recurringRule);
|
||||
final Recur recur = CalendarUtils.getICalRecur(recurringRule);
|
||||
if (recur == null) { return null; }
|
||||
return getNextRecurringDate(recur, seedDate, startDate);
|
||||
}
|
||||
@@ -82,7 +84,7 @@ public class CalendarHelper {
|
||||
public static Collection<LocalDate> getRecurringDates(final String recurringRule, final LocalDate seedDate,
|
||||
final LocalDate periodStartDate, final LocalDate periodEndDate, final int maxCount) {
|
||||
|
||||
final Recur recur = CalendarHelper.getICalRecur(recurringRule);
|
||||
final Recur recur = CalendarUtils.getICalRecur(recurringRule);
|
||||
|
||||
return getRecurringDates(recur, seedDate, periodStartDate,
|
||||
periodEndDate, maxCount);
|
||||
@@ -210,7 +212,7 @@ public class CalendarHelper {
|
||||
|
||||
public static boolean isValidRedurringDate(final String recurringRule, final LocalDate seedDate, final LocalDate date){
|
||||
|
||||
final Recur recur = CalendarHelper.getICalRecur(recurringRule);
|
||||
final Recur recur = CalendarUtils.getICalRecur(recurringRule);
|
||||
if (recur == null) { return false; }
|
||||
|
||||
return isValidRecurringDate(recur, seedDate, date);
|
||||
@@ -248,7 +250,7 @@ public class CalendarHelper {
|
||||
}
|
||||
|
||||
public static PeriodFrequencyType getMeetingPeriodFrequencyType(final String recurringRule){
|
||||
final Recur recur = CalendarHelper.getICalRecur(recurringRule);
|
||||
final Recur recur = CalendarUtils.getICalRecur(recurringRule);
|
||||
PeriodFrequencyType meetingFrequencyType = PeriodFrequencyType.INVALID;
|
||||
if(recur.getFrequency().equals(Recur.DAILY)){
|
||||
meetingFrequencyType = PeriodFrequencyType.DAYS;
|
||||
@@ -277,12 +279,12 @@ public class CalendarHelper {
|
||||
}
|
||||
|
||||
public static int getInterval(final String recurringRule){
|
||||
final Recur recur = CalendarHelper.getICalRecur(recurringRule);
|
||||
final Recur recur = CalendarUtils.getICalRecur(recurringRule);
|
||||
return recur.getInterval();
|
||||
}
|
||||
|
||||
public static LocalDate getFirstRepaymentMeetingDate(final Calendar calendar, final LocalDate disbursementDate, final Integer loanRepaymentInterval, final String frequency){
|
||||
final Recur recur = CalendarHelper.getICalRecur(calendar.getRecurrence());
|
||||
final Recur recur = CalendarUtils.getICalRecur(calendar.getRecurrence());
|
||||
if (recur == null) { return null; }
|
||||
LocalDate startDate = disbursementDate;
|
||||
final LocalDate seedDate = calendar.getStartDateLocalDate();
|
||||
@@ -310,7 +312,7 @@ public class CalendarHelper {
|
||||
}
|
||||
|
||||
public static LocalDate getNewRepaymentMeetingDate(final String recurringRule, final LocalDate seedDate, final LocalDate oldRepaymentDate, final Integer loanRepaymentInterval, final String frequency, final WorkingDays workingDays){
|
||||
final Recur recur = CalendarHelper.getICalRecur(recurringRule);
|
||||
final Recur recur = CalendarUtils.getICalRecur(recurringRule);
|
||||
if (recur == null) { return null; }
|
||||
if(isValidRecurringDate(recur, seedDate, oldRepaymentDate)){
|
||||
return oldRepaymentDate;
|
||||
@@ -320,7 +322,7 @@ public class CalendarHelper {
|
||||
|
||||
public static LocalDate getNextRepaymentMeetingDate(final String recurringRule, final LocalDate seedDate, final LocalDate repaymentDate, final Integer loanRepaymentInterval, final String frequency, final WorkingDays workingDays){
|
||||
|
||||
final Recur recur = CalendarHelper.getICalRecur(recurringRule);
|
||||
final Recur recur = CalendarUtils.getICalRecur(recurringRule);
|
||||
if (recur == null) { return null; }
|
||||
LocalDate tmpDate = repaymentDate;
|
||||
if(isValidRecurringDate(recur, seedDate, repaymentDate)){
|
||||
@@ -364,4 +366,53 @@ public class CalendarHelper {
|
||||
if (oldRecur == null || oldRecur.getFrequency() == null || newRecur == null || newRecur.getFrequency() == null) { return false; }
|
||||
return (oldRecur.getInterval() == newRecur.getInterval());
|
||||
}
|
||||
|
||||
public static List<Integer> createIntegerListFromQueryParameter(String calendarTypeQuery) {
|
||||
List<Integer> calendarTypeOptions = new ArrayList<Integer>();
|
||||
// adding all calendar Types if query parameter is "all"
|
||||
if(calendarTypeQuery.equalsIgnoreCase("all")){
|
||||
calendarTypeOptions.add(1);
|
||||
calendarTypeOptions.add(2);
|
||||
calendarTypeOptions.add(3);
|
||||
calendarTypeOptions.add(4);
|
||||
return calendarTypeOptions;
|
||||
}
|
||||
// creating a list of calendar type options from the comma separated query parameter.
|
||||
List<String> calendarTypeOptionsInQuery = new ArrayList<String>();
|
||||
StringTokenizer st = new StringTokenizer(calendarTypeQuery, ",");
|
||||
while (st.hasMoreElements()) {
|
||||
calendarTypeOptionsInQuery.add(st.nextElement().toString());
|
||||
}
|
||||
|
||||
for(String calType : calendarTypeOptionsInQuery){
|
||||
if(calType.equalsIgnoreCase("collection")) {
|
||||
calendarTypeOptions.add(1);
|
||||
} else if(calType.equalsIgnoreCase("training")) {
|
||||
calendarTypeOptions.add(2);
|
||||
} else if(calType.equalsIgnoreCase("audit")) {
|
||||
calendarTypeOptions.add(3);
|
||||
} else if(calType.equalsIgnoreCase("general")) {
|
||||
calendarTypeOptions.add(4);
|
||||
}
|
||||
}
|
||||
|
||||
return calendarTypeOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* function returns a comma separated list of calendar_type_enum values ex.
|
||||
* 1,2,3,4
|
||||
*
|
||||
* @param calendarTypeOptions
|
||||
* @return
|
||||
*/
|
||||
public static String getSqlCalendarTypeOptionsInString(final List<Integer> calendarTypeOptions) {
|
||||
String sqlCalendarTypeOptions = "";
|
||||
int size = calendarTypeOptions.size();
|
||||
for (int i = 0; i < size - 1; i++) {
|
||||
sqlCalendarTypeOptions += calendarTypeOptions.get(i).toString() + ",";
|
||||
}
|
||||
sqlCalendarTypeOptions += calendarTypeOptions.get(size - 1).toString();
|
||||
return sqlCalendarTypeOptions;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -128,7 +128,7 @@ public class CalendarWritePlatformServiceJpaRepositoryImpl implements CalendarWr
|
||||
final Calendar calendarForUpdate = this.calendarRepository.findOne(calendarId);
|
||||
if (calendarForUpdate == null) { throw new CalendarNotFoundException(calendarId); }
|
||||
|
||||
final CalendarInstance calendarInstanceForUpdate = this.calendarInstanceRepository.findByCalendarAndEntityIdAndEntityTypeId(calendarId, entityId, entityTypeId);
|
||||
final CalendarInstance calendarInstanceForUpdate = this.calendarInstanceRepository.findByCalendarIdAndEntityIdAndEntityTypeId(calendarId, entityId, entityTypeId);
|
||||
this.calendarInstanceRepository.saveAndFlush(calendarInstanceForUpdate);
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(null) //
|
||||
|
||||
@@ -468,4 +468,13 @@ public final class Client extends AbstractPersistable<Long> {
|
||||
public boolean isActivatedAfter(final LocalDate submittedOn) {
|
||||
return getActivationLocalDate().isAfter(submittedOn);
|
||||
}
|
||||
|
||||
public boolean isChildOfGroup(final Long groupId) {
|
||||
if (groupId != null && this.groups != null && !this.groups.isEmpty()) {
|
||||
for (Group group : this.groups) {
|
||||
if (group.getId().equals(groupId)) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -9,5 +9,5 @@ import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
|
||||
public interface ClientRepository extends JpaRepository<Client, Long>, JpaSpecificationExecutor<Client> {
|
||||
// no added behaviour
|
||||
// no added behaviour
|
||||
}
|
||||
+2
@@ -28,6 +28,8 @@ public interface ClientReadPlatformService {
|
||||
Collection<ClientData> retrieveClientMembersOfGroup(Long groupId);
|
||||
|
||||
Collection<ClientData> retrieveActiveClientMembersOfGroup(Long groupId);
|
||||
|
||||
Collection<ClientData> retrieveActiveClientMembersOfCenter(final Long centerId);
|
||||
|
||||
ClientData retrieveAllClosureReasons(String clientClosureReason);
|
||||
}
|
||||
+14
@@ -298,6 +298,20 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ClientData> retrieveActiveClientMembersOfCenter(final Long centerId) {
|
||||
|
||||
final AppUser currentUser = context.authenticatedUser();
|
||||
final String hierarchy = currentUser.getOffice().getHierarchy();
|
||||
final String hierarchySearchString = hierarchy + "%";
|
||||
|
||||
final String sql = "select " + this.membersOfGroupMapper.schema()
|
||||
+ " left join m_group g on pgc.group_id=g.id where o.hierarchy like ? and g.parent_id = ? and c.status_enum = ? group by c.id";
|
||||
|
||||
return this.jdbcTemplate.query(sql, this.membersOfGroupMapper,
|
||||
new Object[] { hierarchySearchString, centerId, ClientStatus.ACTIVE.getValue() });
|
||||
}
|
||||
|
||||
private static final class ClientMapper implements RowMapper<ClientData> {
|
||||
|
||||
private final String schema;
|
||||
|
||||
+2
-1
@@ -216,9 +216,10 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
|
||||
+ "JOIN m_client cl ON cl.id = gc.client_id "
|
||||
+ "LEFT JOIN m_loan ln ON cl.id = ln.client_id AND ln.group_id is not null AND ( ln.loan_status_id = 300 OR ( ln.loan_status_id =200 AND ln.expected_disbursedon_date <= :dueDate )) "
|
||||
+ "LEFT JOIN m_product_loan pl ON pl.id = ln.product_id "
|
||||
+ "JOIN m_currency rc on rc.`code` = ln.currency_code "
|
||||
+ "LEFT JOIN m_currency rc on rc.`code` = ln.currency_code "
|
||||
+ "LEFT JOIN m_loan_repayment_schedule ls ON ls.loan_id = ln.id AND ls.completed_derived = 0 AND ls.duedate <= :dueDate "
|
||||
+ "LEFT JOIN m_loan_charge lc ON lc.loan_id = ln.id AND lc.is_paid_derived = 0 AND ( lc.due_for_collection_as_of_date <= :dueDate OR lc.charge_time_enum = 1) ";
|
||||
|
||||
// + "WHERE gp.hierarchy like :hierarchy " +
|
||||
// "GROUP BY gp.id ,cl.id , ln.id " +
|
||||
// "ORDER BY gp.id , cl.id , ln.id ";
|
||||
|
||||
+18
-3
@@ -6,6 +6,7 @@
|
||||
package org.mifosplatform.portfolio.group.api;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -38,9 +39,13 @@ import org.mifosplatform.infrastructure.core.service.Page;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.portfolio.accountdetails.data.AccountSummaryCollectionData;
|
||||
import org.mifosplatform.portfolio.accountdetails.service.AccountDetailsReadPlatformService;
|
||||
import org.mifosplatform.portfolio.calendar.data.CalendarData;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
|
||||
import org.mifosplatform.portfolio.calendar.service.CalendarReadPlatformService;
|
||||
import org.mifosplatform.portfolio.collectionsheet.data.JLGCollectionSheetData;
|
||||
import org.mifosplatform.portfolio.collectionsheet.service.CollectionSheetReadPlatformService;
|
||||
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.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -64,6 +69,7 @@ public class CentersApiResource {
|
||||
private final CollectionSheetReadPlatformService collectionSheetReadPlatformService;
|
||||
private final FromJsonHelper fromJsonHelper;
|
||||
private final AccountDetailsReadPlatformService accountDetailsReadPlatformService;
|
||||
private final CalendarReadPlatformService calendarReadPlatformService;
|
||||
|
||||
@Autowired
|
||||
public CentersApiResource(final PlatformSecurityContext context, final CenterReadPlatformService centerReadPlatformService,
|
||||
@@ -72,7 +78,7 @@ public class CentersApiResource {
|
||||
final ApiRequestParameterHelper apiRequestParameterHelper,
|
||||
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
|
||||
final CollectionSheetReadPlatformService collectionSheetReadPlatformService, final FromJsonHelper fromJsonHelper,
|
||||
final AccountDetailsReadPlatformService accountDetailsReadPlatformService) {
|
||||
final AccountDetailsReadPlatformService accountDetailsReadPlatformService, final CalendarReadPlatformService calendarReadPlatformService) {
|
||||
this.context = context;
|
||||
this.centerReadPlatformService = centerReadPlatformService;
|
||||
this.centerApiJsonSerializer = centerApiJsonSerializer;
|
||||
@@ -83,6 +89,7 @@ public class CentersApiResource {
|
||||
this.collectionSheetReadPlatformService = collectionSheetReadPlatformService;
|
||||
this.fromJsonHelper = fromJsonHelper;
|
||||
this.accountDetailsReadPlatformService = accountDetailsReadPlatformService;
|
||||
this.calendarReadPlatformService = calendarReadPlatformService;
|
||||
}
|
||||
|
||||
@GET
|
||||
@@ -126,7 +133,8 @@ public class CentersApiResource {
|
||||
|
||||
this.context.authenticatedUser().validateHasReadPermission(GroupingTypesApiConstants.CENTER_RESOURCE_NAME);
|
||||
final Set<String> associationParameters = ApiParameterHelper.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters());
|
||||
|
||||
CalendarData collectionMeetingCalendar = null;
|
||||
Collection<GroupGeneralData> groups = null;
|
||||
CenterData center = this.centerReadPlatformService.retrieveOne(centerId);
|
||||
|
||||
final boolean template = ApiParameterHelper.template(uriInfo.getQueryParameters());
|
||||
@@ -137,9 +145,16 @@ public class CentersApiResource {
|
||||
|
||||
if (!associationParameters.isEmpty()) {
|
||||
if (associationParameters.contains("groupMembers")) {
|
||||
center = CenterData.setGroups(center, this.centerReadPlatformService.retrieveAssociatedGroups(centerId));
|
||||
groups = this.centerReadPlatformService.retrieveAssociatedGroups(centerId);
|
||||
}
|
||||
|
||||
if (associationParameters.contains("collectionMeetingCalendar")) {
|
||||
collectionMeetingCalendar = this.calendarReadPlatformService.retrieveCollctionCalendarByEntity(centerId, CalendarEntityType.CENTERS.getValue());
|
||||
}
|
||||
|
||||
center = CenterData.withAssociations(center, groups, collectionMeetingCalendar);
|
||||
}
|
||||
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.centerApiJsonSerializer.serialize(settings, center, GroupingTypesApiConstants.CENTER_RESPONSE_DATA_PARAMETERS);
|
||||
|
||||
+2
-1
@@ -52,6 +52,7 @@ public class GroupingTypesApiConstants {
|
||||
public static final String officeOptionsParamName = "officeOptions";
|
||||
public static final String staffOptionsParamName = "staffOptions";
|
||||
public static final String clientOptionsParamName = "clientOptions";
|
||||
public static final String collectionMeetingCalendar = "collectionMeetingCalendar";
|
||||
|
||||
public static final Set<String> CENTER_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
|
||||
dateFormatParamName, idParamName, nameParamName, externalIdParamName, officeIdParamName, staffIdParamName, activeParamName,
|
||||
@@ -59,7 +60,7 @@ public class GroupingTypesApiConstants {
|
||||
|
||||
public static final Set<String> GROUP_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName, dateFormatParamName,
|
||||
idParamName, nameParamName, externalIdParamName, centerIdParamName, officeIdParamName, staffIdParamName, activeParamName,
|
||||
activationDateParamName, clientMembersParamName));
|
||||
activationDateParamName, clientMembersParamName, collectionMeetingCalendar));
|
||||
|
||||
public static final Set<String> GROUP_ROLES_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(roleParamName, clientIdParamName));
|
||||
|
||||
|
||||
+32
-10
@@ -8,6 +8,7 @@ package org.mifosplatform.portfolio.group.api;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
@@ -40,6 +41,10 @@ import org.mifosplatform.infrastructure.core.service.Page;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.portfolio.accountdetails.data.AccountSummaryCollectionData;
|
||||
import org.mifosplatform.portfolio.accountdetails.service.AccountDetailsReadPlatformService;
|
||||
import org.mifosplatform.portfolio.calendar.data.CalendarData;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
|
||||
import org.mifosplatform.portfolio.calendar.service.CalendarReadPlatformService;
|
||||
import org.mifosplatform.portfolio.calendar.service.CalendarUtils;
|
||||
import org.mifosplatform.portfolio.client.data.ClientData;
|
||||
import org.mifosplatform.portfolio.client.service.ClientReadPlatformService;
|
||||
import org.mifosplatform.portfolio.collectionsheet.data.JLGCollectionSheetData;
|
||||
@@ -75,6 +80,7 @@ public class GroupsApiResource {
|
||||
private final FromJsonHelper fromJsonHelper;
|
||||
private final GroupRolesReadPlatformService groupRolesReadPlatformService;
|
||||
private final AccountDetailsReadPlatformService accountDetailsReadPlatformService;
|
||||
private final CalendarReadPlatformService calendarReadPlatformService;
|
||||
|
||||
@Autowired
|
||||
public GroupsApiResource(final PlatformSecurityContext context, final GroupReadPlatformService groupReadPlatformService,
|
||||
@@ -86,7 +92,8 @@ public class GroupsApiResource {
|
||||
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
|
||||
final CollectionSheetReadPlatformService collectionSheetReadPlatformService, final FromJsonHelper fromJsonHelper,
|
||||
final GroupRolesReadPlatformService groupRolesReadPlatformService,
|
||||
final AccountDetailsReadPlatformService accountDetailsReadPlatformService) {
|
||||
final AccountDetailsReadPlatformService accountDetailsReadPlatformService, final CalendarReadPlatformService calendarReadPlatformService) {
|
||||
|
||||
this.context = context;
|
||||
this.groupReadPlatformService = groupReadPlatformService;
|
||||
this.centerReadPlatformService = centerReadPlatformService;
|
||||
@@ -100,6 +107,7 @@ public class GroupsApiResource {
|
||||
this.fromJsonHelper = fromJsonHelper;
|
||||
this.groupRolesReadPlatformService = groupRolesReadPlatformService;
|
||||
this.accountDetailsReadPlatformService = accountDetailsReadPlatformService;
|
||||
this.calendarReadPlatformService = calendarReadPlatformService;
|
||||
}
|
||||
|
||||
@GET
|
||||
@@ -162,9 +170,12 @@ public class GroupsApiResource {
|
||||
Collection<ClientData> membersOfGroup = null;
|
||||
Collection<GroupRoleData> groupRoles = null;
|
||||
GroupRoleData selectedRole = null;
|
||||
Collection<CalendarData> calendars = null;
|
||||
CalendarData collectionMeetingCalendar = null;
|
||||
|
||||
if (!associationParameters.isEmpty()) {
|
||||
if (associationParameters.contains("all")) {
|
||||
associationParameters.addAll(Arrays.asList("clientMembers", "groupRoles"));
|
||||
associationParameters.addAll(Arrays.asList("clientMembers", "groupRoles", "calendars", "collectionMeetingCalendar"));
|
||||
}
|
||||
if (associationParameters.contains("clientMembers")) {
|
||||
membersOfGroup = this.clientReadPlatformService.retrieveClientMembersOfGroup(groupId);
|
||||
@@ -174,25 +185,36 @@ public class GroupsApiResource {
|
||||
}
|
||||
if (associationParameters.contains("groupRoles")) {
|
||||
groupRoles = this.groupRolesReadPlatformService.retrieveGroupRoles(groupId);
|
||||
if (CollectionUtils.isEmpty(membersOfGroup)) {
|
||||
if (CollectionUtils.isEmpty(groupRoles)) {
|
||||
groupRoles = null;
|
||||
}
|
||||
}
|
||||
if (roleId != null) {
|
||||
selectedRole = this.groupRolesReadPlatformService.retrieveGroupRole(groupId, roleId);
|
||||
if (selectedRole != null) {
|
||||
group = GroupGeneralData.updateSelectedRole(group, selectedRole);
|
||||
if (associationParameters.contains("calendars")) {
|
||||
final List<Integer> calendarTypeOptions = CalendarUtils.createIntegerListFromQueryParameter("all");
|
||||
calendars = this.calendarReadPlatformService.retrieveParentCalendarsByEntity(groupId, CalendarEntityType.GROUPS.getValue(), calendarTypeOptions);
|
||||
if (CollectionUtils.isEmpty(calendars)) {
|
||||
calendars = null;
|
||||
}
|
||||
}
|
||||
if (associationParameters.contains("collectionMeetingCalendar")) {
|
||||
collectionMeetingCalendar = this.calendarReadPlatformService.retrieveCollctionCalendarByEntity(groupId, CalendarEntityType.GROUPS.getValue());
|
||||
}
|
||||
|
||||
group = GroupGeneralData.withAssocations(group, membersOfGroup, groupRoles, calendars, collectionMeetingCalendar);
|
||||
}
|
||||
|
||||
if (roleId != null) {
|
||||
selectedRole = this.groupRolesReadPlatformService.retrieveGroupRole(groupId, roleId);
|
||||
if (selectedRole != null) {
|
||||
group = GroupGeneralData.updateSelectedRole(group, selectedRole);
|
||||
}
|
||||
}
|
||||
|
||||
final boolean template = ApiParameterHelper.template(uriInfo.getQueryParameters());
|
||||
if (template) {
|
||||
final GroupGeneralData templateGroup = this.groupReadPlatformService.retrieveTemplate(group.officeId(), false,
|
||||
staffInSelectedOfficeOnly);
|
||||
group = GroupGeneralData.withTemplateAndAssociations(templateGroup, group, membersOfGroup, groupRoles);
|
||||
} else {
|
||||
group = GroupGeneralData.withAssocations(group, membersOfGroup, groupRoles);
|
||||
group = GroupGeneralData.withTemplate(templateGroup, group);
|
||||
}
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
|
||||
+11
-6
@@ -11,6 +11,7 @@ import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.organisation.office.data.OfficeData;
|
||||
import org.mifosplatform.organisation.staff.data.StaffData;
|
||||
import org.mifosplatform.portfolio.calendar.data.CalendarData;
|
||||
|
||||
/**
|
||||
* Immutable data object representing groups.
|
||||
@@ -40,17 +41,19 @@ public class CenterData {
|
||||
private final Collection<OfficeData> officeOptions;
|
||||
private final Collection<StaffData> staffOptions;
|
||||
private final Collection<GroupGeneralData> groupMembersOptions;
|
||||
private final CalendarData collectionMeetingCalendar;
|
||||
|
||||
public static CenterData template(final Long officeId, final LocalDate activationDate, final Collection<OfficeData> officeOptions,
|
||||
final Collection<StaffData> staffOptions, final Collection<GroupGeneralData> groupMembersOptions) {
|
||||
final CalendarData collectionMeetingCalendar = null;
|
||||
return new CenterData(null, null, null, null, activationDate, officeId, null, null, null, null, null, officeOptions, staffOptions,
|
||||
groupMembersOptions);
|
||||
groupMembersOptions, collectionMeetingCalendar);
|
||||
}
|
||||
|
||||
public static CenterData withTemplate(final CenterData templateCenter, final CenterData center) {
|
||||
return new CenterData(center.id, center.name, center.externalId, center.status, center.activationDate, center.officeId,
|
||||
center.officeName, center.staffId, center.staffName, center.hierarchy, center.groupMembers, templateCenter.officeOptions,
|
||||
templateCenter.staffOptions, templateCenter.groupMembersOptions);
|
||||
templateCenter.staffOptions, templateCenter.groupMembersOptions, templateCenter.collectionMeetingCalendar);
|
||||
}
|
||||
|
||||
public static CenterData instance(final Long id, final String name, final String externalId, final EnumOptionData status,
|
||||
@@ -61,21 +64,22 @@ public class CenterData {
|
||||
final Collection<OfficeData> officeOptions = null;
|
||||
final Collection<StaffData> staffOptions = null;
|
||||
final Collection<GroupGeneralData> groupMembersOptions = null;
|
||||
final CalendarData collectionMeetingCalendar = null;
|
||||
|
||||
return new CenterData(id, name, externalId, status, activationDate, officeId, officeName, staffId, staffName, hierarchy,
|
||||
groupMembers, officeOptions, staffOptions, groupMembersOptions);
|
||||
groupMembers, officeOptions, staffOptions, groupMembersOptions, collectionMeetingCalendar);
|
||||
}
|
||||
|
||||
public static CenterData setGroups(final CenterData centerData, final Collection<GroupGeneralData> groupMembers) {
|
||||
public static CenterData withAssociations(final CenterData centerData, final Collection<GroupGeneralData> groupMembers, final CalendarData collectionMeetingCalendar) {
|
||||
return new CenterData(centerData.id, centerData.name, centerData.externalId, centerData.status, centerData.activationDate,
|
||||
centerData.officeId, centerData.officeName, centerData.staffId, centerData.staffName, centerData.hierarchy, groupMembers,
|
||||
centerData.officeOptions, centerData.staffOptions, centerData.groupMembersOptions);
|
||||
centerData.officeOptions, centerData.staffOptions, centerData.groupMembersOptions, collectionMeetingCalendar);
|
||||
}
|
||||
|
||||
private CenterData(final Long id, final String name, final String externalId, final EnumOptionData status,
|
||||
final LocalDate activationDate, final Long officeId, final String officeName, final Long staffId, final String staffName,
|
||||
final String hierarchy, final Collection<GroupGeneralData> groupMembers, final Collection<OfficeData> officeOptions,
|
||||
final Collection<StaffData> staffOptions, final Collection<GroupGeneralData> groupMembersOptions) {
|
||||
final Collection<StaffData> staffOptions, final Collection<GroupGeneralData> groupMembersOptions, final CalendarData collectionMeetingCalendar) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.externalId = externalId;
|
||||
@@ -98,6 +102,7 @@ public class CenterData {
|
||||
this.officeOptions = officeOptions;
|
||||
this.staffOptions = staffOptions;
|
||||
this.groupMembersOptions = groupMembersOptions;
|
||||
this.collectionMeetingCalendar = collectionMeetingCalendar;
|
||||
}
|
||||
|
||||
public Long officeId() {
|
||||
|
||||
+16
-17
@@ -12,6 +12,7 @@ import org.mifosplatform.infrastructure.codes.data.CodeValueData;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.organisation.office.data.OfficeData;
|
||||
import org.mifosplatform.organisation.staff.data.StaffData;
|
||||
import org.mifosplatform.portfolio.calendar.data.CalendarData;
|
||||
import org.mifosplatform.portfolio.client.data.ClientData;
|
||||
|
||||
/**
|
||||
@@ -40,6 +41,8 @@ public class GroupGeneralData {
|
||||
// associations
|
||||
private final Collection<ClientData> clientMembers;
|
||||
private final Collection<GroupRoleData> groupRoles;
|
||||
private final Collection<CalendarData> calendarsData;
|
||||
private final CalendarData collectionMeetingCalendar;
|
||||
|
||||
// template
|
||||
private final Collection<CenterData> centerOptions;
|
||||
@@ -54,7 +57,7 @@ public class GroupGeneralData {
|
||||
final Collection<GroupRoleData> groupRoles = null;
|
||||
|
||||
return new GroupGeneralData(groupId, groupName, null, null, null, null, null, null, null, null, null, null, clientMembers, null,
|
||||
null, null, null, groupRoles, null, null);
|
||||
null, null, null, groupRoles, null, null, null, null);
|
||||
}
|
||||
|
||||
public static GroupGeneralData template(final Long officeId, final Long centerId, final String centerName, final Long staffId,
|
||||
@@ -66,7 +69,7 @@ public class GroupGeneralData {
|
||||
final Collection<GroupRoleData> groupRoles = null;
|
||||
|
||||
return new GroupGeneralData(null, null, null, null, null, officeId, null, centerId, centerName, staffId, staffName, null,
|
||||
clientMembers, centerOptions, officeOptions, staffOptions, clientOptions, groupRoles, availableRoles, null);
|
||||
clientMembers, centerOptions, officeOptions, staffOptions, clientOptions, groupRoles, availableRoles, null, null, null);
|
||||
}
|
||||
|
||||
public static GroupGeneralData withTemplate(final GroupGeneralData templatedGrouping, final GroupGeneralData grouping) {
|
||||
@@ -74,24 +77,15 @@ public class GroupGeneralData {
|
||||
grouping.officeId, grouping.officeName, grouping.centerId, grouping.centerName, grouping.staffId, grouping.staffName,
|
||||
grouping.hierarchy, grouping.clientMembers, templatedGrouping.centerOptions, templatedGrouping.officeOptions,
|
||||
templatedGrouping.staffOptions, templatedGrouping.clientOptions, grouping.groupRoles, templatedGrouping.availableRoles,
|
||||
grouping.selectedRole);
|
||||
}
|
||||
|
||||
public static GroupGeneralData withTemplateAndAssociations(final GroupGeneralData templatedGrouping, final GroupGeneralData grouping,
|
||||
final Collection<ClientData> membersOfGroup, final Collection<GroupRoleData> groupRoles) {
|
||||
return new GroupGeneralData(grouping.id, grouping.name, grouping.externalId, grouping.status, grouping.activationDate,
|
||||
grouping.officeId, grouping.officeName, grouping.centerId, grouping.centerName, grouping.staffId, grouping.staffName,
|
||||
grouping.hierarchy, membersOfGroup, templatedGrouping.centerOptions, templatedGrouping.officeOptions,
|
||||
templatedGrouping.staffOptions, templatedGrouping.clientOptions, groupRoles, templatedGrouping.availableRoles,
|
||||
grouping.selectedRole);
|
||||
grouping.selectedRole, grouping.calendarsData, grouping.collectionMeetingCalendar);
|
||||
}
|
||||
|
||||
public static GroupGeneralData withAssocations(final GroupGeneralData grouping, final Collection<ClientData> membersOfGroup,
|
||||
final Collection<GroupRoleData> groupRoles) {
|
||||
final Collection<GroupRoleData> groupRoles, final Collection<CalendarData> calendarsData, final CalendarData collectionMeetingCalendar) {
|
||||
return new GroupGeneralData(grouping.id, grouping.name, grouping.externalId, grouping.status, grouping.activationDate,
|
||||
grouping.officeId, grouping.officeName, grouping.centerId, grouping.centerName, grouping.staffId, grouping.staffName,
|
||||
grouping.hierarchy, membersOfGroup, grouping.centerOptions, grouping.officeOptions, grouping.staffOptions,
|
||||
grouping.clientOptions, groupRoles, grouping.availableRoles, grouping.selectedRole);
|
||||
grouping.clientOptions, groupRoles, grouping.availableRoles, grouping.selectedRole, calendarsData, collectionMeetingCalendar);
|
||||
}
|
||||
|
||||
public static GroupGeneralData instance(final Long id, final String name, final String externalId, final EnumOptionData status,
|
||||
@@ -106,10 +100,12 @@ public class GroupGeneralData {
|
||||
final Collection<GroupRoleData> groupRoles = null;
|
||||
final Collection<CodeValueData> availableRoles = null;
|
||||
final GroupRoleData role = null;
|
||||
final Collection<CalendarData> calendarsData = null;
|
||||
final CalendarData collectionMeetingCalendar = null;
|
||||
|
||||
return new GroupGeneralData(id, name, externalId, status, activationDate, officeId, officeName, centerId, centerName, staffId,
|
||||
staffName, hierarchy, clientMembers, centerOptions, officeOptions, staffOptions, clientOptions, groupRoles, availableRoles,
|
||||
role);
|
||||
role, calendarsData, collectionMeetingCalendar);
|
||||
}
|
||||
|
||||
private GroupGeneralData(final Long id, final String name, final String externalId, final EnumOptionData status,
|
||||
@@ -117,7 +113,8 @@ public class GroupGeneralData {
|
||||
final Long staffId, final String staffName, final String hierarchy, final Collection<ClientData> clientMembers,
|
||||
final Collection<CenterData> centerOptions, final Collection<OfficeData> officeOptions,
|
||||
final Collection<StaffData> staffOptions, final Collection<ClientData> clientOptions,
|
||||
final Collection<GroupRoleData> groupRoles, final Collection<CodeValueData> availableRoles, final GroupRoleData role) {
|
||||
final Collection<GroupRoleData> groupRoles, final Collection<CodeValueData> availableRoles, final GroupRoleData role,
|
||||
final Collection<CalendarData> calendarsData, final CalendarData collectionMeetingCalendar) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.externalId = externalId;
|
||||
@@ -152,6 +149,8 @@ public class GroupGeneralData {
|
||||
this.groupRoles = groupRoles;
|
||||
this.availableRoles = availableRoles;
|
||||
this.selectedRole = role;
|
||||
this.calendarsData = calendarsData;
|
||||
this.collectionMeetingCalendar = collectionMeetingCalendar;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
@@ -174,7 +173,7 @@ public class GroupGeneralData {
|
||||
return new GroupGeneralData(grouping.id, grouping.name, grouping.externalId, grouping.status, grouping.activationDate,
|
||||
grouping.officeId, grouping.officeName, grouping.centerId, grouping.centerName, grouping.staffId, grouping.staffName,
|
||||
grouping.hierarchy, grouping.clientMembers, grouping.centerOptions, grouping.officeOptions, grouping.staffOptions,
|
||||
grouping.clientOptions, grouping.groupRoles, grouping.availableRoles, selectedRole);
|
||||
grouping.clientOptions, grouping.groupRoles, grouping.availableRoles, selectedRole, grouping.calendarsData, grouping.collectionMeetingCalendar);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -384,4 +384,13 @@ public final class Group extends AbstractPersistable<Long> {
|
||||
public boolean isCenter() {
|
||||
return this.groupLevel.isCenter();
|
||||
}
|
||||
|
||||
public boolean isChildClient(final Long clientId){
|
||||
if (clientId != null && this.clientMembers != null && !this.clientMembers.isEmpty()) {
|
||||
for (Client client : this.clientMembers) {
|
||||
if(client.getId().equals(clientId)) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -5,9 +5,11 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.group.domain;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
|
||||
public interface GroupRepository extends JpaRepository<Group, Long>, JpaSpecificationExecutor<Group> {
|
||||
|
||||
Collection<Group> findByParentId(Long parentId);
|
||||
}
|
||||
|
||||
+6
-2
@@ -10,8 +10,12 @@ import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRul
|
||||
public class ClientNotInGroupException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public ClientNotInGroupException(final Long clientId, final Long groupId) {
|
||||
super("error.msg.group.client.not.in.group", "Client with identifier " + clientId + " is not in Group with identifier " + groupId,
|
||||
clientId, groupId);
|
||||
this("group.client.not.in.group", "Client with identifier " + clientId + " is not in Group with identifier " + groupId, clientId, groupId);
|
||||
|
||||
}
|
||||
|
||||
public ClientNotInGroupException(String postFix, String defaultUserMessage, Object... defaultUserMessageArgs) {
|
||||
super("error.msg." + postFix , defaultUserMessage, defaultUserMessageArgs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+21
-15
@@ -56,7 +56,7 @@ import org.mifosplatform.organisation.staff.domain.Staff;
|
||||
import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
|
||||
import org.mifosplatform.organisation.workingdays.service.WorkingDaysUtil;
|
||||
import org.mifosplatform.portfolio.accountdetails.domain.AccountType;
|
||||
import org.mifosplatform.portfolio.calendar.service.CalendarHelper;
|
||||
import org.mifosplatform.portfolio.calendar.service.CalendarUtils;
|
||||
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeAddedException;
|
||||
import org.mifosplatform.portfolio.client.domain.Client;
|
||||
import org.mifosplatform.portfolio.collateral.data.CollateralData;
|
||||
@@ -2387,41 +2387,47 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
|
||||
public void updateLoanRepaymentScheduleDates(final LocalDate meetingStartDate, final String recuringRule,
|
||||
final boolean isHolidayEnabled, final List<Holiday> holidays, final WorkingDays workingDays) {
|
||||
//update repayment dates of repayment schedule installaments
|
||||
LocalDate tmpFromDate = this.getDisbursementDate();//first repayment's from date is same as disbursement date.
|
||||
|
||||
//first repayment's from date is same as disbursement date.
|
||||
LocalDate tmpFromDate = this.getDisbursementDate();
|
||||
final PeriodFrequencyType repaymentPeriodFrequencyType = this.loanRepaymentScheduleDetail.getRepaymentPeriodFrequencyType();
|
||||
final Integer loanRepaymentInterval = this.loanRepaymentScheduleDetail.getRepayEvery();
|
||||
final String frequency = CalendarHelper.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType);
|
||||
final String frequency = CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType);
|
||||
|
||||
LocalDate newRepaymentDate = null;
|
||||
for (final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : this.repaymentScheduleInstallments) {
|
||||
final LocalDate oldDueDate = loanRepaymentScheduleInstallment.getDueDate();
|
||||
// FIXME: AA this won't update repayment dates before current date.
|
||||
if (oldDueDate.isAfter(meetingStartDate) && oldDueDate.isAfter(DateUtils.getLocalDateOfTenant())) {
|
||||
|
||||
newRepaymentDate = CalendarHelper.getNewRepaymentMeetingDate(recuringRule, meetingStartDate, oldDueDate,
|
||||
newRepaymentDate = CalendarUtils.getNewRepaymentMeetingDate(recuringRule, meetingStartDate, oldDueDate,
|
||||
loanRepaymentInterval, frequency, workingDays);
|
||||
|
||||
final LocalDate maxDateLimitForNewRepayment = getMaxDateLimitForNewRepayment(repaymentPeriodFrequencyType,
|
||||
loanRepaymentInterval, tmpFromDate);
|
||||
|
||||
if (newRepaymentDate.isAfter(maxDateLimitForNewRepayment)) {
|
||||
newRepaymentDate = CalendarHelper.getNextRepaymentMeetingDate(recuringRule, meetingStartDate, tmpFromDate,
|
||||
newRepaymentDate = CalendarUtils.getNextRepaymentMeetingDate(recuringRule, meetingStartDate, tmpFromDate,
|
||||
loanRepaymentInterval, frequency, workingDays);
|
||||
}
|
||||
|
||||
if (isHolidayEnabled) {
|
||||
newRepaymentDate = HolidayUtil.getRepaymentRescheduleDateToIfHoliday(newRepaymentDate, holidays);
|
||||
// reset repayment date with new meeting date
|
||||
newRepaymentDate = CalendarUtils.getNewRepaymentMeetingDate(recuringRule, meetingStartDate, oldDueDate,
|
||||
loanRepaymentInterval, frequency, workingDays);
|
||||
if (isHolidayEnabled) {
|
||||
newRepaymentDate = HolidayUtil.getRepaymentRescheduleDateToIfHoliday(newRepaymentDate, holidays);
|
||||
}
|
||||
|
||||
loanRepaymentScheduleInstallment.updateDueDate(newRepaymentDate);
|
||||
// reset from date to get actual daysInPeriod
|
||||
loanRepaymentScheduleInstallment.updateFromDate(tmpFromDate);
|
||||
tmpFromDate = newRepaymentDate;// update with new repayment
|
||||
// date
|
||||
} else {
|
||||
tmpFromDate = oldDueDate;
|
||||
}
|
||||
|
||||
loanRepaymentScheduleInstallment.updateDueDate(newRepaymentDate);
|
||||
// reset from date to get actual daysInPeriod
|
||||
loanRepaymentScheduleInstallment.updateFromDate(tmpFromDate);
|
||||
tmpFromDate = newRepaymentDate;// update with new repayment date
|
||||
} else {
|
||||
tmpFromDate = oldDueDate;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+7
-7
@@ -28,7 +28,7 @@ import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarRepository;
|
||||
import org.mifosplatform.portfolio.calendar.exception.CalendarNotFoundException;
|
||||
import org.mifosplatform.portfolio.calendar.exception.MeetingFrequencyMismatchException;
|
||||
import org.mifosplatform.portfolio.calendar.service.CalendarHelper;
|
||||
import org.mifosplatform.portfolio.calendar.service.CalendarUtils;
|
||||
import org.mifosplatform.portfolio.client.domain.Client;
|
||||
import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper;
|
||||
import org.mifosplatform.portfolio.group.domain.Group;
|
||||
@@ -149,9 +149,9 @@ public class LoanScheduleAssembler {
|
||||
if (calendar == null) { throw new CalendarNotFoundException(calendarId); }
|
||||
|
||||
// validate repayment frequency and interval with meeting frequency and interval
|
||||
PeriodFrequencyType meetingPeriodFrequency = CalendarHelper.getMeetingPeriodFrequencyType(calendar.getRecurrence());
|
||||
PeriodFrequencyType meetingPeriodFrequency = CalendarUtils.getMeetingPeriodFrequencyType(calendar.getRecurrence());
|
||||
validateRepaymentFrequencyIsSameAsMeetingFrequency(meetingPeriodFrequency.getValue(), repaymentFrequencyType,
|
||||
CalendarHelper.getInterval(calendar.getRecurrence()), repaymentEvery);
|
||||
CalendarUtils.getInterval(calendar.getRecurrence()), repaymentEvery);
|
||||
}
|
||||
|
||||
if (synchDisbursement != null && synchDisbursement.booleanValue()) {
|
||||
@@ -166,8 +166,8 @@ public class LoanScheduleAssembler {
|
||||
if (calculatedRepaymentsStartingFromDate == null) {
|
||||
// FIXME: AA - Possibility of having next meeting date immediately after disbursement date,
|
||||
// need to have minimum number of days gap between disbursement and first repayment date.
|
||||
final String frequency = CalendarHelper.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType);
|
||||
calculatedRepaymentsStartingFromDate = CalendarHelper.getFirstRepaymentMeetingDate(calendar, expectedDisbursementDate,
|
||||
final String frequency = CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType);
|
||||
calculatedRepaymentsStartingFromDate = CalendarUtils.getFirstRepaymentMeetingDate(calendar, expectedDisbursementDate,
|
||||
repaymentEvery, frequency);
|
||||
} else {// validate user provided repaymentsStartFromDate
|
||||
validateRepaymentsStartDateWithMeetingDates(repaymentsStartingFromDate, calendar);
|
||||
@@ -192,7 +192,7 @@ public class LoanScheduleAssembler {
|
||||
|
||||
private void validateRepaymentsStartDateWithMeetingDates(final LocalDate repaymentsStartingFromDate, final Calendar calendar) {
|
||||
if (repaymentsStartingFromDate != null
|
||||
&& !CalendarHelper.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(),
|
||||
&& !CalendarUtils.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(),
|
||||
repaymentsStartingFromDate)) {
|
||||
final String errorMessage = "First repayment date '" + repaymentsStartingFromDate + "' do not fall on a meeting date";
|
||||
throw new LoanApplicationDateException("first.repayment.date.do.not.match.meeting.date", errorMessage,
|
||||
@@ -202,7 +202,7 @@ public class LoanScheduleAssembler {
|
||||
|
||||
private void validateDisbursementDateWithMeetingDates(final LocalDate expectedDisbursementDate, final Calendar calendar) {
|
||||
// disbursement date should fall on a meeting date
|
||||
if (!CalendarHelper.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(), expectedDisbursementDate)) {
|
||||
if (!CalendarUtils.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(), 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);
|
||||
}
|
||||
|
||||
+3
-3
@@ -24,7 +24,7 @@ import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
||||
import org.mifosplatform.portfolio.calendar.exception.NotValidRecurringDateException;
|
||||
import org.mifosplatform.portfolio.calendar.service.CalendarHelper;
|
||||
import org.mifosplatform.portfolio.calendar.service.CalendarUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -76,7 +76,7 @@ public final class LoanEventApiJsonValidator {
|
||||
Calendar calendar = calendarInstance.getCalendar();
|
||||
if (calendar != null && actualDisbursementDate != null) {
|
||||
// Disbursement date should fall on a meeting date
|
||||
if (!CalendarHelper.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(), actualDisbursementDate)) {
|
||||
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(),
|
||||
@@ -147,7 +147,7 @@ public final class LoanEventApiJsonValidator {
|
||||
Calendar calendar = calendarInstance.getCalendar();
|
||||
if (calendar != null && repaymentDate != null) {
|
||||
// Disbursement date should fall on a meeting date
|
||||
if (!CalendarHelper.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(), repaymentDate)) {
|
||||
if (!CalendarUtils.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(), repaymentDate)) {
|
||||
final String errorMessage = "Transaction date '" + repaymentDate.toString()
|
||||
+ "' does not fall on a meeting date.";
|
||||
throw new NotValidRecurringDateException("loan.transaction.date", errorMessage, repaymentDate.toString(),
|
||||
|
||||
+9
-2
@@ -41,6 +41,7 @@ import org.mifosplatform.portfolio.client.service.ClientReadPlatformService;
|
||||
import org.mifosplatform.portfolio.fund.data.FundData;
|
||||
import org.mifosplatform.portfolio.fund.service.FundReadPlatformService;
|
||||
import org.mifosplatform.portfolio.group.data.GroupGeneralData;
|
||||
import org.mifosplatform.portfolio.group.data.GroupRoleData;
|
||||
import org.mifosplatform.portfolio.group.service.GroupReadPlatformService;
|
||||
import org.mifosplatform.portfolio.group.service.SearchParameters;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.DisbursementData;
|
||||
@@ -280,7 +281,10 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
// get group associations
|
||||
Collection<ClientData> membersOfGroup = this.clientReadPlatformService.retrieveClientMembersOfGroup(groupId);
|
||||
if (!CollectionUtils.isEmpty(membersOfGroup)) {
|
||||
groupAccount = GroupGeneralData.withAssocations(groupAccount, membersOfGroup, null);
|
||||
final Collection<CalendarData> calendarsData = null;
|
||||
final CalendarData collectionMeetingCalendar = null;
|
||||
final Collection<GroupRoleData> groupRoles = null;
|
||||
groupAccount = GroupGeneralData.withAssocations(groupAccount, membersOfGroup, groupRoles, calendarsData, collectionMeetingCalendar);
|
||||
}
|
||||
|
||||
final LocalDate expectedDisbursementDate = DateUtils.getLocalDateOfTenant();
|
||||
@@ -958,7 +962,10 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
// get group associations
|
||||
Collection<ClientData> membersOfGroup = this.clientReadPlatformService.retrieveActiveClientMembersOfGroup(groupId);
|
||||
if (!CollectionUtils.isEmpty(membersOfGroup)) {
|
||||
groupAccount = GroupGeneralData.withAssocations(groupAccount, membersOfGroup, null);
|
||||
final Collection<CalendarData> calendarsData = null;
|
||||
final CalendarData collectionMeetingCalendar = null;
|
||||
final Collection<GroupRoleData> groupRoles = null;
|
||||
groupAccount = GroupGeneralData.withAssocations(groupAccount, membersOfGroup, groupRoles, calendarsData, collectionMeetingCalendar);
|
||||
}
|
||||
|
||||
return LoanAccountData.groupDefaults(groupAccount, expectedDisbursementDate);
|
||||
|
||||
+3
-3
@@ -39,7 +39,7 @@ import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarInstanceRepository;
|
||||
import org.mifosplatform.portfolio.calendar.service.CalendarHelper;
|
||||
import org.mifosplatform.portfolio.calendar.service.CalendarUtils;
|
||||
import org.mifosplatform.portfolio.charge.domain.Charge;
|
||||
import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper;
|
||||
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeDeletedException;
|
||||
@@ -244,9 +244,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
if (repaymentScheduleDetails != null) {// Not expecting to be
|
||||
// null
|
||||
final Integer repayEvery = repaymentScheduleDetails.getRepayEvery();
|
||||
final String frequency = CalendarHelper.getMeetingFrequencyFromPeriodFrequencyType(repaymentScheduleDetails
|
||||
final String frequency = CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(repaymentScheduleDetails
|
||||
.getRepaymentPeriodFrequencyType());
|
||||
calculatedRepaymentsStartingFromDate = CalendarHelper.getFirstRepaymentMeetingDate(calendar, actualDisbursementDate, repayEvery,
|
||||
calculatedRepaymentsStartingFromDate = CalendarUtils.getFirstRepaymentMeetingDate(calendar, actualDisbursementDate, repayEvery,
|
||||
frequency);
|
||||
}
|
||||
}
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* 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.meeting;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class MeetingApiConstants {
|
||||
|
||||
public static final String MEETING_RESOURCE_NAME = "meeting";
|
||||
|
||||
// general
|
||||
public static final String localeParamName = "locale";
|
||||
public static final String dateFormatParamName = "dateFormat";
|
||||
|
||||
// meetings parameters
|
||||
public static final String idParamName = "id";
|
||||
public static final String meetingDateParamName = "meetingDate";
|
||||
public static final String calendarIdParamName = "calendarId";
|
||||
public static final String clientsAttendanceParamName = "clientsAttendance";
|
||||
|
||||
// attendance parameters
|
||||
public static final String clientIdParamName = "clientId";
|
||||
public static final String attendanceTypeParamName = "attendanceType";
|
||||
|
||||
// attendance response parameters
|
||||
public static final String clientsAttendance = "clientsAttendance";
|
||||
|
||||
// template response parameters
|
||||
public static final String clients = "clients";
|
||||
public static final String calendarData = "calendarData";
|
||||
public static final String attendanceTypeOptions = "attendanceTypeOptions";
|
||||
|
||||
public static final Set<String> MEETING_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(meetingDateParamName,
|
||||
localeParamName, dateFormatParamName, calendarIdParamName, clientsAttendanceParamName));
|
||||
|
||||
public static final Set<String> MEETING_RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(idParamName, meetingDateParamName,
|
||||
clientsAttendance, clients, calendarData, attendanceTypeOptions));
|
||||
|
||||
}
|
||||
+221
@@ -0,0 +1,221 @@
|
||||
/**
|
||||
* 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.meeting.api;
|
||||
|
||||
import static org.mifosplatform.portfolio.meeting.MeetingApiConstants.MEETING_RESOURCE_NAME;
|
||||
import static org.mifosplatform.portfolio.meeting.MeetingApiConstants.MEETING_RESPONSE_DATA_PARAMETERS;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.mifosplatform.commands.domain.CommandWrapper;
|
||||
import org.mifosplatform.commands.service.CommandWrapperBuilder;
|
||||
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.exception.UnrecognizedQueryParamException;
|
||||
import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
|
||||
import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.portfolio.calendar.data.CalendarData;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
|
||||
import org.mifosplatform.portfolio.calendar.service.CalendarReadPlatformService;
|
||||
import org.mifosplatform.portfolio.client.data.ClientData;
|
||||
import org.mifosplatform.portfolio.client.service.ClientReadPlatformService;
|
||||
import org.mifosplatform.portfolio.meeting.attendance.data.ClientAttendanceData;
|
||||
import org.mifosplatform.portfolio.meeting.attendance.service.AttendanceDropdownReadPlatformService;
|
||||
import org.mifosplatform.portfolio.meeting.attendance.service.ClientAttendanceReadPlatformService;
|
||||
import org.mifosplatform.portfolio.meeting.data.MeetingData;
|
||||
import org.mifosplatform.portfolio.meeting.exception.MeetingNotSupportedResourceException;
|
||||
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;
|
||||
|
||||
@Path("/{entityType}/{entityId}/meetings")
|
||||
@Component
|
||||
@Scope("singleton")
|
||||
public class MeetingsApiResource {
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final MeetingReadPlatformService readPlatformService;
|
||||
private final ClientAttendanceReadPlatformService attendanceReadPlatformService;
|
||||
private final ClientReadPlatformService clientReadPlatformService;
|
||||
private final CalendarReadPlatformService calendarReadPlatformService;
|
||||
private final AttendanceDropdownReadPlatformService attendanceDropdownReadPlatformService;
|
||||
private final DefaultToApiJsonSerializer<MeetingData> toApiJsonSerializer;
|
||||
private final ApiRequestParameterHelper apiRequestParameterHelper;
|
||||
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
|
||||
|
||||
@Autowired
|
||||
public MeetingsApiResource(PlatformSecurityContext context, MeetingReadPlatformService readPlatformService,
|
||||
ClientAttendanceReadPlatformService attendanceReadPlatformService, final ClientReadPlatformService clientReadPlatformService,
|
||||
final CalendarReadPlatformService calendarReadPlatformService,
|
||||
final AttendanceDropdownReadPlatformService attendanceDropdownReadPlatformService,
|
||||
DefaultToApiJsonSerializer<MeetingData> toApiJsonSerializer, ApiRequestParameterHelper apiRequestParameterHelper,
|
||||
PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) {
|
||||
this.context = context;
|
||||
this.readPlatformService = readPlatformService;
|
||||
this.attendanceReadPlatformService = attendanceReadPlatformService;
|
||||
this.clientReadPlatformService = clientReadPlatformService;
|
||||
this.calendarReadPlatformService = calendarReadPlatformService;
|
||||
this.attendanceDropdownReadPlatformService = attendanceDropdownReadPlatformService;
|
||||
this.toApiJsonSerializer = toApiJsonSerializer;
|
||||
this.apiRequestParameterHelper = apiRequestParameterHelper;
|
||||
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("template")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String template(@PathParam("entityType") final String entityType, @PathParam("entityId") final Long entityId,
|
||||
@QueryParam("calendarId") Long calendarId, @Context final UriInfo uriInfo) {
|
||||
|
||||
this.context.authenticatedUser().validateHasReadPermission(MEETING_RESOURCE_NAME);
|
||||
final Integer entityTypeId = CalendarEntityType.valueOf(entityType.toUpperCase()).getValue();
|
||||
Collection<ClientData> clients = null;
|
||||
CalendarData calendarData = null;
|
||||
|
||||
if (CalendarEntityType.isGroup(entityType)) {
|
||||
clients = this.clientReadPlatformService.retrieveActiveClientMembersOfGroup(entityId);
|
||||
} else if (CalendarEntityType.isCenter(entityType)) {
|
||||
clients = this.clientReadPlatformService.retrieveActiveClientMembersOfCenter(entityId);
|
||||
} else {
|
||||
final String defaultUserMessage = "Meeting attendance is not supported for the resource " + entityType
|
||||
+ ". The supported resources are [" + CalendarEntityType.GROUPS.name() + ", " + CalendarEntityType.CENTERS.name() + "]";
|
||||
throw new MeetingNotSupportedResourceException(defaultUserMessage, CalendarEntityType.GROUPS.name(), CalendarEntityType.CENTERS.name());
|
||||
}
|
||||
|
||||
if (calendarId != null) {
|
||||
calendarData = this.calendarReadPlatformService.retrieveCalendar(calendarId, entityId, entityTypeId);
|
||||
calendarData = this.calendarReadPlatformService.generateRecurringDate(calendarData, DateUtils.getLocalDateOfTenant());
|
||||
}
|
||||
|
||||
final MeetingData meetingData = MeetingData.template(clients, calendarData,
|
||||
attendanceDropdownReadPlatformService.retrieveAttendanceTypeOptions());
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.toApiJsonSerializer.serialize(settings, meetingData, MEETING_RESPONSE_DATA_PARAMETERS);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveMeetings(@PathParam("entityType") final String entityType, @PathParam("entityId") final Long entityId,
|
||||
@QueryParam("limit") final Integer limit, @Context final UriInfo uriInfo) {
|
||||
|
||||
this.context.authenticatedUser().validateHasReadPermission(MEETING_RESOURCE_NAME);
|
||||
|
||||
final Collection<MeetingData> meetingsData = this.readPlatformService.retrieveMeetingsByEntity(entityId, CalendarEntityType
|
||||
.valueOf(entityType.toUpperCase()).getValue(), limit);
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.toApiJsonSerializer.serialize(settings, meetingsData, MEETING_RESPONSE_DATA_PARAMETERS);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{meetingId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveMeeting(@PathParam("meetingId") final Long meetingId, @PathParam("entityType") final String entityType,
|
||||
@PathParam("entityId") final Long entityId, @Context final UriInfo uriInfo) {
|
||||
|
||||
this.context.authenticatedUser().validateHasReadPermission(MEETING_RESOURCE_NAME);
|
||||
final Integer entityTypeId = CalendarEntityType.valueOf(entityType.toUpperCase()).getValue();
|
||||
MeetingData meetingData = this.readPlatformService.retrieveMeeting(meetingId, entityId, entityTypeId);
|
||||
final Collection<ClientAttendanceData> clientsAttendance = this.attendanceReadPlatformService
|
||||
.retrieveClientAttendanceByMeetingId(meetingId);
|
||||
meetingData = MeetingData.withClientsAttendanceAndAttendanceTypeOptions(meetingData, clientsAttendance,
|
||||
attendanceDropdownReadPlatformService.retrieveAttendanceTypeOptions());
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.toApiJsonSerializer.serialize(settings, meetingData, MEETING_RESPONSE_DATA_PARAMETERS);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String createMeeting(@PathParam("entityType") final String entityType, @PathParam("entityId") final Long entityId,
|
||||
final String apiRequestBodyAsJson) {
|
||||
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().createMeeting(entityType, entityId)
|
||||
.withJson(apiRequestBodyAsJson).build();
|
||||
|
||||
CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("{meetingId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String performMeetingCommands(@PathParam("entityType") final String entityType, @PathParam("entityId") final Long entityId,
|
||||
@PathParam("meetingId") final Long meetingId, @QueryParam("command") final String commandParam,
|
||||
final String apiRequestBodyAsJson) {
|
||||
|
||||
final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson);
|
||||
|
||||
CommandProcessingResult result = null;
|
||||
if (is(commandParam, "saveOrUpdateAttendance")) {
|
||||
final CommandWrapper commandRequest = builder.saveOrUpdateAttendance(meetingId, entityType, entityId).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
} else {
|
||||
throw new UnrecognizedQueryParamException("command", commandParam, new Object[] { "saveOrUpdateAttendance" });
|
||||
}
|
||||
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("{meetingId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String updateMeeting(@PathParam("entityType") final String entityType, @PathParam("entityId") final Long entityId,
|
||||
@PathParam("meetingId") final Long meetingId, final String jsonRequestBody) {
|
||||
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateMeeting(entityType, entityId, meetingId)
|
||||
.withJson(jsonRequestBody).build();
|
||||
|
||||
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("{meetingId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String deleteMeeting(@PathParam("entityType") final String entityType, @PathParam("entityId") final Long entityId,
|
||||
@PathParam("meetingId") final Long meetingId) {
|
||||
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteMeeting(entityType, entityId, meetingId).build();
|
||||
|
||||
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
}
|
||||
|
||||
private boolean is(final String commandParam, final String commandValue) {
|
||||
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* 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.meeting.attendance;
|
||||
|
||||
import org.mifosplatform.portfolio.meeting.attendance.domain.ClientAttendance;
|
||||
|
||||
/**
|
||||
* An enumeration of {@link ClientAttendance} type.
|
||||
*/
|
||||
public enum AttendanceType {
|
||||
|
||||
INVALID(0, "attendanceType.invalid"), //
|
||||
PRESENT(1, "attendanceType.present"), //
|
||||
ABSENT(2, "attendanceType.absent"), //
|
||||
APPROVED(3, "attendanceType.approved"), //
|
||||
LEAVE(4, "attendanceType.leave"), //
|
||||
LATE(5, "attendanceType.late");
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
|
||||
private AttendanceType(final Integer value, final String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public static AttendanceType fromInt(final Integer attendanceTypeId) {
|
||||
|
||||
if (attendanceTypeId == null) { return AttendanceType.INVALID; }
|
||||
|
||||
AttendanceType attendanceType = AttendanceType.INVALID;
|
||||
switch (attendanceTypeId) {
|
||||
case 1:
|
||||
attendanceType = AttendanceType.PRESENT;
|
||||
break;
|
||||
case 2:
|
||||
attendanceType = AttendanceType.ABSENT;
|
||||
break;
|
||||
case 3:
|
||||
attendanceType = AttendanceType.APPROVED;
|
||||
break;
|
||||
case 4:
|
||||
attendanceType = AttendanceType.LEAVE;
|
||||
break;
|
||||
case 5:
|
||||
attendanceType = AttendanceType.LATE;
|
||||
break;
|
||||
}
|
||||
return attendanceType;
|
||||
}
|
||||
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* 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.meeting.attendance.data;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
|
||||
/**
|
||||
* Immutable data object representing a ClientAttendance.
|
||||
*/
|
||||
public class ClientAttendanceData {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final Long id;
|
||||
@SuppressWarnings("unused")
|
||||
private final Long clientId;
|
||||
@SuppressWarnings("unused")
|
||||
private final String clientName;
|
||||
@SuppressWarnings("unused")
|
||||
private final EnumOptionData attendanceType;
|
||||
|
||||
public static ClientAttendanceData instance(Long id, Long clientId, String clientName, EnumOptionData attendanceType){
|
||||
return new ClientAttendanceData(id, clientId, clientName, attendanceType);
|
||||
}
|
||||
|
||||
private ClientAttendanceData(Long id, Long clientId, String clientName, EnumOptionData attendanceType) {
|
||||
this.id = id;
|
||||
this.clientId = clientId;
|
||||
this.clientName = clientName;
|
||||
this.attendanceType = attendanceType;
|
||||
}
|
||||
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package org.mifosplatform.portfolio.meeting.attendance.domain;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
||||
import org.mifosplatform.portfolio.client.domain.Client;
|
||||
import org.mifosplatform.portfolio.meeting.domain.Meeting;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_client_attendance", uniqueConstraints = { @UniqueConstraint(columnNames = { "client_id", "meeting_id" }, name = "unique_client_meeting_attendance") })
|
||||
public class ClientAttendance extends AbstractPersistable<Long> {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "client_id", nullable = false)
|
||||
private Client client;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "meeting_id", nullable = false)
|
||||
private Meeting meeting;
|
||||
|
||||
@Column(name = "attendance_type_enum", nullable = false)
|
||||
private Integer attendanceTypeId;
|
||||
|
||||
protected ClientAttendance() {
|
||||
|
||||
}
|
||||
|
||||
public static ClientAttendance createClientAttendance(final Client client, final Meeting meeting, final Integer attendanceTypeId) {
|
||||
return new ClientAttendance(client, meeting, attendanceTypeId);
|
||||
}
|
||||
|
||||
private ClientAttendance(final Client client, final Meeting meeting, final Integer attendanceTypeId) {
|
||||
this.client = client;
|
||||
this.meeting = meeting;
|
||||
this.attendanceTypeId = attendanceTypeId;
|
||||
}
|
||||
|
||||
public Long clientId() {
|
||||
return client.getId();
|
||||
}
|
||||
|
||||
public void updateAttendanceTypeId(final Integer attendanceTypeId) {
|
||||
this.attendanceTypeId = attendanceTypeId;
|
||||
}
|
||||
|
||||
public Integer getAttendanceTypeId() {
|
||||
return this.attendanceTypeId;
|
||||
}
|
||||
}
|
||||
+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.meeting.attendance.domain;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
|
||||
public interface ClientAttendanceRepository extends JpaRepository<ClientAttendance, Long>, JpaSpecificationExecutor<ClientAttendance> {
|
||||
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* 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.meeting.attendance.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
|
||||
public interface AttendanceDropdownReadPlatformService {
|
||||
List<EnumOptionData> retrieveAttendanceTypeOptions();
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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.meeting.attendance.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.portfolio.meeting.attendance.AttendanceType;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class AttendanceDropdownReadPlatformServiceImpl implements AttendanceDropdownReadPlatformService {
|
||||
|
||||
@Override
|
||||
public List<EnumOptionData> retrieveAttendanceTypeOptions() {
|
||||
return AttendanceEnumerations.attendanceType(AttendanceType.values());
|
||||
}
|
||||
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* 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.meeting.attendance.service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.portfolio.meeting.attendance.AttendanceType;
|
||||
|
||||
public class AttendanceEnumerations {
|
||||
|
||||
public static EnumOptionData attendanceType(final int attendanceType) {
|
||||
return attendanceType(AttendanceType.fromInt(attendanceType));
|
||||
}
|
||||
|
||||
public static EnumOptionData attendanceType(final AttendanceType attendanceType) {
|
||||
|
||||
EnumOptionData optionData = new EnumOptionData(AttendanceType.INVALID.getValue().longValue(), AttendanceType.INVALID.getCode(),
|
||||
"Invalid");
|
||||
|
||||
switch (attendanceType) {
|
||||
case INVALID:
|
||||
optionData = new EnumOptionData(AttendanceType.INVALID.getValue().longValue(), AttendanceType.INVALID.getCode(), "Invalid");
|
||||
break;
|
||||
case PRESENT:
|
||||
optionData = new EnumOptionData(AttendanceType.PRESENT.getValue().longValue(), AttendanceType.PRESENT.getCode(), "Present");
|
||||
break;
|
||||
case ABSENT:
|
||||
optionData = new EnumOptionData(AttendanceType.ABSENT.getValue().longValue(), AttendanceType.ABSENT.getCode(), "Absent");
|
||||
break;
|
||||
case APPROVED:
|
||||
optionData = new EnumOptionData(AttendanceType.APPROVED.getValue().longValue(), AttendanceType.APPROVED.getCode(),
|
||||
"Approved");
|
||||
break;
|
||||
case LEAVE:
|
||||
optionData = new EnumOptionData(AttendanceType.LEAVE.getValue().longValue(), AttendanceType.LEAVE.getCode(), "Leave");
|
||||
break;
|
||||
case LATE:
|
||||
optionData = new EnumOptionData(AttendanceType.LATE.getValue().longValue(), AttendanceType.LATE.getCode(), "Late");
|
||||
break;
|
||||
}
|
||||
return optionData;
|
||||
}
|
||||
|
||||
public static List<EnumOptionData> attendanceType(final AttendanceType[] attendanceTypes) {
|
||||
final List<EnumOptionData> optionDatas = new ArrayList<EnumOptionData>();
|
||||
for (final AttendanceType attendanceType : attendanceTypes) {
|
||||
if(attendanceType.getValue().equals(AttendanceType.INVALID.getValue())) continue;
|
||||
optionDatas.add(attendanceType(attendanceType));
|
||||
}
|
||||
return optionDatas;
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* 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.meeting.attendance.service;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.mifosplatform.portfolio.meeting.attendance.data.ClientAttendanceData;
|
||||
|
||||
public interface ClientAttendanceReadPlatformService {
|
||||
Collection<ClientAttendanceData> retrieveClientAttendanceByMeetingId(final Long meetingId);
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* 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.meeting.attendance.service;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
|
||||
import org.mifosplatform.portfolio.meeting.attendance.data.ClientAttendanceData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class ClientAttendanceReadPlatformServiceImpl implements ClientAttendanceReadPlatformService {
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
@Autowired
|
||||
public ClientAttendanceReadPlatformServiceImpl(final RoutingDataSource dataSource) {
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
private static final class ClientAttendanceDataMapper implements RowMapper<ClientAttendanceData> {
|
||||
|
||||
public String schema() {
|
||||
|
||||
return " select ca.id as id, ca.client_id as clientId, ca.attendance_type_enum as attendanceTypeId, " +
|
||||
" c.display_name as clientName from m_meeting m inner join m_client_attendance ca on m.id = ca.meeting_id " +
|
||||
" inner join m_client c on ca.client_id=c.id ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientAttendanceData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||
|
||||
final Long id = rs.getLong("id");
|
||||
final Long clientId = rs.getLong("clientId");
|
||||
final Integer attendanceTypeId = rs.getInt("attendanceTypeId");
|
||||
final String clientName = rs.getString("clientName");
|
||||
final EnumOptionData attendanceType = AttendanceEnumerations.attendanceType(attendanceTypeId);
|
||||
return ClientAttendanceData.instance(id, clientId, clientName, attendanceType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ClientAttendanceData> retrieveClientAttendanceByMeetingId(final Long meetingId) {
|
||||
final ClientAttendanceDataMapper rm = new ClientAttendanceDataMapper();
|
||||
final String sql = rm.schema() + " where m.id = ? ";
|
||||
|
||||
return this.jdbcTemplate.query(sql, rm, new Object[] { meetingId });
|
||||
}
|
||||
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* 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.meeting.data;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.portfolio.calendar.data.CalendarData;
|
||||
import org.mifosplatform.portfolio.client.data.ClientData;
|
||||
import org.mifosplatform.portfolio.meeting.attendance.data.ClientAttendanceData;
|
||||
|
||||
/**
|
||||
* Immutable data object representing a Meeting.
|
||||
*/
|
||||
public class MeetingData {
|
||||
|
||||
private final Long id;
|
||||
private final LocalDate meetingDate;
|
||||
private final Collection<ClientAttendanceData> clientsAttendance;
|
||||
|
||||
// template data
|
||||
private final Collection<ClientData> clients;
|
||||
private final CalendarData calendarData;
|
||||
@SuppressWarnings("unused")
|
||||
private final List<EnumOptionData> attendanceTypeOptions;
|
||||
|
||||
public static MeetingData instance(final Long id, final LocalDate meetingDate) {
|
||||
final Collection<ClientAttendanceData> clientsAttendance = null;
|
||||
final Collection<ClientData> clients = null;
|
||||
final CalendarData calendarData = null;
|
||||
final List<EnumOptionData> attendanceTypeOptions = null;
|
||||
return new MeetingData(id, meetingDate, clientsAttendance, clients, calendarData, attendanceTypeOptions);
|
||||
}
|
||||
|
||||
public static MeetingData withClientsAttendanceAndAttendanceTypeOptions(final MeetingData meetingData,
|
||||
final Collection<ClientAttendanceData> clientsAttendance, final List<EnumOptionData> attendanceTypesOptions) {
|
||||
return new MeetingData(meetingData.id, meetingData.meetingDate, clientsAttendance, meetingData.clients, meetingData.calendarData,
|
||||
attendanceTypesOptions);
|
||||
}
|
||||
|
||||
public static MeetingData template(final Collection<ClientData> clients, final CalendarData calendarData,
|
||||
final List<EnumOptionData> attendanceTypeOptions) {
|
||||
final Long id = null;
|
||||
final LocalDate meetingDate = null;
|
||||
final Collection<ClientAttendanceData> clientsAttendance = null;
|
||||
return new MeetingData(id, meetingDate, clientsAttendance, clients, calendarData, attendanceTypeOptions);
|
||||
}
|
||||
|
||||
public static MeetingData withAttendanceTypeOptions(final MeetingData meetingData, final List<EnumOptionData> attendanceTypeOptions) {
|
||||
|
||||
return new MeetingData(meetingData.id, meetingData.meetingDate, meetingData.clientsAttendance, meetingData.clients,
|
||||
meetingData.calendarData, attendanceTypeOptions);
|
||||
}
|
||||
|
||||
private MeetingData(Long id, LocalDate meetingDate, Collection<ClientAttendanceData> clientsAttendance,
|
||||
final Collection<ClientData> clients, final CalendarData calendarData, final List<EnumOptionData> attendanceTypeOptions) {
|
||||
this.id = id;
|
||||
this.meetingDate = meetingDate;
|
||||
this.clientsAttendance = clientsAttendance;
|
||||
this.clients = clients;
|
||||
this.calendarData = calendarData;
|
||||
this.attendanceTypeOptions = attendanceTypeOptions;
|
||||
}
|
||||
}
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
* 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.meeting.data;
|
||||
|
||||
import static org.mifosplatform.portfolio.meeting.MeetingApiConstants.MEETING_REQUEST_DATA_PARAMETERS;
|
||||
import static org.mifosplatform.portfolio.meeting.MeetingApiConstants.MEETING_RESOURCE_NAME;
|
||||
import static org.mifosplatform.portfolio.meeting.MeetingApiConstants.clientsAttendanceParamName;
|
||||
import static org.mifosplatform.portfolio.meeting.MeetingApiConstants.attendanceTypeParamName;
|
||||
import static org.mifosplatform.portfolio.meeting.MeetingApiConstants.calendarIdParamName;
|
||||
import static org.mifosplatform.portfolio.meeting.MeetingApiConstants.clientIdParamName;
|
||||
import static org.mifosplatform.portfolio.meeting.MeetingApiConstants.meetingDateParamName;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
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.exception.InvalidJsonException;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
@Component
|
||||
public class MeetingDataValidator {
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
@Autowired
|
||||
public MeetingDataValidator(final FromJsonHelper fromApiJsonHelper) {
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
}
|
||||
|
||||
public void validateForCreate(final JsonCommand command) {
|
||||
final String json = command.json();
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, MEETING_REQUEST_DATA_PARAMETERS);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(MEETING_RESOURCE_NAME);
|
||||
final JsonElement element = fromApiJsonHelper.parse(json);
|
||||
|
||||
final String meetingDateStr = this.fromApiJsonHelper.extractStringNamed(meetingDateParamName, element);
|
||||
baseDataValidator.reset().parameter(meetingDateParamName).value(meetingDateStr).notBlank();
|
||||
|
||||
if(!StringUtils.isBlank(meetingDateStr)){
|
||||
final LocalDate meetingDate = this.fromApiJsonHelper.extractLocalDateNamed(meetingDateParamName, element);
|
||||
baseDataValidator.reset().parameter(meetingDateParamName).value(meetingDate).notNull();
|
||||
}
|
||||
|
||||
final Long calendarId = this.fromApiJsonHelper.extractLongNamed(calendarIdParamName, element);
|
||||
baseDataValidator.reset().parameter(calendarIdParamName).value(calendarId).notNull();
|
||||
|
||||
validateAttendanceDetails(element, baseDataValidator);
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
public void validateForUpdate(final JsonCommand command) {
|
||||
final String json = command.json();
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, MEETING_REQUEST_DATA_PARAMETERS);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(MEETING_RESOURCE_NAME);
|
||||
final JsonElement element = fromApiJsonHelper.parse(json);
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(meetingDateParamName, element)) {
|
||||
final String meetingDateStr = this.fromApiJsonHelper.extractStringNamed(meetingDateParamName, element);
|
||||
baseDataValidator.reset().parameter(meetingDateParamName).value(meetingDateStr).notBlank();
|
||||
|
||||
if(!StringUtils.isBlank(meetingDateStr)){
|
||||
final LocalDate meetingDate = this.fromApiJsonHelper.extractLocalDateNamed(meetingDateParamName, element);
|
||||
baseDataValidator.reset().parameter(meetingDateParamName).value(meetingDate).notNull();
|
||||
}
|
||||
}
|
||||
|
||||
if(this.fromApiJsonHelper.parameterExists(calendarIdParamName, element)){
|
||||
final Long calendarId = this.fromApiJsonHelper.extractLongNamed(calendarIdParamName, element);
|
||||
baseDataValidator.reset().parameter(calendarIdParamName).value(calendarId).notNull();
|
||||
}
|
||||
|
||||
validateAttendanceDetails(element, baseDataValidator);
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
public void validateForUpdateAttendance(final JsonCommand command) {
|
||||
final String json = command.json();
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, MEETING_REQUEST_DATA_PARAMETERS);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(MEETING_RESOURCE_NAME);
|
||||
final JsonElement element = fromApiJsonHelper.parse(json);
|
||||
|
||||
validateAttendanceDetails(element, baseDataValidator);
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
private void validateAttendanceDetails(final JsonElement element, final DataValidatorBuilder baseDataValidator){
|
||||
final JsonObject topLevelJsonElement = element.getAsJsonObject();
|
||||
if (element.isJsonObject()) {
|
||||
if (topLevelJsonElement.has(clientsAttendanceParamName)
|
||||
&& topLevelJsonElement.get(clientsAttendanceParamName).isJsonArray()) {
|
||||
final JsonArray array = topLevelJsonElement.get(clientsAttendanceParamName).getAsJsonArray();
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
final JsonObject attendanceElement = array.get(i).getAsJsonObject();
|
||||
final Long clientId = this.fromApiJsonHelper.extractLongNamed(clientIdParamName, attendanceElement);
|
||||
final Long attendanceType = this.fromApiJsonHelper.extractLongNamed(attendanceTypeParamName, attendanceElement);
|
||||
baseDataValidator.reset().parameter(clientsAttendanceParamName + "[" + i + "]." + clientIdParamName).value(clientId).notNull().integerGreaterThanZero();
|
||||
baseDataValidator.reset().parameter(clientsAttendanceParamName + "[" + i + "]." + attendanceTypeParamName).value(attendanceType).notNull().integerGreaterThanZero();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* 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.meeting.domain;
|
||||
|
||||
import static org.mifosplatform.portfolio.meeting.MeetingApiConstants.clientsAttendanceParamName;
|
||||
import static org.mifosplatform.portfolio.meeting.MeetingApiConstants.attendanceTypeParamName;
|
||||
import static org.mifosplatform.portfolio.meeting.MeetingApiConstants.clientIdParamName;
|
||||
import static org.mifosplatform.portfolio.meeting.MeetingApiConstants.meetingDateParamName;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
||||
import org.mifosplatform.portfolio.calendar.exception.NotValidRecurringDateException;
|
||||
import org.mifosplatform.portfolio.calendar.service.CalendarUtils;
|
||||
import org.mifosplatform.portfolio.meeting.attendance.domain.ClientAttendance;
|
||||
import org.mifosplatform.portfolio.meeting.exception.MeetingDateException;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_meeting", uniqueConstraints = { @UniqueConstraint(columnNames = { "calendar_instance_id", "meeting_date" }, name = "unique_calendar_instance_id_meeting_date") })
|
||||
public class Meeting extends AbstractPersistable<Long> {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "calendar_instance_id", nullable = false)
|
||||
private CalendarInstance calendarInstance;
|
||||
|
||||
@Column(name = "meeting_date", nullable = false)
|
||||
@Temporal(TemporalType.DATE)
|
||||
private Date meetingDate;
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "meeting", orphanRemoval = true)
|
||||
private Set<ClientAttendance> clientsAttendance;
|
||||
|
||||
protected Meeting() {
|
||||
//
|
||||
}
|
||||
|
||||
private Meeting(CalendarInstance calendarInstance, Date meetingDate) {
|
||||
this.calendarInstance = calendarInstance;
|
||||
this.meetingDate = meetingDate;
|
||||
}
|
||||
|
||||
public static Meeting createNew(final CalendarInstance calendarInstance, final Date meetingDate) {
|
||||
|
||||
if(!isValidMeetingDate(calendarInstance, meetingDate)){
|
||||
throw new NotValidRecurringDateException("meeting", "The date '" + meetingDate + "' is not a valid meeting date.", meetingDate);
|
||||
}
|
||||
return new Meeting(calendarInstance, meetingDate);
|
||||
}
|
||||
|
||||
public void associateClientsAttendance(final Collection<ClientAttendance> clientsAttendance) {
|
||||
//do not allow to capture attendance in advance.
|
||||
if(isMeetingDateAfter(DateUtils.getLocalDateOfTenant())){
|
||||
final String errorMessage = "Attendance cannot be in the future.";
|
||||
throw new MeetingDateException("cannot.be.a.future.date", errorMessage, getMeetingDateLocalDate());
|
||||
}
|
||||
this.clientsAttendance = new HashSet<ClientAttendance>(clientsAttendance);
|
||||
}
|
||||
|
||||
public Map<String, Object> update(final JsonCommand command) {
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(9);
|
||||
final String dateFormatAsInput = command.dateFormat();
|
||||
final String localeAsInput = command.locale();
|
||||
|
||||
if (command.isChangeInLocalDateParameterNamed(meetingDateParamName, getMeetingDateLocalDate())) {
|
||||
final String valueAsInput = command.stringValueOfParameterNamed(meetingDateParamName);
|
||||
final LocalDate newValue = command.localDateValueOfParameterNamed(meetingDateParamName);
|
||||
actualChanges.put(meetingDateParamName, valueAsInput);
|
||||
actualChanges.put("dateFormat", dateFormatAsInput);
|
||||
actualChanges.put("locale", localeAsInput);
|
||||
this.meetingDate = newValue.toDate();
|
||||
|
||||
if(!isValidMeetingDate(this.calendarInstance, this.meetingDate)){
|
||||
throw new NotValidRecurringDateException("meeting", "Not a valid meeting date", meetingDate);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
public Map<String, Object> updateAttendance(final Collection<ClientAttendance> clientsAttendance) {
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(1);
|
||||
final Map<String, Object> clientAttendanceChanges = new LinkedHashMap<String, Object>(clientsAttendance.size());
|
||||
|
||||
updateAttendanceLoop: for (ClientAttendance clientAttendance : clientsAttendance) {
|
||||
for (ClientAttendance clientAttendanceOriginal : this.clientsAttendance) {
|
||||
if (clientAttendanceOriginal.clientId().equals(clientAttendance.clientId())) {
|
||||
final Integer newValue = clientAttendance.getAttendanceTypeId();
|
||||
if(!newValue.equals(clientAttendanceOriginal.getAttendanceTypeId())){
|
||||
clientAttendanceOriginal.updateAttendanceTypeId(newValue);
|
||||
final Map<String, Object> clientAttendanceChange = new LinkedHashMap<String, Object>(2);
|
||||
clientAttendanceChange.put(clientIdParamName, clientAttendanceOriginal.clientId());
|
||||
clientAttendanceChange.put(attendanceTypeParamName, newValue);
|
||||
clientAttendanceChanges.put(clientAttendanceOriginal.clientId().toString(), clientAttendanceChange);
|
||||
}
|
||||
continue updateAttendanceLoop;
|
||||
}
|
||||
}
|
||||
|
||||
final Map<String, Object> clientAttendanceChange = new LinkedHashMap<String, Object>();
|
||||
clientAttendanceChange.put(clientIdParamName, clientAttendance.clientId());
|
||||
clientAttendanceChange.put(attendanceTypeParamName, clientAttendance.getAttendanceTypeId());
|
||||
clientAttendanceChanges.put(clientAttendance.clientId().toString(), clientAttendanceChange);
|
||||
//New attendance record
|
||||
this.clientsAttendance.add(clientAttendance);
|
||||
}
|
||||
|
||||
actualChanges.put(clientsAttendanceParamName, clientAttendanceChanges);
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
public Long entityId() {
|
||||
return calendarInstance.getEntityId();
|
||||
}
|
||||
|
||||
public boolean isCenterEntity(){
|
||||
return CalendarEntityType.isCenter(calendarInstance.getEntityTypeId());
|
||||
}
|
||||
|
||||
public boolean isGroupEntity(){
|
||||
return CalendarEntityType.isGroup(calendarInstance.getEntityTypeId());
|
||||
}
|
||||
|
||||
public LocalDate getMeetingDateLocalDate() {
|
||||
LocalDate meetingDateLocalDate = null;
|
||||
if (this.meetingDate != null) {
|
||||
meetingDateLocalDate = LocalDate.fromDateFields(this.meetingDate);
|
||||
}
|
||||
return meetingDateLocalDate;
|
||||
}
|
||||
|
||||
public Date getMeetingDate(){
|
||||
return this.meetingDate;
|
||||
}
|
||||
|
||||
public boolean isMeetingDateBefore(final LocalDate newStartDate) {
|
||||
return (this.meetingDate != null && newStartDate != null && getMeetingDateLocalDate().isBefore(newStartDate)) ? true : false;
|
||||
}
|
||||
|
||||
private static boolean isValidMeetingDate(final CalendarInstance calendarInstance, final Date meetingDate ){
|
||||
final Calendar calendar = calendarInstance.getCalendar();
|
||||
LocalDate meetingDateLocalDate = null;
|
||||
if (meetingDate != null) {
|
||||
meetingDateLocalDate = LocalDate.fromDateFields(meetingDate);
|
||||
}
|
||||
if(meetingDateLocalDate == null || !CalendarUtils.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(), meetingDateLocalDate)){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isMeetingDateAfter(final LocalDate date){
|
||||
return getMeetingDateLocalDate().isAfter(date);
|
||||
}
|
||||
|
||||
public Collection<ClientAttendance> getClientsAttendance() {
|
||||
return this.clientsAttendance;
|
||||
}
|
||||
|
||||
}
|
||||
+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.meeting.domain;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
|
||||
public interface MeetingRepository extends JpaRepository<Meeting, Long>, JpaSpecificationExecutor<Meeting> {
|
||||
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* 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.meeting.domain;
|
||||
|
||||
import org.mifosplatform.portfolio.meeting.exception.MeetingNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Wrapper for {@link MeetingRepository} that is responsible for checking
|
||||
* if {@link Meeting} is returned when using <code>findOne</code>
|
||||
* repository method and throwing an appropriate not found exception.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This is to avoid need for checking and throwing in multiple areas of code
|
||||
* base where {@link MeetingRepository} is required.
|
||||
* </p>
|
||||
*/
|
||||
@Service
|
||||
public class MeetingRepositoryWrapper {
|
||||
|
||||
private final MeetingRepository repository;
|
||||
|
||||
@Autowired
|
||||
public MeetingRepositoryWrapper(final MeetingRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public Meeting findOneWithNotFoundDetection(final Long meetingId) {
|
||||
final Meeting meeting = this.repository.findOne(meetingId);
|
||||
if (meeting == null) { throw new MeetingNotFoundException(meetingId); }
|
||||
return meeting;
|
||||
}
|
||||
|
||||
public void save(final Meeting meeting) {
|
||||
this.repository.save(meeting);
|
||||
}
|
||||
|
||||
public void delete(final Meeting meeting) {
|
||||
this.repository.delete(meeting);
|
||||
}
|
||||
|
||||
public void saveAndFlush(final Meeting meeting) {
|
||||
this.repository.saveAndFlush(meeting);
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.meeting.exception;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
/**
|
||||
* A {@link RuntimeException} thrown when Meeting date violates a domain rule.
|
||||
*/
|
||||
public class MeetingDateException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public MeetingDateException(final String postFix, final String defaultUserMessage, final Object... defaultUserMessageArgs) {
|
||||
super("error.msg.meeting.date." + postFix, defaultUserMessage, defaultUserMessageArgs);
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.meeting.exception;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
|
||||
|
||||
/**
|
||||
* A {@link RuntimeException} thrown when Meeting resources are not found.
|
||||
*/
|
||||
public class MeetingNotFoundException extends AbstractPlatformResourceNotFoundException {
|
||||
|
||||
public MeetingNotFoundException(final Long id) {
|
||||
super("error.msg.meeting.id.invalid", "Meeting with identifier " + id + " does not exist", id);
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.meeting.exception;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
/**
|
||||
* {@link AbstractPlatformDomainRuleException} thrown when meeting is captured against not supported resource.
|
||||
*/
|
||||
public class MeetingNotSupportedResourceException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public MeetingNotSupportedResourceException(String defaultUserMessage, Object... defaultUserMessageArgs) {
|
||||
super("error.msg.meeting.not.supported.resource", defaultUserMessage, defaultUserMessageArgs);
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 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.meeting.handler;
|
||||
|
||||
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.portfolio.meeting.service.MeetingWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class CreateMeetingCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final MeetingWritePlatformService writePlatformService;
|
||||
|
||||
@Autowired
|
||||
public CreateMeetingCommandHandler(final MeetingWritePlatformService writePlatformService) {
|
||||
this.writePlatformService = writePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
return this.writePlatformService.createMeeting(command);
|
||||
}
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 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.meeting.handler;
|
||||
|
||||
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.portfolio.meeting.service.MeetingWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class DeleteMeetingCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final MeetingWritePlatformService writePlatformService;
|
||||
|
||||
@Autowired
|
||||
public DeleteMeetingCommandHandler(final MeetingWritePlatformService writePlatformService) {
|
||||
this.writePlatformService = writePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
return this.writePlatformService.deleteMeeting(command.entityId());
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 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.meeting.handler;
|
||||
|
||||
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.portfolio.meeting.service.MeetingWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class UpdateMeetingAttendanceCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final MeetingWritePlatformService writePlatformService;
|
||||
|
||||
@Autowired
|
||||
public UpdateMeetingAttendanceCommandHandler(final MeetingWritePlatformService writePlatformService) {
|
||||
this.writePlatformService = writePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
|
||||
return this.writePlatformService.saveOrUpdateAttendance(command);
|
||||
}
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 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.meeting.handler;
|
||||
|
||||
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.portfolio.meeting.service.MeetingWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class UpdateMeetingCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final MeetingWritePlatformService writePlatformService;
|
||||
|
||||
@Autowired
|
||||
public UpdateMeetingCommandHandler(final MeetingWritePlatformService writePlatformService) {
|
||||
this.writePlatformService = writePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
|
||||
return this.writePlatformService.updateMeeting(command);
|
||||
}
|
||||
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* 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.meeting.service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.mifosplatform.portfolio.meeting.data.MeetingData;
|
||||
|
||||
public interface MeetingReadPlatformService {
|
||||
|
||||
MeetingData retrieveMeeting(final Long meetingId, Long entityId, Integer entityTypeId);
|
||||
|
||||
Collection<MeetingData> retrieveMeetingsByEntity(final Long entityId, final Integer entityTypeId, Integer limit);
|
||||
|
||||
Collection<MeetingData> retrieveMeetingsByEntityByCalendarType(final Long entityId, final Integer entityTypeId,
|
||||
final List<Integer> calendarTypeOptions);
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* 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.meeting.service;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
|
||||
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
|
||||
import org.mifosplatform.portfolio.calendar.service.CalendarUtils;
|
||||
import org.mifosplatform.portfolio.meeting.data.MeetingData;
|
||||
import org.mifosplatform.portfolio.meeting.exception.MeetingNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class MeetingReadPlatformServiceImpl implements MeetingReadPlatformService {
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
@Autowired
|
||||
public MeetingReadPlatformServiceImpl(final RoutingDataSource dataSource) {
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
private static final class MeetingDataMapper implements RowMapper<MeetingData> {
|
||||
|
||||
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 ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public MeetingData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||
|
||||
final Long id = rs.getLong("id");
|
||||
final LocalDate meetingDate = JdbcSupport.getLocalDate(rs, "meetingDate");
|
||||
|
||||
return MeetingData.instance(id, meetingDate);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MeetingData retrieveMeeting(final Long meetingId, Long entityId, Integer entityTypeId) {
|
||||
|
||||
try {
|
||||
final MeetingDataMapper rm = new MeetingDataMapper();
|
||||
|
||||
final String sql = rm.schema() + " where m.id = ? and ci.entity_id = ? and ci.entity_type_enum = ? ";
|
||||
|
||||
return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { meetingId, entityId, entityTypeId });
|
||||
} catch (final EmptyResultDataAccessException e) {
|
||||
throw new MeetingNotFoundException(meetingId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<MeetingData> retrieveMeetingsByEntity(Long entityId, Integer entityTypeId, Integer limit) {
|
||||
final MeetingDataMapper rm = new MeetingDataMapper();
|
||||
String sql = rm.schema() + " where ci.entity_id = ? and ci.entity_type_enum = ? ";
|
||||
if(limit != null && limit > 0){
|
||||
sql = sql + " order by m.meeting_date desc " + " limit " + limit;
|
||||
}
|
||||
|
||||
return this.jdbcTemplate.query(sql, rm, new Object[] { entityId, entityTypeId });
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<MeetingData> retrieveMeetingsByEntityByCalendarType(Long entityId, Integer entityTypeId,
|
||||
List<Integer> calendarTypeOptions) {
|
||||
final MeetingDataMapper rm = new MeetingDataMapper();
|
||||
String sqlCalendarTypeOptions = CalendarUtils.getSqlCalendarTypeOptionsInString(calendarTypeOptions);
|
||||
final String sql = rm.schema()
|
||||
+ " inner join m_calendar c on ci.calendar_id=c.id where ci.entity_id = ? and ci.entity_type_enum = ? and c.calendar_type_enum in ("
|
||||
+ sqlCalendarTypeOptions + ") order by c.start_date ";
|
||||
|
||||
return this.jdbcTemplate.query(sql, rm, new Object[] { entityId, entityTypeId });
|
||||
}
|
||||
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* 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.meeting.service;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
|
||||
public interface MeetingWritePlatformService {
|
||||
|
||||
CommandProcessingResult createMeeting(JsonCommand command);
|
||||
|
||||
CommandProcessingResult updateMeeting(JsonCommand command);
|
||||
|
||||
CommandProcessingResult deleteMeeting(Long meetingId);
|
||||
|
||||
CommandProcessingResult saveOrUpdateAttendance(JsonCommand command);
|
||||
}
|
||||
+229
@@ -0,0 +1,229 @@
|
||||
/**
|
||||
* 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.meeting.service;
|
||||
|
||||
import static org.mifosplatform.portfolio.meeting.MeetingApiConstants.attendanceTypeParamName;
|
||||
import static org.mifosplatform.portfolio.meeting.MeetingApiConstants.calendarIdParamName;
|
||||
import static org.mifosplatform.portfolio.meeting.MeetingApiConstants.clientIdParamName;
|
||||
import static org.mifosplatform.portfolio.meeting.MeetingApiConstants.clientsAttendanceParamName;
|
||||
import static org.mifosplatform.portfolio.meeting.MeetingApiConstants.meetingDateParamName;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarInstanceRepository;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarRepository;
|
||||
import org.mifosplatform.portfolio.calendar.exception.CalendarInstanceNotFoundException;
|
||||
import org.mifosplatform.portfolio.calendar.exception.CalendarNotFoundException;
|
||||
import org.mifosplatform.portfolio.client.domain.Client;
|
||||
import org.mifosplatform.portfolio.client.domain.ClientRepository;
|
||||
import org.mifosplatform.portfolio.group.domain.Group;
|
||||
import org.mifosplatform.portfolio.group.domain.GroupRepository;
|
||||
import org.mifosplatform.portfolio.group.exception.ClientNotInGroupException;
|
||||
import org.mifosplatform.portfolio.meeting.attendance.domain.ClientAttendance;
|
||||
import org.mifosplatform.portfolio.meeting.data.MeetingDataValidator;
|
||||
import org.mifosplatform.portfolio.meeting.domain.Meeting;
|
||||
import org.mifosplatform.portfolio.meeting.domain.MeetingRepositoryWrapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
@Service
|
||||
public class MeetingWritePlatformServiceJpaRepositoryImpl implements MeetingWritePlatformService {
|
||||
|
||||
private final MeetingRepositoryWrapper meetingRepository;
|
||||
private final MeetingDataValidator meetingDataValidator;
|
||||
private final CalendarInstanceRepository calendarInstanceRepository;
|
||||
private final CalendarRepository calendarRepository;
|
||||
private final ClientRepository clientRepository;
|
||||
private final GroupRepository groupRepository;
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
@Autowired
|
||||
public MeetingWritePlatformServiceJpaRepositoryImpl(MeetingRepositoryWrapper meetingRepository,
|
||||
MeetingDataValidator meetingDataValidator, CalendarInstanceRepository calendarInstanceRepository,
|
||||
CalendarRepository calendarRepository, final ClientRepository clientRepository, final GroupRepository groupRepository,
|
||||
final FromJsonHelper fromApiJsonHelper) {
|
||||
this.meetingRepository = meetingRepository;
|
||||
this.meetingDataValidator = meetingDataValidator;
|
||||
this.calendarInstanceRepository = calendarInstanceRepository;
|
||||
this.calendarRepository = calendarRepository;
|
||||
this.clientRepository = clientRepository;
|
||||
this.groupRepository = groupRepository;
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult createMeeting(JsonCommand command) {
|
||||
|
||||
this.meetingDataValidator.validateForCreate(command);
|
||||
|
||||
final Date meetingDate = command.DateValueOfParameterNamed(meetingDateParamName);
|
||||
|
||||
try {
|
||||
final CalendarInstance calendarInstance = getCalendarInstance(command);
|
||||
// create new meeting
|
||||
final Meeting newMeeting = Meeting.createNew(calendarInstance, meetingDate);
|
||||
|
||||
final Collection<ClientAttendance> clientsAttendance = getClientsAttendance(newMeeting, command);
|
||||
if (clientsAttendance != null && !clientsAttendance.isEmpty()) {
|
||||
newMeeting.associateClientsAttendance(clientsAttendance);
|
||||
}
|
||||
// save meeting details
|
||||
this.meetingRepository.save(newMeeting);
|
||||
final Long groupId = newMeeting.isGroupEntity() ? newMeeting.entityId() : null;
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(newMeeting.getId()) //
|
||||
.withGroupId(groupId).build();
|
||||
|
||||
} catch (DataIntegrityViolationException dve) {
|
||||
handleMeetingDataIntegrityIssues(meetingDate, dve);
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
private CalendarInstance getCalendarInstance(final JsonCommand command) {
|
||||
final Long calendarId = command.longValueOfParameterNamed(calendarIdParamName);
|
||||
final Long entityId = command.getSupportedEntityId();
|
||||
final Calendar calendarForUpdate = this.calendarRepository.findOne(calendarId);
|
||||
if (calendarForUpdate == null) { throw new CalendarNotFoundException(calendarId); }
|
||||
|
||||
final Integer entityTypeId = CalendarEntityType.valueOf(command.getSupportedEntityType().toUpperCase()).getValue();
|
||||
final CalendarInstance calendarInstance = calendarInstanceRepository.findByCalendarIdAndEntityIdAndEntityTypeId(
|
||||
calendarForUpdate.getId(), entityId, entityTypeId);
|
||||
if(calendarInstance == null) {
|
||||
final String postFix = "for." + command.getSupportedEntityType() + "not.found";
|
||||
final String defaultUserMessage = "No Calendar Instance details found for group with identifier " + entityId + " and calendar with identifier " + calendarId;
|
||||
throw new CalendarInstanceNotFoundException(postFix, defaultUserMessage, entityId, calendarId);
|
||||
}
|
||||
return calendarInstance;
|
||||
}
|
||||
|
||||
private Collection<ClientAttendance> getClientsAttendance(final Meeting meeting, final JsonCommand command) {
|
||||
final Collection<ClientAttendance> clientsAttendance = new ArrayList<ClientAttendance>();
|
||||
|
||||
Collection<Group> childGroups = null;
|
||||
if (meeting.isCenterEntity()) {
|
||||
childGroups = this.groupRepository.findByParentId(meeting.entityId());
|
||||
}
|
||||
|
||||
final String json = command.json();
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||
final JsonObject topLevelJsonElement = element.getAsJsonObject();
|
||||
if (element.isJsonObject()) {
|
||||
if (topLevelJsonElement.has(clientsAttendanceParamName) && topLevelJsonElement.get(clientsAttendanceParamName).isJsonArray()) {
|
||||
final JsonArray array = topLevelJsonElement.get(clientsAttendanceParamName).getAsJsonArray();
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
final JsonObject attendanceElement = array.get(i).getAsJsonObject();
|
||||
final Long clientId = this.fromApiJsonHelper.extractLongNamed(clientIdParamName, attendanceElement);
|
||||
final Integer attendanceTypeId = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(attendanceTypeParamName,
|
||||
attendanceElement);
|
||||
|
||||
final Client client = this.clientRepository.findOne(clientId);
|
||||
|
||||
if (meeting.isGroupEntity() && !client.isChildOfGroup(meeting.entityId())) {
|
||||
throw new ClientNotInGroupException(clientId, meeting.entityId());
|
||||
} else if (meeting.isCenterEntity()) {
|
||||
if (childGroups != null && !childGroups.isEmpty()) {
|
||||
boolean isChildClient = false;
|
||||
for (Group group : childGroups) {
|
||||
if (group.isChildClient(clientId)){
|
||||
isChildClient = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!isChildClient){
|
||||
final String defaultUserMessage = "Client with identifier " + clientId + " is not in center "
|
||||
+ meeting.entityId();
|
||||
throw new ClientNotInGroupException("client.not.in.center", defaultUserMessage, clientId, meeting.entityId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final ClientAttendance clientAttendance = ClientAttendance.createClientAttendance(client, meeting, attendanceTypeId);
|
||||
clientsAttendance.add(clientAttendance);
|
||||
}
|
||||
}
|
||||
}
|
||||
return clientsAttendance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult updateMeeting(JsonCommand command) {
|
||||
this.meetingDataValidator.validateForUpdate(command);
|
||||
|
||||
final Meeting meetingForUpdate = this.meetingRepository.findOneWithNotFoundDetection(command.entityId());
|
||||
final Map<String, Object> changes = meetingForUpdate.update(command);
|
||||
|
||||
try {
|
||||
if (!changes.isEmpty()) {
|
||||
this.meetingRepository.saveAndFlush(meetingForUpdate);
|
||||
}
|
||||
} catch (DataIntegrityViolationException dve) {
|
||||
handleMeetingDataIntegrityIssues(meetingForUpdate.getMeetingDate(), dve);
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.build();
|
||||
}
|
||||
final Long groupId = meetingForUpdate.isGroupEntity() ? meetingForUpdate.entityId() : null;
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(meetingForUpdate.getId()) //
|
||||
.withGroupId(groupId) //
|
||||
.with(changes) //
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult deleteMeeting(Long meetingId) {
|
||||
final Meeting meetingForDelete = this.meetingRepository.findOneWithNotFoundDetection(meetingId);
|
||||
this.meetingRepository.delete(meetingForDelete);
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(meetingId) //
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult saveOrUpdateAttendance(JsonCommand command) {
|
||||
this.meetingDataValidator.validateForUpdateAttendance(command);
|
||||
|
||||
final Meeting meetingForUpdate = this.meetingRepository.findOneWithNotFoundDetection(command.entityId());
|
||||
final Collection<ClientAttendance> clientsAttendance = getClientsAttendance(meetingForUpdate, command);
|
||||
final Map<String, Object> changes = meetingForUpdate.updateAttendance(clientsAttendance);
|
||||
|
||||
this.meetingRepository.saveAndFlush(meetingForUpdate);
|
||||
final Long groupId = meetingForUpdate.isGroupEntity() ? meetingForUpdate.entityId() : null;
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(meetingForUpdate.getId()) //
|
||||
.withGroupId(groupId) //
|
||||
.with(changes) //
|
||||
.build();
|
||||
}
|
||||
|
||||
private void handleMeetingDataIntegrityIssues(final Date meetingDate, final DataIntegrityViolationException dve) {
|
||||
final Throwable realCause = dve.getMostSpecificCause();
|
||||
if (realCause.getMessage().contains("unique_calendar_instance_id_meeting_date")) {
|
||||
|
||||
throw new PlatformDataIntegrityException("error.msg.meeting.duplicate", "A meeting with date '" + meetingDate + "' already exists",
|
||||
meetingDateParamName, meetingDate); }
|
||||
|
||||
throw new PlatformDataIntegrityException("error.msg.meeting.unknown.data.integrity.issue",
|
||||
"Unknown data integrity issue with resource: " + realCause.getMessage());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user