blob: be914edcc3ef0422c80ec6ac052584e8628307d7 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.meeting.domain;
import static org.apache.fineract.portfolio.meeting.MeetingApiConstants.attendanceTypeParamName;
import static org.apache.fineract.portfolio.meeting.MeetingApiConstants.clientIdParamName;
import static org.apache.fineract.portfolio.meeting.MeetingApiConstants.clientsAttendanceParamName;
import static org.apache.fineract.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.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.portfolio.calendar.domain.Calendar;
import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType;
import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
import org.apache.fineract.portfolio.calendar.exception.NotValidRecurringDateException;
import org.apache.fineract.portfolio.meeting.attendance.domain.ClientAttendance;
import org.apache.fineract.portfolio.meeting.exception.MeetingDateException;
import org.joda.time.LocalDate;
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(final CalendarInstance calendarInstance, final Date meetingDate) {
this.calendarInstance = calendarInstance;
this.meetingDate = meetingDate;
}
public static Meeting createNew(final CalendarInstance calendarInstance, final Date meetingDate, Boolean isTransactionDateOnNonMeetingDate) {
if (!isTransactionDateOnNonMeetingDate && !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<>(clientsAttendance);
}
public Map<String, Object> update(final JsonCommand command) {
final Map<String, Object> actualChanges = new LinkedHashMap<>(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", this.meetingDate); }
}
return actualChanges;
}
public Map<String, Object> updateAttendance(final Collection<ClientAttendance> clientsAttendance) {
final Map<String, Object> actualChanges = new LinkedHashMap<>(1);
final Map<String, Object> clientAttendanceChanges = new LinkedHashMap<>(clientsAttendance.size());
updateAttendanceLoop: for (final ClientAttendance clientAttendance : clientsAttendance) {
if (this.clientsAttendance == null) {
this.clientsAttendance = new HashSet<>();
}
for (final 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<>(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<>();
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 this.calendarInstance.getEntityId();
}
public boolean isCenterEntity() {
return CalendarEntityType.isCenter(this.calendarInstance.getEntityTypeId());
}
public boolean isGroupEntity() {
return CalendarEntityType.isGroup(this.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 || !calendar.isValidRecurringDate(meetingDateLocalDate)) { return false; }
return true;
}
private boolean isMeetingDateAfter(final LocalDate date) {
return getMeetingDateLocalDate().isAfter(date);
}
public Collection<ClientAttendance> getClientsAttendance() {
return this.clientsAttendance;
}
}