/* * @(#)PaymentProcess.java * * Copyright 2009 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 pt.ist.expenditureTrackingSystem.domain.acquisitions; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.stream.Stream; import org.fenixedu.bennu.core.domain.User; import org.fenixedu.bennu.core.groups.Group; import org.fenixedu.bennu.core.i18n.BundleUtil; import org.fenixedu.bennu.core.security.Authenticate; import org.fenixedu.bennu.core.util.CoreConfiguration; import org.fenixedu.messaging.core.domain.Message; import org.fenixedu.messaging.core.template.DeclareMessageTemplate; import org.fenixedu.messaging.core.template.TemplateParameter; import org.joda.time.LocalDate; import module.finance.util.Money; import module.mission.domain.MissionProcess; import module.workflow.domain.ProcessFile; import module.workflow.domain.WorkflowLog; import module.workflow.domain.utils.WorkflowCommentCounter; import module.workflow.util.ClassNameBundle; import module.workflow.util.HasPresentableProcessState; import module.workflow.util.PresentableProcessState; import module.workflow.widgets.UnreadCommentsWidget; import pt.ist.expenditureTrackingSystem._development.Bundle; import pt.ist.expenditureTrackingSystem.domain.ExpenditureTrackingSystem; import pt.ist.expenditureTrackingSystem.domain.ProcessState; import pt.ist.expenditureTrackingSystem.domain.authorizations.Authorization; import pt.ist.expenditureTrackingSystem.domain.organization.AccountingUnit; import pt.ist.expenditureTrackingSystem.domain.organization.Person; import pt.ist.expenditureTrackingSystem.domain.organization.Project; import pt.ist.expenditureTrackingSystem.domain.organization.SubProject; import pt.ist.expenditureTrackingSystem.domain.organization.Supplier; import pt.ist.expenditureTrackingSystem.domain.organization.Unit; import pt.ist.expenditureTrackingSystem.domain.util.DomainException; /** * * @author João Antunes * @author João Neves * @author Paulo Abrantes * @author Luis Cruz * @author João Alfaiate * */ @DeclareMessageTemplate(id = "expenditures.payment.comment", bundle = Bundle.ACQUISITION, description = "template.payment.comment", subject = "template.payment.comment.subject", text = "template.payment.comment.text", parameters = { @TemplateParameter(id = "applicationUrl", description = "template.parameter.application.url"), @TemplateParameter(id = "comment", description = "template.parameter.comment"), @TemplateParameter(id = "commenter", description = "template.parameter.commenter"), @TemplateParameter(id = "process", description = "template.parameter.process") }) @ClassNameBundle(bundle = "ExpenditureResources") public abstract class PaymentProcess extends PaymentProcess_Base implements HasPresentableProcessState { public static Comparator<PaymentProcess> COMPARATOR_BY_YEAR_AND_ACQUISITION_PROCESS_NUMBER = new Comparator<PaymentProcess>() { @Override public int compare(PaymentProcess o1, PaymentProcess o2) { int yearComp = COMPARATOR_BY_YEAR.compare(o1, o2); return (yearComp != 0) ? yearComp : COMPARATOR_BY_ACQUISITION_PROCESS_NUMBER.compare(o1, o2); } }; public static Comparator<PaymentProcess> COMPARATOR_BY_YEAR = new Comparator<PaymentProcess>() { @Override public int compare(PaymentProcess o1, PaymentProcess o2) { return o1.getPaymentProcessYear().getYear().compareTo(o2.getPaymentProcessYear().getYear()); } }; public static Comparator<PaymentProcess> COMPARATOR_BY_ACQUISITION_PROCESS_NUMBER = new Comparator<PaymentProcess>() { @Override public int compare(PaymentProcess o1, PaymentProcess o2) { return o1.getAcquisitionProcessNumber().compareTo(o2.getAcquisitionProcessNumber()); } }; static { UnreadCommentsWidget.register(new WorkflowCommentCounter(PaymentProcess.class)); } public PaymentProcess() { super(); final PaymentProcessYear acquisitionProcessYear = getPaymentProcessYearForConstruction(); setPaymentProcessYear(acquisitionProcessYear); setAcquisitionProcessNumber(acquisitionProcessYear.nextAcquisitionProcessYearNumber()); } private PaymentProcessYear getPaymentProcessYearForConstruction() { return PaymentProcessYear.getPaymentProcessYearByYear(getYearForConstruction()); } protected int getYearForConstruction() { return new LocalDate().getYear(); } public abstract <T extends RequestWithPayment> T getRequest(); /** * Use getPayingUnitStream instead * */ @Deprecated public List<Unit> getPayingUnits() { List<Unit> res = new ArrayList<Unit>(); for (Financer financer : getRequest().getFinancers()) { res.add(financer.getUnit()); } return res; } public Stream<Unit> getPayingUnitStream() { return getRequest().getFinancersSet().stream().map(f -> f.getUnit()); } public boolean isRealValueEqualOrLessThanFundAllocation() { Money allocatedMoney = this.getRequest().getTotalValue(); Money realMoney = this.getRequest().getRealTotalValue(); return realMoney.isLessThanOrEqual(allocatedMoney); } public boolean isResponsibleForAtLeastOnePayingUnit(Person person) { return getPayingUnitStream().anyMatch(u -> u.isResponsible(person)); } public Person getRequestor() { return getRequest().getRequester(); } public boolean isResponsibleForUnit(Person person) { return getPayingUnitStream().anyMatch(u -> isResponsibleForUnit(person, u)); } private boolean isResponsibleForUnit(final Person person, final Unit unit) { return person.getValidAuthorizationStream().anyMatch(a -> unit.isSubUnit(a.getUnit())); } public boolean isResponsibleForUnit() { final Person loggedPerson = getLoggedPerson(); return loggedPerson != null && isResponsibleForUnit(loggedPerson); } public boolean isProjectAccountingEmployee(final Person person) { return getRequest().isProjectAccountingEmployee(person); } public boolean isTreasuryMember(final Person person) { return getRequest().isTreasuryMember(person); } public boolean isProjectAccountingEmployee() { final Person loggedPerson = getLoggedPerson(); return loggedPerson != null && isProjectAccountingEmployee(loggedPerson); } public boolean hasAllocatedFundsForAllProjectFinancers(final Person person) { return getRequest().hasAllocatedFundsForAllProjectFinancers(person); } public boolean hasAllInvoicesAllocated() { return getRequest().hasAllInvoicesAllocated(); } public boolean hasAllInvoicesAllocatedInProject() { return getRequest().hasAllInvoicesAllocatedInProject(); } public boolean hasAnyFundAllocationId() { return getRequest().hasAnyFundAllocationId(); } public boolean hasAnyEffectiveFundAllocationId() { return getRequest().hasAnyEffectiveFundAllocationId(); } public boolean hasAnyNonProjectFundAllocationId() { return getRequest().hasAnyNonProjectFundAllocationId(); } public boolean isAccountingEmployee(final Person person) { return getRequest().isAccountingEmployee(person); } public boolean isProjectAccountingEmployeeForOnePossibleUnit() { final Person loggedPerson = getLoggedPerson(); return loggedPerson != null && isProjectAccountingEmployeeForOnePossibleUnit(loggedPerson); } public boolean isProjectAccountingEmployeeForOnePossibleUnit(final Person person) { return getRequest().isProjectAccountingEmployeeForOnePossibleUnit(person); } public boolean isAccountingEmployee() { final Person loggedPerson = getLoggedPerson(); return loggedPerson != null && isAccountingEmployee(loggedPerson); } public boolean isAccountingEmployeeForOnePossibleUnit() { final Person loggedPerson = getLoggedPerson(); return loggedPerson != null && isAccountingEmployeeForOnePossibleUnit(loggedPerson); } public boolean isAccountingEmployeeForOnePossibleUnit(final Person person) { return getRequest().isAccountingEmployeeForOnePossibleUnit(person); } public boolean hasAllocatedFundsForAllProjectFinancers() { return getRequest().hasAllocatedFundsForAllProjectFinancers(); } public boolean hasAnyAllocatedFunds() { return getRequest().hasAnyAllocatedFunds(); } public boolean hasAllFundAllocationId(Person person) { return getRequest().hasAllFundAllocationId(person); } public Set<Financer> getFinancersWithFundsAllocated() { return getRequest().getFinancersWithFundsAllocated(); } public Set<Financer> getFinancersWithFundsInitiallyAllocated() { return getRequest().getFinancersWithFundsInitiallyAllocated(); } public Set<Financer> getFinancersWithFundsAllocated(Person person) { return getRequest().getFinancersWithFundsAllocated(person); } public Set<ProjectFinancer> getProjectFinancersWithFundsAllocated() { return getRequest().getProjectFinancersWithFundsAllocated(); } public Set<ProjectFinancer> getProjectFinancersWithFundsAllocated(final Person person) { return getRequest().getProjectFinancersWithFundsAllocated(person); } public abstract boolean isCanceled(); public abstract boolean isInGenesis(); public abstract boolean isPendingApproval(); public abstract boolean isInApprovedState(); public abstract boolean isPendingFundAllocation(); public abstract void allocateFundsToUnit(); public abstract void submitForApproval(); public abstract void submitForFundAllocation(); public abstract boolean isInAllocatedToUnitState(); public abstract boolean isInAuthorizedState(); protected abstract void authorize(); public boolean isResponsibleForUnit(final Person person, final Money amount) { return getPayingUnitStream().anyMatch(u -> isResponsibleForUnit(person, amount, u)); } public boolean isResponsibleForUnit(final Person person, final Money amount, final Unit unit) { return person.getValidAuthorizationStream().anyMatch(a -> isResponsibleForUnit(amount, unit, a)); } private boolean isResponsibleForUnit(final Money amount, final Unit unit, final Authorization authorization) { if (authorization.getMaxAmount().isGreaterThanOrEqual(amount) && unit.isSubUnit(authorization.getUnit())) { final ExpenditureTrackingSystem instance = ExpenditureTrackingSystem.getInstance(); if (!authorization.getUnit().hasParentUnit() || !isProcessessStartedWithInvoive() || (isProcessessStartedWithInvoive() && (instance.getValueRequireingTopLevelAuthorization() == null || instance.getValueRequireingTopLevelAuthorization().isGreaterThan(amount)))) { return true; } } return false; } protected boolean isProcessessStartedWithInvoive() { return false; } public void skitToAuthorizedState() { authorize(); } public void authorizeBy(final Person person) { getRequest().authorizeBy(person); if (getRequest().isAuthorizedByAllResponsibles()) { authorize(); } } public boolean hasProjectsAsPayingUnits() { return getPayingUnitStream().anyMatch(u -> u instanceof Project || u instanceof SubProject); } public boolean isRealValueFullyAttributedToUnits() { return getRequest().isRealValueFullyAttributedToUnits(); } public boolean isSimplifiedProcedureProcess() { return false; } public boolean isInvoiceConfirmed() { return false; } public boolean hasAllocatedFundsPermanentlyForAllProjectFinancers() { final RequestWithPayment requestWithPayment = getRequest(); return requestWithPayment.hasAllocatedFundsPermanentlyForAllProjectFinancers(); } public boolean hasAllocatedFundsPermanentlyForAnyProjectFinancers() { final RequestWithPayment requestWithPayment = getRequest(); return requestWithPayment.hasAllocatedFundsPermanentlyForAnyProjectFinancer(); } public boolean areAllFundsPermanentlyAllocated() { final RequestWithPayment requestWithPayment = getRequest(); return requestWithPayment.areAllFundsPermanentlyAllocated(); } public void allocateFundsPermanently() { } public boolean isAllocatedPermanently() { return false; } public void resetEffectiveFundAllocationId() { } public <T extends WorkflowLog> List<T> getExecutionLogsForState(String stateName) { return (List<T>) getExecutionLogs(); } public boolean isPayed() { return false; } public boolean isAuthorized() { return isInAuthorizedState(); } public boolean isRefundProcess() { return false; } public abstract String getAcquisitionProcessId(); private static final String EMPTY_STRING = new String(); public String getProcessStateDescription() { return EMPTY_STRING; } public String getProcessStateName() { return EMPTY_STRING; } public int getProcessStateOrder() { return 0; } public abstract Collection<Supplier> getSuppliers(); public String getSuppliersDescription() { Iterator<Supplier> iterator = getSuppliers().iterator(); StringBuilder builder = new StringBuilder(); while (iterator.hasNext()) { builder.append(iterator.next().getName()); if (iterator.hasNext()) { builder.append(" ,"); } } return builder.toString(); } public String getTypeDescription() { return BundleUtil.getString("resources/ExpenditureResources", "label." + getClass().getSimpleName() + ".description"); } public String getTypeShortDescription() { return BundleUtil.getString("resources/ExpenditureResources", "label." + getClass().getSimpleName() + ".shortDescription"); } public abstract boolean isAppiableForYear(final int year); public boolean isPriorityProcess() { for (RequestItem item : getRequest().getRequestItems()) { if (item.getCPVReference().isPriorityCode()) { return true; } } return false; } @Override public void notifyUserDueToComment(User user, String comment) { Message.fromSystem().to(Group.users(user)).template("expenditures.payment.comment") .parameter("process", getAcquisitionProcessId()) .parameter("commenter", Authenticate.getUser().getProfile().getFullName()).parameter("comment", comment) .parameter("applicationUrl", CoreConfiguration.getConfiguration().applicationUrl()).and().send(); } public boolean isCurrentUserObserver() { return isObserver(Person.getLoggedPerson()); } public boolean isObserver(Person person) { if (getRequest().getRequestingUnit().getObserversSet().contains(person)) { return true; } return getPayingUnitStream().anyMatch(u -> u.getObserversSet().contains(person)); } @Override public User getProcessCreator() { return getRequest().getRequester().getUser(); } public List<ProcessFile> getGenericFiles() { return getFiles(ProcessFile.class); } public abstract void revertToState(ProcessState processState); public abstract String getLocalizedName(); @Override public void setMissionProcess(final MissionProcess missionProcess) { if (missionProcess == null // || (missionProcess.isExpenditureAuthorized() && missionProcess.areAllParticipantsAuthorized()) || (!missionProcess.isUnderConstruction() && !missionProcess.getIsCanceled() && !missionProcess.isTerminated() /*&& missionProcess.getMission().isPendingApproval()*/)) { super.setMissionProcess(missionProcess); } else { // throw new DomainException(Bundle.EXPENDITURE, "error.cannot.connect.acquisition.to.unauthorized.mission", throw new DomainException(Bundle.ACQUISITION, "error.cannot.connect.acquisition.to.unsubmitted.for.approval.mission"); } } @Override public PresentableProcessState getPresentableAcquisitionProcessState() { return null; } @Override public List<? extends PresentableProcessState> getAvailablePresentableStates() { return Collections.emptyList(); } public abstract Money getTotalValue(); public boolean isDirectResponsibleForUnit(final User user, final Money amount) { final Person person = user.getExpenditurePerson(); return getPayingUnitStream().anyMatch(u -> u.isDirectResponsible(person, amount)); } public abstract Set<CPVReference> getCPVReferences(); public String getAccountingUnitsAsString() { final StringBuilder builder = new StringBuilder(); for (final Financer financer : getFinancersWithFundsAllocated()) { final AccountingUnit accountingUnit = financer.getAccountingUnit(); if (accountingUnit != null) { if (builder.length() > 0) { builder.append(", "); } builder.append(accountingUnit.getName()); } } return builder.toString(); } public abstract AcquisitionItemClassification getGoodsOrServiceClassification(); @Deprecated public boolean hasAcquisitionProcessNumber() { return getAcquisitionProcessNumber() != null; } @Deprecated public boolean hasSkipSupplierFundAllocation() { return getSkipSupplierFundAllocation() != null; } @Deprecated public boolean hasPaymentProcessYear() { return getPaymentProcessYear() != null; } @Deprecated public boolean hasMissionProcess() { return getMissionProcess() != null; } }