/**
* Copyright © ${project.inceptionYear} Instituto Superior Técnico
*
* This file is part of Fenix IST.
*
* Fenix IST is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fenix IST is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Fenix IST. If not, see <http://www.gnu.org/licenses/>.
*/
package pt.ist.fenix.ui.struts.action.academicAdministration;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import org.fenixedu.academic.domain.DegreeCurricularPlan;
import org.fenixedu.academic.domain.Enrolment;
import org.fenixedu.academic.domain.ExecutionSemester;
import org.fenixedu.academic.domain.Person;
import org.fenixedu.academic.domain.StudentCurricularPlan;
import org.fenixedu.academic.domain.administrativeOffice.AdministrativeOfficeType;
import org.fenixedu.academic.domain.student.Registration;
import org.fenixedu.academic.domain.student.registrationStates.RegistrationState;
import org.fenixedu.academic.domain.student.registrationStates.RegistrationStateType;
import org.fenixedu.academic.domain.studentCurriculum.CurriculumLine;
import org.fenixedu.academic.domain.studentCurriculum.CurriculumModule;
import org.fenixedu.academic.domain.studentCurriculum.CurriculumModule.CurriculumModulePredicateByType;
import org.fenixedu.academic.domain.util.email.Message;
import org.fenixedu.academic.domain.util.email.Recipient;
import org.fenixedu.academic.domain.util.email.SystemSender;
import org.fenixedu.bennu.core.domain.Bennu;
import org.fenixedu.bennu.core.groups.UserGroup;
import org.joda.time.YearMonthDay;
import pt.ist.fenixWebFramework.renderers.utils.RenderUtils;
import pt.ist.fenixframework.Atomic;
import pt.utl.ist.fenix.tools.predicates.AndPredicate;
import pt.utl.ist.fenix.tools.predicates.Predicate;
public class UpdateAbandonStateBean implements Serializable {
private static final long serialVersionUID = 1L;
private static final String RESOURCE_BUNDLE = "FENIX_IST_RESOURCES";
private ExecutionSemester whenToAbandon;
private StringBuilder log;
public UpdateAbandonStateBean() {
}
public void updateStates() {
int totalByDegree = 0;
int total = 0;
setLog(new StringBuilder());
for (final DegreeCurricularPlan degreeCurricularPlan : DegreeCurricularPlan.readBolonhaDegreeCurricularPlans()) {
if (degreeCurricularPlan.getDegreeType().getAdministrativeOfficeType() != AdministrativeOfficeType.DEGREE) {
continue;
}
if (degreeCurricularPlan.hasExecutionDegreeFor(getWhenToAbandon().getExecutionYear())
|| degreeCurricularPlan.hasExecutionDegreeFor(getWhenToAbandon().getExecutionYear()
.getPreviousExecutionYear())) {
totalByDegree = 0;
for (final StudentCurricularPlan studentCurricularPlan : degreeCurricularPlan.getActiveStudentCurricularPlans()) {
try {
if (processStudent(studentCurricularPlan)) {
totalByDegree++;
}
} catch (Exception e) {
getLog().append(
RenderUtils.getFormatedResourceString(RESOURCE_BUNDLE,
"label.academicAdministration.setAbandonState.report.error")).append("\t")
.append(studentCurricularPlan.getRegistration().getStudent().getNumber()).append("\t")
.append(e.getMessage()).append("\n");
}
}
getLog().append(
RenderUtils.getFormatedResourceString(RESOURCE_BUNDLE,
"label.academicAdministration.setAbandonState.report.degreeTotal")).append(" ")
.append(degreeCurricularPlan.getName()).append("\t").append(totalByDegree).append("\n\n");
total += totalByDegree;
}
}
getLog().append("\n")
.append(RenderUtils.getFormatedResourceString(RESOURCE_BUNDLE,
"label.academicAdministration.setAbandonState.report.totalStudents")).append("\t").append(total);
}
@Atomic
private boolean processStudent(StudentCurricularPlan studentCurricularPlan) {
final ExecutionSemester startChecking = getWhenToAbandon().getPreviousExecutionPeriod();
final Registration registration = studentCurricularPlan.getRegistration();
RegistrationState lastRegistrationState =
registration.getLastRegistrationState(getWhenToAbandon().getExecutionYear().getPreviousExecutionYear());
if (hasValidRegistrationAgreement(registration) && registration.isDegreeAdministrativeOffice()
&& lastRegistrationState != null && lastRegistrationState.isActive()
&& !lastRegistrationState.getStateType().equals(RegistrationStateType.MOBILITY) && !registration.hasConcluded()) {
if (registration.getStartExecutionYear().isBefore(getWhenToAbandon().getExecutionYear())
&& !hasAnyEnrolmentInPeriodOrPrevious(registration, startChecking)) {
if (registration.hasStateType(getWhenToAbandon().getPreviousExecutionPeriod(),
RegistrationStateType.EXTERNAL_ABANDON)
|| registration.hasStateType(getWhenToAbandon(), RegistrationStateType.EXTERNAL_ABANDON)) {
return false;
}
final YearMonthDay now = new YearMonthDay();
final RegistrationState state =
RegistrationState.createRegistrationState(registration, null, (now.isBefore(getWhenToAbandon()
.getBeginDateYearMonthDay()) ? getWhenToAbandon().getBeginDateYearMonthDay() : now)
.toDateTimeAtMidnight(), RegistrationStateType.EXTERNAL_ABANDON);
state.setRemarks(RenderUtils.getFormatedResourceString(RESOURCE_BUNDLE,
"message.academicAdministration.abandonState.observations"));
sendEmail(registration);
getLog().append(registration.getStudent().getNumber()).append("\t")
.append(registration.getLastDegreeCurricularPlan().getName()).append("\n");
return true;
}
}
return false;
}
private boolean hasValidRegistrationAgreement(final Registration registration) {
return registration.getRegistrationProtocol() == null
|| (!registration.getRegistrationProtocol().isMilitaryAgreement() && !registration.getRegistrationProtocol()
.isMobilityAgreement());
}
private boolean hasAnyEnrolmentInPeriodOrPrevious(final Registration registration, final ExecutionSemester executionSemester) {
return evaluateAndCheckEnrolments(registration, executionSemester);
}
private boolean evaluateAndCheckEnrolments(final Registration registration, final ExecutionSemester semester) {
if (registration.getStartExecutionYear().isBeforeOrEquals(semester.getExecutionYear())) {
if (hasAnyCurriculumLines(registration, semester)) {
return true;
}
if (registration.getStartExecutionYear().isBeforeOrEquals(semester.getPreviousExecutionPeriod().getExecutionYear())) {
return hasAnyCurriculumLines(registration, semester.getPreviousExecutionPeriod());
}
}
return true;
}
private boolean hasAnyCurriculumLines(final Registration registration, final ExecutionSemester semester) {
final AndPredicate<CurriculumModule> andPredicate = new AndPredicate<CurriculumModule>();
andPredicate.add(new CurriculumModulePredicateByType(CurriculumLine.class));
andPredicate.add(new CurriculumLinePredicateByExecutionSemester(semester));
for (final StudentCurricularPlan studentCurricularPlan : registration.getStudentCurricularPlansSet()) {
if (studentCurricularPlan.hasAnyCurriculumModules(andPredicate)) {
return true;
}
}
return false;
}
private class CurriculumLinePredicateByExecutionSemester extends Predicate<CurriculumModule> {
private final ExecutionSemester semester;
private CurriculumLinePredicateByExecutionSemester(final ExecutionSemester semester) {
this.semester = semester;
}
@Override
public boolean eval(final CurriculumModule module) {
if (!module.isCurriculumLine()) {
return false;
}
if (module.isEnrolment()) {
return ((Enrolment) module).isValid(semester);
}
return ((CurriculumLine) module).getExecutionPeriod().equals(semester);
}
}
private void sendEmail(final Registration registration) {
final Person person = registration.getPerson();
SystemSender systemSender = Bennu.getInstance().getSystemSender();
List<Recipient> recipientList = new ArrayList<Recipient>();
recipientList.add(new Recipient(UserGroup.of(person.getUser())));
String body = buildMessage(registration);
String subject =
RenderUtils
.getFormatedResourceString(RESOURCE_BUNDLE, "message.academicAdministration.abandonState.mail.subject");
new Message(systemSender, systemSender.getConcreteReplyTos(), recipientList, null, null, subject, body,
new HashSet<String>());
}
private String buildMessage(final Registration registration) {
return RenderUtils.getFormatedResourceString(RESOURCE_BUNDLE, "message.academicAdministration.abandonState.mail.body",
registration.getLastStudentCurricularPlan().getName(), getWhenToAbandon().getQualifiedName(), getWhenToAbandon()
.getPreviousExecutionPeriod().getPreviousExecutionPeriod().getQualifiedName(), getWhenToAbandon()
.getPreviousExecutionPeriod().getQualifiedName());
}
public ExecutionSemester getWhenToAbandon() {
return whenToAbandon;
}
public void setWhenToAbandon(ExecutionSemester whenToAbandon) {
this.whenToAbandon = whenToAbandon;
}
public StringBuilder getLog() {
return log;
}
public void setLog(StringBuilder log) {
this.log = log;
}
}