/* * @(#)MissionYear.java * * Copyright 2010 Instituto Superior Tecnico * Founding Authors: Luis Cruz, Nuno Ochoa, Paulo Abrantes * * https://fenix-ashes.ist.utl.pt/ * * This file is part of the Expenditure Tracking Module. * * The Expenditure Tracking Module 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. * * The Expenditure Tracking Module 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 the Expenditure Tracking Module. If not, see <http://www.gnu.org/licenses/>. * */ package module.mission.domain; import java.util.Calendar; import java.util.Collection; import java.util.Comparator; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import java.util.stream.Collectors; import java.util.stream.Stream; import org.fenixedu.bennu.core.domain.User; import org.fenixedu.bennu.core.security.Authenticate; import org.joda.time.DateTime; import module.mission.domain.util.MissionAuthorizationMap; import module.mission.domain.util.MissionPendingProcessCounter; import module.mission.domain.util.MissionState; import module.organization.domain.Party; import module.organization.domain.Person; import module.workflow.widgets.ProcessListWidget; import pt.ist.expenditureTrackingSystem.domain.authorizations.Authorization; import pt.ist.expenditureTrackingSystem.domain.organization.Unit; import pt.ist.fenixframework.Atomic; /** * * @author João Neves * @author Luis Cruz * */ public class MissionYear extends MissionYear_Base { static { ProcessListWidget.register(new MissionPendingProcessCounter()); } public static final Comparator<MissionYear> COMPARATOR_BY_YEAR = new Comparator<MissionYear>() { @Override public int compare(MissionYear o1, MissionYear o2) { final Integer year1 = o1.getYear(); final Integer year2 = o2.getYear(); return year1.compareTo(year2); } }; public static Integer getBiggestYearCounter() { int biggestCounter = 0; for (MissionYear year : MissionSystem.getInstance().getMissionYearSet()) { if (year.getCounter() > biggestCounter) { biggestCounter = year.getCounter(); } } return biggestCounter; } private MissionYear(final int year) { super(); if (findMissionByYearAux(year) != null) { throw new Error("There can only be one! (MissionYear object for each year)"); } final int currentYear = Calendar.getInstance().get(Calendar.YEAR); if (year != currentYear && year != currentYear + 1) { throw new Error("There is absolutly no need to create a year other that the current and the next!"); } setMissionSystem(MissionSystem.getInstance()); setYear(new Integer(year)); setCounter(Integer.valueOf(0)); } private static MissionYear findMissionByYearAux(final int year) { final MissionSystem missionSystem = MissionSystem.getInstance(); for (final MissionYear missionYear : missionSystem.getMissionYearSet()) { if (missionYear.getYear().intValue() == year) { return missionYear; } } return null; } public static MissionYear findMissionYear(final int year) { return findMissionByYearAux(year); } @Atomic public static MissionYear findOrCreateMissionYear(final int year) { final MissionYear missionYear = findMissionByYearAux(year); return missionYear == null ? new MissionYear(year) : missionYear; } public Integer nextNumber() { return getAndIncreaseNextNumber(); } private Integer getAndIncreaseNextNumber() { setCounter(getCounter().intValue() + 1); return getCounter(); } public static MissionYear getCurrentYear() { final int year = new DateTime().getYear(); return findOrCreateMissionYear(year); } private abstract class MissionProcessSearch { private final SortedSet<MissionProcess> result; abstract boolean shouldAdd(final MissionProcess missionProcess, final User user); private MissionProcessSearch() { result = new TreeSet<MissionProcess>(MissionProcess.COMPARATOR_BY_PROCESS_NUMBER); } private MissionProcessSearch(final SortedSet<MissionProcess> result) { this.result = result; } SortedSet<MissionProcess> search() { final User user = Authenticate.getUser(); for (final MissionProcess missionProcess : getMissionProcessSet()) { if (shouldAdd(missionProcess, user)) { result.add(missionProcess); } } return result; } } private class PendingAprovalSearch extends MissionProcessSearch { private PendingAprovalSearch() { } private PendingAprovalSearch(final SortedSet<MissionProcess> result) { super(result); } @Override boolean shouldAdd(final MissionProcess missionProcess, final User user) { if (missionProcess.getCurrentOwner() != null && !missionProcess.isTakenByCurrentUser()) { return false; } if (missionProcess.isUnderConstruction() || missionProcess.getIsCanceled()) { return false; } if (missionProcess.isPendingApprovalBy(user)) { return true; } if (missionProcess.isCurrentUserAbleToAccessAnyQueues() && MissionState.VERIFICATION.isPending(missionProcess)) { return true; } return false; } } private class PendingVehicleAuthorizationSearch extends MissionProcessSearch { private PendingVehicleAuthorizationSearch() { } private PendingVehicleAuthorizationSearch(final SortedSet<MissionProcess> result) { super(result); } @Override boolean shouldAdd(final MissionProcess missionProcess, final User user) { if (!MissionSystem.getInstance().getVehicleAuthorizersSet().contains(user)) { return false; } if (missionProcess.isCanceled()) { return false; } if (!missionProcess.isApprovedByResponsible()) { return false; } if (missionProcess.getCurrentOwner() != null && !missionProcess.isTakenByCurrentUser()) { return false; } return missionProcess.getMission().isVehicleAuthorizationNeeded() && !missionProcess.getMission().areAllVehicleItemsAuthorized(); } } private class PendingAuthorizationSearch extends MissionProcessSearch { private PendingAuthorizationSearch() { } private PendingAuthorizationSearch(final SortedSet<MissionProcess> result) { super(result); } @Override boolean shouldAdd(final MissionProcess missionProcess, final User user) { if (missionProcess.getCurrentOwner() != null && !missionProcess.isTakenByCurrentUser()) { return false; } if (!missionProcess.isApproved()) { return false; } if (missionProcess.getIsCanceled()) { return false; } if (missionProcess.isPendingParticipantAuthorisationBy(user) && MissionState.PARTICIPATION_AUTHORIZATION.isPending(missionProcess)) { return true; } return (missionProcess.areAllParticipantsAuthorized() && missionProcess.hasAllAllocatedFunds() && missionProcess.isPendingDirectAuthorizationBy(user)); // return (missionProcess.areAllParticipantsAuthorized() && missionProcess.hasAllAllocatedFunds() // && isPendingDirectAuthorizationBy(missionProcess, user)); } private boolean isPendingDirectAuthorizationBy(MissionProcess missionProcess, User user) { final boolean pendingDirectAuthorizationBy = missionProcess.isPendingDirectAuthorizationBy(user); return (pendingDirectAuthorizationBy && missionProcess.hasBeenCheckedByUnderlings()) || (!pendingDirectAuthorizationBy && !missionProcess.isAuthorized() && !missionProcess.hasBeenCheckedByUnderlings() && missionProcess.isPendingCheckByUnderlings(user)); } } private class PendingFundAllocationSearch extends MissionProcessSearch { private PendingFundAllocationSearch() { } private PendingFundAllocationSearch(final SortedSet<MissionProcess> result) { super(result); } @Override boolean shouldAdd(final MissionProcess missionProcess, final User user) { return (missionProcess.getCurrentOwner() == null || missionProcess.isTakenByCurrentUser()) && (isPendingFundAllocation(missionProcess, user) || isPendingFundUnAllocation(missionProcess, user)); } private boolean isPendingFundAllocation(MissionProcess missionProcess, User user) { return missionProcess.isApproved() && !missionProcess.getIsCanceled() && (((!missionProcess.hasAnyProjectFinancer() || missionProcess.hasAllAllocatedProjectFunds()) && !missionProcess.hasAllAllocatedFunds() && missionProcess.canAllocateFund()) || (!missionProcess.hasAllAllocatedProjectFunds() && missionProcess.canAllocateProjectFund()) || (missionProcess.getMission().hasAnyFinancer() && missionProcess.hasAllAllocatedFunds() && !missionProcess.hasAllCommitmentNumbers() && missionProcess.isAccountingEmployee(user.getExpenditurePerson()))); } private boolean isPendingFundUnAllocation(final MissionProcess missionProcess, final User user) { return missionProcess.getIsCanceled().booleanValue() && ((missionProcess.hasAnyAllocatedFunds() && missionProcess.isAccountingEmployee(user.getExpenditurePerson())) || (missionProcess.hasAnyAllocatedProjectFunds()) && missionProcess.isProjectAccountingEmployee(user.getExpenditurePerson())); } } private class PendingProcessingPersonelInformationSearch extends MissionProcessSearch { private PendingProcessingPersonelInformationSearch() { } private PendingProcessingPersonelInformationSearch(final SortedSet<MissionProcess> result) { super(result); } @Override boolean shouldAdd(final MissionProcess missionProcess, final User user) { if (missionProcess.getCurrentOwner() != null && !missionProcess.isTakenByCurrentUser()) { return false; } if (missionProcess.isCurrentUserAbleToAccessAnyQueues() && MissionState.PERSONAL_INFORMATION_PROCESSING.isPending(missionProcess)) { return true; } if (missionProcess.isReadyForMissionTermination(user)) { return true; } if (missionProcess.isTerminated() && !missionProcess.isArchived() && missionProcess.canArchiveMission()) { return true; } return false; } } public SortedSet<MissionProcess> getPendingAproval() { return new PendingAprovalSearch().search(); } public SortedSet<MissionProcess> getPendingAproval(final SortedSet<MissionProcess> result) { return new PendingAprovalSearch(result).search(); } public SortedSet<MissionProcess> getPendingVehicleAuthorization() { return new PendingVehicleAuthorizationSearch().search(); } public SortedSet<MissionProcess> getPendingVehicleAuthorization(final SortedSet<MissionProcess> result) { return new PendingVehicleAuthorizationSearch(result).search(); } public SortedSet<MissionProcess> getPendingAuthorization() { return new PendingAuthorizationSearch().search(); } public SortedSet<MissionProcess> getPendingAuthorization(final SortedSet<MissionProcess> result) { return new PendingAuthorizationSearch(result).search(); } public SortedSet<MissionProcess> getPendingFundAllocation() { try { return new PendingFundAllocationSearch().search(); } catch (Throwable t) { t.printStackTrace(); throw new Error(t); } } public SortedSet<MissionProcess> getPendingFundAllocation(final SortedSet<MissionProcess> result) { try { return new PendingFundAllocationSearch(result).search(); } catch (Throwable t) { t.printStackTrace(); throw new Error(t); } } public SortedSet<MissionProcess> getDirectPendingFundAllocation() { try { return new MissionProcessSearch() { @Override boolean shouldAdd(final MissionProcess missionProcess, final User user) { return (missionProcess.getCurrentOwner() == null || missionProcess.isTakenByCurrentUser()) && (isPendingFundAllocation(missionProcess, user) || isPendingFundUnAllocation(missionProcess, user)); } private boolean isPendingFundAllocation(MissionProcess missionProcess, User user) { return missionProcess.isApproved() && !missionProcess.getIsCanceled() && (((!missionProcess.hasAnyProjectFinancer() || missionProcess.hasAllAllocatedProjectFunds()) && !missionProcess.hasAllAllocatedFunds() && missionProcess.canAllocateFund()) || (!missionProcess.hasAllAllocatedProjectFunds() && missionProcess.isDirectResponsibleForPendingProjectFundAllocation())); } private boolean isPendingFundUnAllocation(final MissionProcess missionProcess, final User user) { return missionProcess.getIsCanceled().booleanValue() && ((missionProcess.hasAnyAllocatedFunds() && missionProcess.isAccountingEmployee(user.getExpenditurePerson())) || (missionProcess.hasAnyAllocatedProjectFunds()) && missionProcess.isDirectProjectAccountingEmployee(user.getExpenditurePerson())); } }.search(); } catch (Throwable t) { t.printStackTrace(); throw new Error(t); } } public SortedSet<MissionProcess> getPendingProcessingPersonelInformation() { return new PendingProcessingPersonelInformationSearch().search(); } public SortedSet<MissionProcess> getPendingProcessingPersonelInformation(final SortedSet<MissionProcess> result) { return new PendingProcessingPersonelInformationSearch(result).search(); } public SortedSet<MissionProcess> getPendingDirectProcessingPersonelInformation() { MissionProcessSearch search = new MissionProcessSearch() { @Override boolean shouldAdd(final MissionProcess missionProcess, final User user) { if (missionProcess.getCurrentOwner() != null && !missionProcess.isTakenByCurrentUser()) { return false; } if (missionProcess.isCurrentUserAbleToAccessAnyQueues() && MissionState.PERSONAL_INFORMATION_PROCESSING.isPending(missionProcess)) { return true; } if (missionProcess.isCurrentUserAbleToAccessAnyQueues() && MissionState.VERIFICATION.isPending(missionProcess)) { return true; } if (missionProcess.isReadyForMissionTermination(user)) { return true; } if (missionProcess.isTerminated() && !missionProcess.isArchived() && missionProcess.canArchiveMissionDirect()) { return true; } return false; } }; return search.search(); } public SortedSet<MissionProcess> getRequested() { final User user = Authenticate.getUser(); final SortedSet<MissionProcess> result = new TreeSet<MissionProcess>(MissionProcess.COMPARATOR_BY_PROCESS_NUMBER); final Person person = user.getPerson(); if (person != null) { for (final Mission mission : person.getRequestedMissionsSet()) { final MissionProcess missionProcess = mission.getMissionProcess(); if (missionProcess.getMissionYear() == this && !missionProcess.getIsCanceled() && !missionProcess.isArchived()) { result.add(missionProcess); } } } return result; } private boolean hasValidAuthorization(final Set<Authorization> authorizations) { for (final Authorization authorization : authorizations) { if (authorization.isValid()) { return true; } } return false; } private boolean isDirectlyResponsibleFor(final User user, final pt.ist.expenditureTrackingSystem.domain.organization.Unit unit) { final Set<Authorization> authorizationsFromUnit = unit.getAuthorizationsSet(); if (getAuthorizations(user).anyMatch(a -> a.getUnit() == unit)) { return true; } if (hasValidAuthorization(authorizationsFromUnit)) { return false; } final pt.ist.expenditureTrackingSystem.domain.organization.Unit parentUnit = unit.getParentUnit(); return parentUnit != null && isDirectlyResponsibleFor(user, parentUnit); } private Stream<Authorization> getAuthorizations(final User user) { return user.getExpenditurePerson().getAuthorizationsSet().stream().filter(a -> a.isValid()); } public SortedSet<MissionProcess> getAprovalResponsible() { final SortedSet<MissionProcess> result = new TreeSet<MissionProcess>(MissionProcess.COMPARATOR_BY_PROCESS_NUMBER); final User user = Authenticate.getUser(); if (user.getExpenditurePerson() != null) { for (final MissionProcess missionProcess : getMissionProcessSet()) { if (!missionProcess.getIsCanceled() && !missionProcess.isArchived()) { final Mission mission = missionProcess.getMission(); final Party missionResponsible = mission.getMissionResponsible(); if (missionResponsible != null) { if (missionResponsible.isPerson()) { if (missionResponsible == user.getPerson()) { result.add(missionProcess); } } else if (missionResponsible.isUnit() && getAuthorizations(user).findAny().orElse(null) != null) { final pt.ist.expenditureTrackingSystem.domain.organization.Unit unit = getExpenditureUnit(mission, (module.organization.domain.Unit) missionResponsible); if (unit != null && isDirectlyResponsibleFor(user, unit)) { result.add(missionProcess); } } } } } } return result; } private Unit getExpenditureUnit(final Mission mission, final module.organization.domain.Unit unit) { return unit.getExpenditureUnit() != null ? unit.getExpenditureUnit() : getExpenditureUnit(mission, unit.getParentAccountabilityStream().filter(a -> a.getParent().isUnit()) .map(a -> (module.organization.domain.Unit) a.getParent()).findAny().orElse(null)); } public SortedSet<MissionProcess> getParticipate() { final User user = Authenticate.getUser(); final SortedSet<MissionProcess> result = new TreeSet<MissionProcess>(MissionProcess.COMPARATOR_BY_PROCESS_NUMBER); final Person person = user.getPerson(); if (person != null) { for (final Mission mission : person.getMissionsSet()) { final MissionProcess missionProcess = mission.getMissionProcess(); if (missionProcess.getMissionYear() == this && !missionProcess.getIsCanceled() && !missionProcess.isArchived()) { result.add(missionProcess); } } } return result; } public MissionAuthorizationMap getMissionAuthorizationMap() { return new MissionAuthorizationMap(this); } public Collection<MissionProcess> getTaken() { return getTakenStream().collect(Collectors.toSet()); } public Stream<MissionProcess> getTakenStream() { final User user = Authenticate.getUser(); return user.getUserProcessesSet().stream().filter(wp -> wp instanceof MissionProcess).map(wp -> (MissionProcess) wp) .filter(mp -> mp.getMissionYear() == this && !mp.getIsCanceled()); } public void delete() { if (hasAnyMissionProcess()) { throw new Error("cannot.delete.because.mission.process.exist"); } setMissionSystem(null); deleteDomainObject(); } @Deprecated public java.util.Set<module.mission.domain.MissionProcess> getMissionProcess() { return getMissionProcessSet(); } @Deprecated public boolean hasAnyMissionProcess() { return !getMissionProcessSet().isEmpty(); } @Deprecated public boolean hasYear() { return getYear() != null; } @Deprecated public boolean hasCounter() { return getCounter() != null; } @Deprecated public boolean hasMissionSystem() { return getMissionSystem() != null; } }