/** * Copyright © 2011 Instituto Superior Técnico * * This file is part of FenixEdu GIAF Contracts. * * FenixEdu GIAF Contracts 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 GIAF Contracts 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 GIAF Contracts. If not, see <http://www.gnu.org/licenses/>. */ package pt.ist.fenixedu.contracts.domain.organizationalStructure; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.List; import org.apache.commons.beanutils.BeanComparator; import org.apache.commons.collections.comparators.ComparatorChain; import org.fenixedu.academic.domain.DomainObjectUtil; import org.fenixedu.academic.domain.ExecutionInterval; import org.fenixedu.academic.domain.ExecutionSemester; import org.fenixedu.academic.domain.ExecutionYear; import org.fenixedu.academic.domain.Person; import org.fenixedu.academic.domain.Teacher; import org.fenixedu.academic.domain.exceptions.DomainException; import org.fenixedu.academic.domain.organizationalStructure.Accountability; import org.fenixedu.academic.domain.organizationalStructure.AccountabilityTypeEnum; import org.fenixedu.academic.domain.organizationalStructure.Party; import org.fenixedu.academic.domain.organizationalStructure.Unit; import org.joda.time.YearMonthDay; import pt.ist.fenixframework.Atomic; public class PersonFunction extends PersonFunction_Base { public final static Comparator<PersonFunction> COMPARATOR_BY_BEGIN_DATE = new ComparatorChain(); public final static Comparator<PersonFunction> COMPARATOR_BY_PERSON_NAME = new ComparatorChain(); static { ((ComparatorChain) COMPARATOR_BY_BEGIN_DATE).addComparator(new BeanComparator("beginDate")); ((ComparatorChain) COMPARATOR_BY_BEGIN_DATE).addComparator(DomainObjectUtil.COMPARATOR_BY_ID); ((ComparatorChain) COMPARATOR_BY_PERSON_NAME).addComparator(new BeanComparator("person.name")); ((ComparatorChain) COMPARATOR_BY_PERSON_NAME).addComparator(DomainObjectUtil.COMPARATOR_BY_ID); } public PersonFunction(Party parentParty, Party childParty, Function function, YearMonthDay begin, YearMonthDay end, Double credits) { super(); setParentParty(parentParty); setChildParty(childParty); setAccountabilityType(function); setCredits(credits); setOccupationInterval(begin, end); } public PersonFunction(Party parentParty, Party childParty, Function function, ExecutionInterval executionInterval, Double credits) { super(); setParentParty(parentParty); setChildParty(childParty); setAccountabilityType(function); setCredits(credits); setOccupationInterval(executionInterval); } public PersonFunction(Party parentParty, Party childParty, Function function, YearMonthDay begin, YearMonthDay end) { this(parentParty, childParty, function, begin, end, 0.0); } public PersonFunction(Person parentParty, Person childParty, Function function, YearMonthDay begin, YearMonthDay end) { super(); setParentParty(parentParty); setChildParty(childParty); setAccountabilityType(function); setCredits(0.0); setOccupationInterval(begin, end); } protected PersonFunction() { super(); } @Override public YearMonthDay getBeginDate() { return getExecutionInterval() != null ? getExecutionInterval().getBeginDateYearMonthDay() : super.getBeginDate(); } @Override public YearMonthDay getEndDate() { return getExecutionInterval() != null ? getExecutionInterval().getEndDateYearMonthDay() : super.getEndDate(); } @Override protected boolean checkDateInterval() { return getExecutionInterval() != null ? true : super.checkDateInterval(); } public void edit(YearMonthDay begin, YearMonthDay end, Double credits) { setCredits(credits); setOccupationInterval(begin, end); } @Override public void setChildParty(Party childParty) { if (childParty == null || !childParty.isPerson()) { throw new DomainException("error.invalid.child.party"); } super.setChildParty(childParty); } @Override public void setParentParty(Party parentParty) { if (parentParty == null || !parentParty.isUnit()) { throw new DomainException("error.invalid.parent.party"); } super.setParentParty(parentParty); } public void setParentParty(Person parentParty) { if (parentParty == null) { throw new DomainException("error.invalid.parent.party"); } super.setParentParty(parentParty); } public void setOccupationInterval(ExecutionInterval executionInterval) { checkPersonFunctionDatesIntersection(getPerson(), getUnit(), getFunction(), executionInterval.getBeginDateYearMonthDay(), executionInterval.getEndDateYearMonthDay()); super.setExecutionInterval(executionInterval); } public void setOccupationInterval(YearMonthDay beginDate, YearMonthDay endDate) { checkPersonFunctionDatesIntersection(getPerson(), getUnit(), getFunction(), beginDate, endDate); super.setBeginDate(beginDate); super.setEndDate(endDate); } @Override public void setBeginDate(YearMonthDay beginDate) { throw new DomainException("error.invalid.operation"); } @Override public void setEndDate(YearMonthDay endDate) { throw new DomainException("error.invalid.operation"); } @Override public Double getCredits() { if (super.getCredits() == null) { return 0d; } return super.getCredits(); } public Person getPerson() { return (Person) getChildParty(); } public Unit getUnit() { return getParentParty() instanceof Unit ? (Unit) getParentParty() : null; } public Function getFunction() { return (Function) getAccountabilityType(); } private void checkPersonFunctionDatesIntersection(Person person, Unit unit, Function function, YearMonthDay begin, YearMonthDay end) { checkBeginDateAndEndDate(begin, end); for (PersonFunction personFunction : PersonFunction.getPersonFunctions(person, unit, false, null, null)) { if (!personFunction.equals(this) && personFunction.getFunction().equals(function) && personFunction.checkDatesIntersections(begin, end)) { throw new DomainException("error.personFunction.dates.intersection.for.same.function"); } } } private boolean checkDatesIntersections(YearMonthDay begin, YearMonthDay end) { return ((end == null || !getBeginDate().isAfter(end)) && (getEndDate() == null || !getEndDate().isBefore(begin))); } private void checkBeginDateAndEndDate(YearMonthDay begin, YearMonthDay end) { if (begin == null) { throw new DomainException("error.personFunction.no.beginDate"); } if (end == null) { throw new DomainException("error.personFunction.no.endDate"); } if (end != null && begin.isAfter(end)) { throw new DomainException("error.personFunction.endDateBeforeBeginDate"); } } public boolean hasCredits() { return getCredits() > 0d; } @Override @Atomic public void delete() { DomainException.throwWhenDeleteBlocked(getDeletionBlockers()); if (getCurricularYear() != null) { setCurricularYear(null); } setExecutionInterval(null); super.delete(); } public static List<Function> getActiveInherentPersonFunctions(Person person) { final List<Function> inherentFunctions = new ArrayList<Function>(); for (final PersonFunction accountability : getActivePersonFunctions(person)) { inherentFunctions.addAll(accountability.getFunction().getInherentFunctionsSet()); } return inherentFunctions; } public static List<PersonFunction> getManagementFunctions(Teacher teacher, ExecutionSemester executionSemester) { List<PersonFunction> personFunctions = new ArrayList<PersonFunction>(); for (PersonFunction personFunction : (Collection<PersonFunction>) teacher.getPerson().getParentAccountabilities( AccountabilityTypeEnum.MANAGEMENT_FUNCTION, PersonFunction.class)) { if (personFunction.belongsToPeriod(executionSemester.getBeginDateYearMonthDay(), executionSemester.getEndDateYearMonthDay())) { personFunctions.add(personFunction); } } return personFunctions; } public static List<PersonFunction> getPersonFunctions(Person person, Unit unit, boolean includeSubUnits, Boolean active, Boolean virtual, AccountabilityTypeEnum accountabilityTypeEnum) { final List<PersonFunction> result = new ArrayList<PersonFunction>(); Collection<Unit> allSubUnits = Collections.emptyList(); if (includeSubUnits) { allSubUnits = unit.getAllSubUnits(); } final YearMonthDay today = new YearMonthDay(); final AccountabilityTypeEnum accountabilityTypeEnum1 = accountabilityTypeEnum; for (final PersonFunction personFunction : PersonFunction.getPersonFunctions(person, accountabilityTypeEnum1)) { if (active != null && personFunction.isActive(today) == !active) { continue; } if (virtual != null && personFunction.getFunction().isVirtual() == !virtual) { continue; } final Unit functionUnit = personFunction.getUnit(); if (unit == null || functionUnit.equals(unit) || includeSubUnits && allSubUnits.contains(functionUnit)) { result.add(personFunction); } } return result; } public static List<PersonFunction> getPersonFunctions(Person person, Party party, boolean includeSubUnits, Boolean active, Boolean virtual, AccountabilityTypeEnum accountabilityTypeEnum) { if (party.isUnit()) { return PersonFunction.getPersonFunctions(person, (Unit) party, includeSubUnits, active, virtual, AccountabilityTypeEnum.MANAGEMENT_FUNCTION); } final List<PersonFunction> result = new ArrayList<PersonFunction>(); final YearMonthDay today = new YearMonthDay(); for (final PersonFunction personFunction : PersonFunction.getPersonFunctions(person, accountabilityTypeEnum)) { if (active != null && personFunction.isActive(today) == !active) { continue; } if (virtual != null && personFunction.getFunction().isVirtual() == !virtual) { continue; } if (personFunction.getParentParty().isPerson()) { final Person functionPerson = (Person) personFunction.getParentParty(); if (party == null || functionPerson.equals(party)) { result.add(personFunction); } } } return result; } public static List<PersonFunction> getPersonFuntions(Person person, AccountabilityTypeEnum accountabilityTypeEnum, YearMonthDay begin, YearMonthDay end) { final List<PersonFunction> result = new ArrayList<PersonFunction>(); for (final Accountability accountability : (Collection<PersonFunction>) person.getParentAccountabilities( accountabilityTypeEnum, PersonFunction.class)) { if (accountability.belongsToPeriod(begin, end)) { result.add((PersonFunction) accountability); } } return result; } public static List<PersonFunction> getActivePersonFunctions(Person person) { return PersonFunction.getPersonFunctions(person, null, false, true, false); } public static List<PersonFunction> getInactivePersonFunctions(Person person) { return PersonFunction.getPersonFunctions(person, null, false, false, false); } /** * The main difference between this method and {@link #getActivePersonFunctions()} is that person functions with a virtual * function are also included. This method also collects person functions from the given unit and all subunits. * * @see Function#isVirtual() */ public static List<PersonFunction> getAllActivePersonFunctions(Person person, Unit unit) { return PersonFunction.getPersonFunctions(person, unit, true, true, null); } public static Collection<PersonFunction> getPersonFunctions(Person person, Function function) { final Collection<PersonFunction> personFunctions = (Collection<PersonFunction>) person.getParentAccountabilities(AccountabilityTypeEnum.MANAGEMENT_FUNCTION, PersonFunction.class); final Iterator<PersonFunction> iterator = personFunctions.iterator(); while (iterator.hasNext()) { final PersonFunction element = iterator.next(); if (element.getFunction() == function) { continue; } iterator.remove(); } return personFunctions; } public static List<PersonFunction> getPersonFuntions(Person person, YearMonthDay begin, YearMonthDay end) { return PersonFunction.getPersonFuntions(person, AccountabilityTypeEnum.MANAGEMENT_FUNCTION, begin, end); } public static List<PersonFunction> getPersonFunctions(Person person, Unit unit, boolean includeSubUnits, Boolean active, Boolean virtual) { return PersonFunction.getPersonFunctions(person, unit, includeSubUnits, active, virtual, AccountabilityTypeEnum.MANAGEMENT_FUNCTION); } public static Collection<PersonFunction> getPersonFunctions(Person person, AccountabilityTypeEnum accountabilityTypeEnum) { return (Collection<PersonFunction>) person.getParentAccountabilities(accountabilityTypeEnum, PersonFunction.class); } public static PersonFunction getActiveGGAEDelegatePersonFunction(Person person) { for (final PersonFunction personFunction : PersonFunction.getActivePersonFunctions(person)) { if (personFunction.getFunction().getFunctionType().equals(FunctionType.DELEGATE_OF_GGAE)) { return personFunction; } } return null; } public static List<PersonFunction> getAllGGAEDelegatePersonFunctions(Person person) { final List<PersonFunction> result = new ArrayList<PersonFunction>(); for (final PersonFunction personFunction : (Collection<PersonFunction>) person.getParentAccountabilities( AccountabilityTypeEnum.MANAGEMENT_FUNCTION, PersonFunction.class)) { if (personFunction.getFunction().getFunctionType().equals(FunctionType.DELEGATE_OF_GGAE)) { result.add(personFunction); } } return result; } public static Person getActiveUnitCoordinator(Unit unit) { return PersonFunction.getActiveUnitCoordinator(unit, new YearMonthDay()); } private static Collection<Function> getFunctions(Unit unit, final FunctionType functionType) { final Collection<Function> result = new HashSet<Function>(); for (Function function : unit.getFunctionsSet()) { if (function.getFunctionType() == functionType) { result.add(function); } } return result; } private static Function getUnitCoordinatorFunction(Unit unit) { final Collection<Function> possibleCoordinators = getFunctions(unit, FunctionType.ASSIDUOUSNESS_RESPONSIBLE); if (possibleCoordinators.isEmpty()) { throw new DomainException("Unit.no.one.entitled.to.be.unit.coordinator"); } else if (possibleCoordinators.size() > 1) { throw new DomainException("Unit.more.than.one.person.entitled.to.be.unit.coordinator"); } return possibleCoordinators.iterator().next(); } public static Person getActiveUnitCoordinator(Unit unit, YearMonthDay yearMonthDay) { for (final Accountability accountability : getUnitCoordinatorFunction(unit).getAccountabilitiesSet()) { if (accountability instanceof PersonFunction && accountability.isActive(yearMonthDay)) { return ((PersonFunction) accountability).getPerson(); } } return null; } public static List<PersonFunction> getPersonFunctions(Function function) { List<PersonFunction> personFunctions = new ArrayList<PersonFunction>(); for (Accountability accountability : function.getAccountabilitiesSet()) { if (accountability instanceof PersonFunction) { personFunctions.add((PersonFunction) accountability); } } return personFunctions; } public static List<PersonFunction> getActivePersonFunctions(Function function) { List<PersonFunction> personFunctions = new ArrayList<PersonFunction>(); YearMonthDay currentDate = new YearMonthDay(); for (Accountability accountability : function.getAccountabilitiesSet()) { if (accountability instanceof PersonFunction && accountability.isActive(currentDate)) { personFunctions.add((PersonFunction) accountability); } } return personFunctions; } public static List<PersonFunction> getActivePersonFunctionsByPerson(Function function, Person person) { List<PersonFunction> personFunctions = new ArrayList<PersonFunction>(); YearMonthDay currentDate = new YearMonthDay(); for (Accountability accountability : function.getAccountabilitiesSet()) { if (accountability instanceof PersonFunction && accountability.isActive(currentDate)) { PersonFunction personFunction = (PersonFunction) accountability; if (personFunction.getPerson().equals(person)) { personFunctions.add(personFunction); } } } return personFunctions; } public static List<PersonFunction> getActivePersonFunctionsStartingIn(Function function, ExecutionYear executionYear) { List<PersonFunction> personFunctions = new ArrayList<PersonFunction>(); for (Accountability accountability : function.getAccountabilitiesSet()) { if (accountability instanceof PersonFunction) { if (accountability.getBeginDate().isBefore(executionYear.getEndDateYearMonthDay()) && (accountability.getEndDate() == null || accountability.getEndDate().isAfter( executionYear.getBeginDateYearMonthDay()))) { personFunctions.add((PersonFunction) accountability); } } } return personFunctions; } }