/**
* Copyright © 2002 Instituto Superior Técnico
*
* This file is part of FenixEdu Academic.
*
* FenixEdu Academic 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.
*
* FenixEdu Academic 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 FenixEdu Academic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.fenixedu.academic.domain.candidacyProcess;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.fenixedu.academic.domain.Attends;
import org.fenixedu.academic.domain.ExecutionCourse;
import org.fenixedu.academic.domain.ExecutionInterval;
import org.fenixedu.academic.domain.Person;
import org.fenixedu.academic.domain.accounting.paymentCodes.IndividualCandidacyPaymentCode;
import org.fenixedu.academic.domain.exceptions.DomainException;
import org.fenixedu.academic.domain.period.CandidacyPeriod;
import org.fenixedu.academic.domain.person.IDDocumentType;
import org.fenixedu.academic.domain.student.Registration;
import org.fenixedu.academic.domain.student.Student;
import org.fenixedu.academic.dto.person.ChoosePersonBean;
import org.fenixedu.academic.dto.person.PersonBean;
import org.fenixedu.academic.util.Bundle;
import org.fenixedu.bennu.core.domain.Bennu;
import org.fenixedu.bennu.core.i18n.BundleUtil;
import org.joda.time.DateTime;
import org.joda.time.DateTimeFieldType;
import org.joda.time.LocalDate;
abstract public class IndividualCandidacyProcess extends IndividualCandidacyProcess_Base {
static final public Comparator<IndividualCandidacyProcess> COMPARATOR_BY_CANDIDACY_PERSON =
new Comparator<IndividualCandidacyProcess>() {
@Override
public int compare(IndividualCandidacyProcess o1, IndividualCandidacyProcess o2) {
return IndividualCandidacyPersonalDetails.COMPARATOR_BY_NAME_AND_ID.compare(o1.getPersonalDetails(),
o2.getPersonalDetails());
}
};
protected IndividualCandidacyProcess() {
super();
setAccessHash(RandomStringUtils.random(16, true, true));
setProcessChecked(Boolean.FALSE);
}
/**
* This method is a refactor of IndividualCandidacyProcess subclasses
* initialization The initialization is composed by parameters checking,
* IndividualCandidacy creation and candidacy information setting
*
* @param bean
*/
protected void init(IndividualCandidacyProcessBean bean) {
checkParameters(bean.getCandidacyProcess());
if (bean.getPublicCandidacyHashCode() == null) {
throw new DomainException("error.IndividualCandidacy.hash.code.is.null");
}
if (existsIndividualCandidacyProcessForDocumentId(bean.getCandidacyProcess(), bean.getPersonBean().getIdDocumentType(),
bean.getPersonBean().getDocumentIdNumber())) {
throw new DomainException("error.IndividualCandidacy.exists.for.same.document.id");
}
setCandidacyProcess(bean.getCandidacyProcess());
createIndividualCandidacy(bean);
/*
* 11/04/2009 - An external candidacy submission requires documents like
* identification and habilitation certificate documents
*/
setCandidacyHashCode(bean.getPublicCandidacyHashCode());
setCandidacyDocumentFiles(bean);
setProcessCodeForThisIndividualCandidacy(bean.getCandidacyProcess());
}
protected boolean existsIndividualCandidacyProcessForDocumentId(final CandidacyProcess process, IDDocumentType documentType,
String identification) {
return process.getOpenChildProcessByDocumentId(documentType, identification) != null;
}
protected void setProcessCodeForThisIndividualCandidacy(CandidacyProcess process) {
CandidacyPeriod period = process.getCandidacyPeriod();
String beginExecutionYear =
String.valueOf(period.getExecutionInterval().getBeginDateYearMonthDay().get(DateTimeFieldType.year())).substring(
2, 4);
String endExecutionYear =
String.valueOf(period.getExecutionInterval().getEndDateYearMonthDay().get(DateTimeFieldType.year())).substring(2,
4);
setProcessCode(beginExecutionYear + endExecutionYear + getExternalId());
}
protected void setCandidacyDocumentFiles(IndividualCandidacyProcessBean bean) {
/*
* 06/07/2009 - Lots of candidates camplaint about the upload of
* documents in application submission. The upload of documents will be
* done in application edit right after submission
*/
if (bean.getPhotoDocument() != null) {
bindIndividualCandidacyDocumentFile(bean.getPhotoDocument());
}
}
protected abstract void checkParameters(CandidacyProcess process);
/**
* Each type of CandidacyProcess has its own IndividualCandidacy. Each
* subclass must implement this method that will instantiate the specific
* IndividualCandidacy
*
* @param bean
*/
protected abstract void createIndividualCandidacy(IndividualCandidacyProcessBean bean);
public ExecutionInterval getCandidacyExecutionInterval() {
return getCandidacyProcess() != null ? getCandidacyProcess().getCandidacyExecutionInterval() : null;
}
public boolean isFor(final ExecutionInterval executionInterval) {
return getCandidacyExecutionInterval() == executionInterval;
}
public DateTime getCandidacyStart() {
return getCandidacyProcess() != null ? getCandidacyProcess().getCandidacyStart() : null;
}
public DateTime getCandidacyEnd() {
return getCandidacyProcess() != null ? getCandidacyProcess().getCandidacyEnd() : null;
}
public LocalDate getCandidacyDate() {
return getCandidacy().getCandidacyDate();
}
public boolean hasOpenCandidacyPeriod() {
return getCandidacyProcess() != null && getCandidacyProcess().hasOpenCandidacyPeriod();
}
public boolean hasOpenCandidacyPeriod(final DateTime date) {
return getCandidacyProcess() != null && getCandidacyProcess().hasOpenCandidacyPeriod(date);
}
public CandidacyProcessState getState() {
return getCandidacyProcess() != null ? getCandidacyProcess().getState() : null;
}
public boolean isInStandBy() {
return getCandidacyProcess() != null && getCandidacyProcess().isInStandBy();
}
public boolean isSentToJury() {
return getCandidacyProcess() != null && getCandidacyProcess().isSentToJury();
}
public boolean isSentToCoordinator() {
return getCandidacyProcess() != null && getCandidacyProcess().isSentToCoordinator();
}
public boolean isSentToScientificCouncil() {
return getCandidacyProcess() != null && getCandidacyProcess().isSentToScientificCouncil();
}
public boolean isPublished() {
return getCandidacyProcess() != null && getCandidacyProcess().isPublished();
}
protected boolean hasAnyPaymentForCandidacy() {
return getCandidacy().hasAnyPayment();
}
protected void cancelCandidacy(final Person person) {
getCandidacy().cancel(person);
}
protected void rejectCandidacy(final Person person) {
getCandidacy().reject(person);
}
protected void revertToStandBy(final Person person) {
getCandidacy().revertToStandBy(person);
}
public IndividualCandidacyState getCandidacyState() {
return getCandidacy().getState();
}
public boolean isCandidacyValid() {
return !isCandidacyCancelled() && (isEventCanceledOrNoEvent() || isCandidacyDebtPayed());
}
private boolean isEventCanceledOrNoEvent() {
return getCandidacy().getEvent() == null || getCandidacy().getEvent().isCancelled();
}
public boolean isCandidacyInStandBy() {
return getCandidacy().isInStandBy();
}
public boolean isCandidacyAccepted() {
return getCandidacy().isAccepted();
}
public boolean isCandidacyNotAccepted() {
return getCandidacy().isNotAccepted();
}
public boolean isCandidacyRejected() {
return getCandidacy().isRejected();
}
public boolean isCandidacyCancelled() {
return getCandidacy().isCancelled();
}
public boolean isCandidacyDebtPayed() {
return getCandidacy().isDebtPayed();
}
public IndividualCandidacyPersonalDetails getPersonalDetails() {
return getCandidacy().getPersonalDetails();
}
public boolean hasCandidacyPerson() {
return getPersonalDetails() != null;
}
public Student getCandidacyStudent() {
return getPersonalDetails().getStudent();
}
public boolean hasCandidacyStudent() {
return getCandidacyStudent() != null;
}
public Registration getCandidacyRegistration() {
return getCandidacy().getRegistration();
}
public boolean hasRegistrationForCandidacy() {
return getCandidacy().getRegistration() != null;
}
@Override
public String getDisplayName() {
return BundleUtil.getString(Bundle.CASE_HANDLEING, getClass().getSimpleName());
}
protected void editPersonalCandidacyInformation(final PersonBean personBean) {
getCandidacy().editPersonalCandidacyInformationPublic(personBean);
}
protected void editPersonalCandidacyInformationPublic(final PersonBean personBean) {
getCandidacy().editPersonalCandidacyInformationPublic(personBean);
}
/**
* Find an individual candidacy process given a kind of candidacy process,
* an email and an access hash
*/
public static IndividualCandidacyProcess findIndividualCandidacyProcess(
final Class<? extends IndividualCandidacyProcess> individualCandidacyProcessClass, String email, String accessHash) {
if (StringUtils.isEmpty(email) || StringUtils.isEmpty(accessHash)) {
return null;
}
Set<IndividualCandidacyProcess> candidacies = getAllInstancesOf(individualCandidacyProcessClass);
for (IndividualCandidacyProcess individualCandidacyProcess : candidacies) {
if (email.equals(individualCandidacyProcess.getPersonalDetails().getEmail())
&& accessHash.equals(individualCandidacyProcess.getAccessHash())) {
return individualCandidacyProcess;
}
}
return null;
}
public static <T extends IndividualCandidacyProcess> T findIndividualCandidacyProcessByCode(
Class<T> individualCandidacyProcessClass, final String processCode) {
Set<IndividualCandidacyProcess> candidacies = getAllInstancesOf(individualCandidacyProcessClass);
for (IndividualCandidacyProcess process : candidacies) {
if (processCode.equals(process.getProcessCode())) {
return (T) process;
}
}
return null;
}
public IndividualCandidacyDocumentFile getPhoto() {
IndividualCandidacyDocumentFile photo = getActiveFileForType(IndividualCandidacyDocumentFileType.PHOTO);
return photo;
}
public IndividualCandidacyDocumentFile getActiveFileForType(IndividualCandidacyDocumentFileType type) {
for (IndividualCandidacyDocumentFile document : this.getCandidacy().getDocumentsSet()) {
if (document.getCandidacyFileType().equals(type) && document.getCandidacyFileActive()) {
return document;
}
}
return null;
}
public List<IndividualCandidacyDocumentFile> getAllFilesForType(IndividualCandidacyDocumentFileType type) {
List<IndividualCandidacyDocumentFile> files = new ArrayList<IndividualCandidacyDocumentFile>();
for (IndividualCandidacyDocumentFile document : this.getCandidacy().getDocumentsSet()) {
if (document.getCandidacyFileType().equals(type)) {
files.add(document);
}
}
return files;
}
public void bindIndividualCandidacyDocumentFile(CandidacyProcessDocumentUploadBean uploadBean) {
if (uploadBean.getDocumentFile() != null) {
executeOperationsBeforeDocumentFileBinding(uploadBean.getDocumentFile());
uploadBean.getDocumentFile().addIndividualCandidacy(this.getCandidacy());
}
}
protected abstract void executeOperationsBeforeDocumentFileBinding(IndividualCandidacyDocumentFile documentFile);
public abstract List<IndividualCandidacyDocumentFileType> getMissingRequiredDocumentFiles();
public List<ExecutionCourse> getMissingShifts() {
HashSet<ExecutionCourse> missingShifts = new HashSet<ExecutionCourse>();
for (Attends attends : this.getCandidacy().getPersonalDetails().getPerson().getCurrentAttends()) {
if (!attends.hasAllShiftEnrolments()) {
missingShifts.add(attends.getExecutionCourse());
}
}
return new ArrayList<ExecutionCourse>(missingShifts);
}
public boolean isProcessMissingRequiredDocumentFiles() {
return !getMissingRequiredDocumentFiles().isEmpty();
}
public List<IndividualCandidacyDocumentFile> getActiveDocumentFiles() {
List<IndividualCandidacyDocumentFile> documentList = new ArrayList<IndividualCandidacyDocumentFile>();
CollectionUtils.select(getCandidacy().getDocumentsSet(), new Predicate() {
@Override
public boolean evaluate(Object arg0) {
IndividualCandidacyDocumentFile file = (IndividualCandidacyDocumentFile) arg0;
return file.getCandidacyFileActive();
}
}, documentList);
return documentList;
}
public Boolean getAllRequiredFilesUploaded() {
return getMissingRequiredDocumentFiles().isEmpty();
}
public Boolean getCandidacyHasVatDocument() {
return getActiveFileForType(IndividualCandidacyDocumentFileType.VAT_CARD_DOCUMENT) != null;
}
/**
* Check if the process is complete i.e. if it has all required candidate
* personal information and candidacy information like the chosen degree.
*/
public abstract Boolean isCandidacyProcessComplete();
public Boolean isCandidacyInternal() {
return this.getCandidacy().isCandidacyInternal();
}
public Boolean getIsCandidacyInternal() {
return this.isCandidacyInternal();
}
public void bindPerson(ChoosePersonBean choosePersonBean) {
this.getCandidacy().bindPerson(choosePersonBean);
}
public IndividualCandidacyPaymentCode getAssociatedPaymentCode() {
if (getCandidacy().getEvent() != null) {
return (IndividualCandidacyPaymentCode) (getCandidacy().getEvent().getAllPaymentCodes().isEmpty() ? null : getCandidacy()
.getEvent().getAllPaymentCodes().iterator().next());
}
return null;
}
public Boolean getIsCandidateWithRoles() {
return this.getCandidacy().getPersonalDetails().hasAnyRole();
}
protected void editCandidacyHabilitations(IndividualCandidacyProcessBean bean) {
this.getCandidacy().editFormationEntries(bean.getFormationConcludedBeanList(), bean.getFormationNonConcludedBeanList());
}
protected void editPrecedentDegreeInformation(IndividualCandidacyProcessBean bean) {
getCandidacy().editPrecedentDegreeInformation(bean);
}
private static Set<IndividualCandidacyProcess> getAllInstancesOf(final Class<? extends IndividualCandidacyProcess> type) {
return Bennu.getInstance().getProcessesSet().stream().filter((type)::isInstance).map(p -> (IndividualCandidacyProcess) p)
.collect(Collectors.toSet());
}
}