/*
* @(#)SimplifiedProcedureProcess.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.simplified;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import module.finance.util.Money;
import module.mission.domain.MissionSystem;
import module.workflow.activities.ActivityInformation;
import module.workflow.activities.GiveProcess;
import module.workflow.activities.ReleaseProcess;
import module.workflow.activities.StealProcess;
import module.workflow.activities.TakeProcess;
import module.workflow.activities.WorkflowActivity;
import module.workflow.domain.ProcessFile;
import module.workflow.domain.WorkflowProcess;
import module.workflow.util.ClassNameBundle;
import module.workflow.util.PresentableProcessState;
import org.fenixedu.bennu.core.i18n.BundleUtil;
import pt.ist.expenditureTrackingSystem._development.Bundle;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.AcquisitionInvoice;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.AcquisitionItemClassification;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.AcquisitionProcessStateType;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.AcquisitionProposalDocument;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.AcquisitionRequest;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.CreditNoteDocument;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.Financer;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.PurchaseOrderDocument;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.RegularAcquisitionProcess;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.activities.commons.AllocateFundsPermanently;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.activities.commons.AllocateProjectFundsPermanently;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.activities.commons.Authorize;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.activities.commons.CommitFunds;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.activities.commons.DeleteCommitmentNumber;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.activities.commons.FundAllocation;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.activities.commons.GenericAddPayingUnit;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.activities.commons.GenericAssignPayingUnitToItem;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.activities.commons.GenericRemovePayingUnit;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.activities.commons.ProjectFundAllocation;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.activities.commons.RemoveFundsPermanentlyAllocated;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.activities.commons.RemovePermanentProjectFunds;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.activities.commons.ReverifiedAfterCommitment;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.activities.commons.UnApprove;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.activities.commons.UnAuthorize;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.CancelAcquisitionRequest;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.CancelInvoiceConfirmation;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.ChangeAcquisitionRequestItemClassification;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.ChangeFinancersAccountingUnit;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.ChangeProcessClassification;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.ConfirmInvoice;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.CreateAcquisitionPurchaseOrderDocument;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.CreateAcquisitionRequestItem;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.DeleteAcquisitionRequestItem;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.DistributeRealValuesForPayingUnits;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.EditAcquisitionRequestItem;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.EditAcquisitionRequestItemRealValues;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.EditSimpleContractDescription;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.ExceptionalChangeRequestingPerson;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.FundAllocationExpirationDate;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.FundAllocationExpirationDateAndPurchaseOrderDocument;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.JumpToProcessState;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.LockInvoiceReceiving;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.PayAcquisition;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.RejectAcquisitionProcess;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.RemoveCancelProcess;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.RemoveFundAllocation;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.RemoveFundAllocationExpirationDate;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.RemoveFundAllocationExpirationDateForResponsible;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.RemoveProjectFundAllocation;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.RevertInvoiceSubmission;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.RevertProcessNotConfirmmingFundAllocationExpirationDate;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.RevertSkipPurchaseOrderDocument;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.RevertToInvoiceConfirmation;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.SelectSupplier;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.SendPurchaseOrderToSupplier;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.SetSkipSupplierFundAllocation;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.SkipPurchaseOrderDocument;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.SubmitForApproval;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.SubmitForConfirmInvoice;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.SubmitForFundAllocation;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.UnSubmitForApproval;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.UnlockInvoiceReceiving;
import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.UnsetSkipSupplierFundAllocation;
import pt.ist.expenditureTrackingSystem.domain.announcements.RCISTAnnouncement;
import pt.ist.expenditureTrackingSystem.domain.dto.CreateAcquisitionProcessBean;
import pt.ist.expenditureTrackingSystem.domain.organization.Person;
import pt.ist.expenditureTrackingSystem.domain.organization.Supplier;
import pt.ist.expenditureTrackingSystem.domain.organization.Unit;
import pt.ist.expenditureTrackingSystem.domain.util.DomainException;
import pt.ist.fenixWebFramework.rendererExtensions.util.IPresentableEnum;
import pt.ist.fenixframework.Atomic;
@ClassNameBundle(bundle = "ExpenditureResources")
/**
*
* @author Diogo Figueiredo
* @author João Neves
* @author João Antunes
* @author Paulo Abrantes
* @author Luis Cruz
*
*/
public class SimplifiedProcedureProcess extends SimplifiedProcedureProcess_Base {
public static enum ProcessClassification implements IPresentableEnum {
CCP(new Money("5000"), true, "RS 5000"), CT10000(new Money("10000"), "CT 10000"),
CT75000(new Money("75000"), "CT 75000"), NORMAL(new Money("75000"), "NORMAL");
final private Money value;
final private String shortDescription;
final private boolean ccp;
ProcessClassification(Money value, String shortDescription) {
this(value, false, shortDescription);
}
ProcessClassification(Money value, boolean ccp, String shortDescription) {
this.value = value;
this.ccp = ccp;
this.shortDescription = shortDescription;
}
public Money getLimit() {
return value;
}
public boolean isCCP() {
return ccp;
}
public String getShortDescription() {
return shortDescription;
}
@Override
public String getLocalizedName() {
return BundleUtil.getString("resources/ExpenditureResources", "label.processClassification." + name());
}
}
private static List<AcquisitionProcessStateType> availableStates = new ArrayList<AcquisitionProcessStateType>();
private static List<WorkflowActivity<? extends RegularAcquisitionProcess, ? extends ActivityInformation<? extends RegularAcquisitionProcess>>> activities =
new ArrayList<WorkflowActivity<? extends RegularAcquisitionProcess, ? extends ActivityInformation<? extends RegularAcquisitionProcess>>>();
static {
activities.add(new CommitFunds());
activities.add(new DeleteCommitmentNumber());
activities.add(new ReverifiedAfterCommitment());
activities.add(new CreateAcquisitionPurchaseOrderDocument());
activities.add(new SendPurchaseOrderToSupplier());
activities.add(new SkipPurchaseOrderDocument());
activities.add(new RevertSkipPurchaseOrderDocument());
activities.add(new GenericAddPayingUnit<RegularAcquisitionProcess>());
activities.add(new GenericRemovePayingUnit<RegularAcquisitionProcess>());
activities.add(new SubmitForApproval());
activities.add(new SubmitForFundAllocation());
activities.add(new RejectAcquisitionProcess());
activities.add(new UnApprove<RegularAcquisitionProcess>());
activities.add(new FundAllocationExpirationDate());
activities.add(new FundAllocationExpirationDateAndPurchaseOrderDocument());
activities.add(new RevertProcessNotConfirmmingFundAllocationExpirationDate());
activities.add(new RevertToInvoiceConfirmation());
activities.add(new Authorize<RegularAcquisitionProcess>());
activities.add(new UnAuthorize<RegularAcquisitionProcess>());
activities.add(new AllocateProjectFundsPermanently<RegularAcquisitionProcess>());
activities.add(new AllocateFundsPermanently<RegularAcquisitionProcess>());
activities.add(new RemovePermanentProjectFunds<RegularAcquisitionProcess>());
activities.add(new RemoveFundsPermanentlyAllocated<RegularAcquisitionProcess>());
activities.add(new ProjectFundAllocation<RegularAcquisitionProcess>());
activities.add(new FundAllocation<RegularAcquisitionProcess>());
activities.add(new RemoveFundAllocation());
activities.add(new RemoveProjectFundAllocation());
activities.add(new RemoveFundAllocationExpirationDate());
activities.add(new RemoveFundAllocationExpirationDateForResponsible());
activities.add(new CancelAcquisitionRequest());
activities.add(new UnlockInvoiceReceiving());
activities.add(new LockInvoiceReceiving());
activities.add(new SubmitForConfirmInvoice());
activities.add(new ConfirmInvoice());
activities.add(new CancelInvoiceConfirmation());
activities.add(new UnSubmitForApproval());
activities.add(new SetSkipSupplierFundAllocation());
activities.add(new UnsetSkipSupplierFundAllocation());
activities.add(new RevertInvoiceSubmission());
activities.add(new RemoveCancelProcess());
activities.add(new GenericAssignPayingUnitToItem<RegularAcquisitionProcess>());
activities.add(new DistributeRealValuesForPayingUnits());
activities.add(new ChangeFinancersAccountingUnit());
activities.add(new SelectSupplier());
activities.add(new ChangeProcessClassification());
activities.add(new ChangeAcquisitionRequestItemClassification());
activities.add(new CreateAcquisitionRequestItem());
activities.add(new PayAcquisition());
activities.add(new DeleteAcquisitionRequestItem());
activities.add(new EditAcquisitionRequestItem());
activities.add(new EditAcquisitionRequestItemRealValues());
activities.add(new TakeProcess<RegularAcquisitionProcess>());
activities.add(new GiveProcess<RegularAcquisitionProcess>());
activities.add(new ReleaseProcess<RegularAcquisitionProcess>());
activities.add(new StealProcess<RegularAcquisitionProcess>());
activities.add(new JumpToProcessState());
activities.add(new EditSimpleContractDescription());
activities.add(new ExceptionalChangeRequestingPerson());
availableStates.add(AcquisitionProcessStateType.IN_GENESIS);
availableStates.add(AcquisitionProcessStateType.SUBMITTED_FOR_APPROVAL);
availableStates.add(AcquisitionProcessStateType.SUBMITTED_FOR_FUNDS_ALLOCATION);
availableStates.add(AcquisitionProcessStateType.FUNDS_ALLOCATED_TO_SERVICE_PROVIDER);
availableStates.add(AcquisitionProcessStateType.FUNDS_ALLOCATED);
availableStates.add(AcquisitionProcessStateType.AUTHORIZED);
availableStates.add(AcquisitionProcessStateType.ACQUISITION_PROCESSED);
availableStates.add(AcquisitionProcessStateType.INVOICE_RECEIVED);
availableStates.add(AcquisitionProcessStateType.SUBMITTED_FOR_CONFIRM_INVOICE);
availableStates.add(AcquisitionProcessStateType.INVOICE_CONFIRMED);
availableStates.add(AcquisitionProcessStateType.FUNDS_ALLOCATED_PERMANENTLY);
availableStates.add(AcquisitionProcessStateType.ACQUISITION_PAYED);
availableStates.add(AcquisitionProcessStateType.REJECTED);
availableStates.add(AcquisitionProcessStateType.CANCELED);
}
protected SimplifiedProcedureProcess(final Person requester) {
super();
inGenesis();
new AcquisitionRequest(this, requester);
}
protected SimplifiedProcedureProcess(Supplier supplier, Person person) {
super();
inGenesis();
new AcquisitionRequest(this, supplier, person);
}
protected SimplifiedProcedureProcess(ProcessClassification classification, List<Supplier> suppliers, Person person) {
super();
inGenesis();
AcquisitionRequest acquisitionRequest = new AcquisitionRequest(this, suppliers, person);
if (suppliers.size() == 0) {
throw new DomainException(Bundle.ACQUISITION, "acquisitionProcess.message.exception.needsMoreSuppliers");
}
if (suppliers.size() == 1) {
acquisitionRequest.setSelectedSupplier(suppliers.get(0));
}
setProcessClassification(classification);
}
@Atomic
public static SimplifiedProcedureProcess createNewAcquisitionProcess(
final CreateAcquisitionProcessBean createAcquisitionProcessBean) {
if (!isCreateNewProcessAvailable()) {
throw new DomainException(Bundle.EXPENDITURE, "acquisitionProcess.message.exception.invalidStateToRun.create");
}
if (createAcquisitionProcessBean.isUnderMandatorySupplierScope()
&& !MissionSystem.getInstance().getMandatorySupplierSet().contains(createAcquisitionProcessBean.getSupplier())) {
throw new DomainException(Bundle.ACQUISITION,
"acquisitionProcess.message.exception.manditory.supplier.for.this.scope", MissionSystem.getInstance()
.getMandatorySupplierNotUsedErrorMessageArg());
}
SimplifiedProcedureProcess process =
new SimplifiedProcedureProcess(createAcquisitionProcessBean.getClassification(),
createAcquisitionProcessBean.getSuppliers(), createAcquisitionProcessBean.getRequester());
AcquisitionRequest acquisitionRequest = process.getAcquisitionRequest();
acquisitionRequest.setRequestingUnit(createAcquisitionProcessBean.getRequestingUnit());
acquisitionRequest.setContractSimpleDescription(createAcquisitionProcessBean.getContractSimpleDescription());
if (createAcquisitionProcessBean.isRequestUnitPayingUnit()) {
final Unit unit = createAcquisitionProcessBean.getRequestingUnit();
acquisitionRequest.addFinancers(unit.finance(acquisitionRequest));
}
if (createAcquisitionProcessBean.isForMission()) {
if (createAcquisitionProcessBean.getMissionProcess() == null) {
throw new DomainException(Bundle.ACQUISITION, "mission.process.is.mandatory");
}
process.setMissionProcess(createAcquisitionProcessBean.getMissionProcess());
}
if (createAcquisitionProcessBean.isUnderMandatorySupplierScope()
&& MissionSystem.getInstance().getMandatorySupplierSet().contains(createAcquisitionProcessBean.getSupplier())) {
process.skipSupplierFundAllocation();
}
return process;
}
@Override
public <T extends WorkflowActivity<? extends WorkflowProcess, ? extends ActivityInformation>> List<T> getActivities() {
return (List<T>) activities;
}
public <T extends WorkflowActivity<? extends WorkflowProcess, ? extends ActivityInformation>> Stream<T> getActivityStream() {
final List activities = this.activities;
return activities.stream();
}
public boolean isEditRequestItemAvailable() {
final Person loggedPerson = getLoggedPerson();
return loggedPerson != null && loggedPerson.equals(getRequestor()) && getLastAcquisitionProcessState().isInGenesis();
}
@Override
public Money getAcquisitionRequestValueLimit() {
return getProcessClassification().getLimit();
}
@Override
public boolean isSimplifiedAcquisitionProcess() {
return true;
}
@Override
public List<AcquisitionProcessStateType> getAvailableStates() {
return availableStates;
}
public static List<AcquisitionProcessStateType> getAvailableStatesForSimplifiedProcedureProcess() {
return availableStates;
}
@Override
public boolean isSimplifiedProcedureProcess() {
return true;
}
@Override
public boolean isPayed() {
return getRequest().isPayed();
}
@Override
public String getProcessStateDescription() {
return getLastAcquisitionProcessState().getLocalizedName();
}
@Override
public boolean isAppiableForYear(final int year) {
return Util.isAppiableForYear(year, this);
}
public boolean isCCP() {
return getProcessClassification().isCCP();
}
@Override
public void setProcessClassification(ProcessClassification processClassification) {
if (getSkipSupplierFundAllocation()) {
unSkipSupplierFundAllocation();
}
if (processClassification.getLimit().isLessThan(this.getAcquisitionRequest().getCurrentValue())) {
throw new DomainException(Bundle.ACQUISITION, "error.message.processValueExceedsLimitForClassification");
}
super.setProcessClassification(processClassification);
}
public void setProcessClassificationWithoutChecks(ProcessClassification processClassification) {
super.setProcessClassification(processClassification);
}
public boolean isWarnRegardingProcessClassificationNeeded() {
return getProcessClassification().isCCP() != getRequestingUnit().getDefaultRegeimIsCCP();
}
@Override
public Boolean getShouldSkipSupplierFundAllocation() {
return !this.isCCP() || super.getShouldSkipSupplierFundAllocation();
}
public boolean isWarnForLessSuppliersActive() {
return getProcessClassification() == ProcessClassification.CT75000 && getSuppliers().size() < 3;
}
@Override
public List<Class<? extends ProcessFile>> getAvailableFileTypes() {
List<Class<? extends ProcessFile>> availableFileTypes = new ArrayList<Class<? extends ProcessFile>>();
availableFileTypes.add(AcquisitionProposalDocument.class);
availableFileTypes.add(PurchaseOrderDocument.class);
availableFileTypes.add(AcquisitionInvoice.class);
availableFileTypes.add(CreditNoteDocument.class);
availableFileTypes.addAll(super.getAvailableFileTypes());
return availableFileTypes;
}
@Override
public List<Class<? extends ProcessFile>> getUploadableFileTypes() {
List<Class<? extends ProcessFile>> uploadableFileTypes = super.getUploadableFileTypes();
uploadableFileTypes.remove(PurchaseOrderDocument.class);
return uploadableFileTypes;
}
@Override
public String getLocalizedName() {
return getProcessClassification().getLocalizedName();
}
@Override
public String getTypeDescription() {
return getProcessClassification().getLocalizedName();
}
@Override
public String getTypeShortDescription() {
return getProcessClassification().getShortDescription();
}
@Override
public void processAcquisition() {
super.processAcquisition();
ProcessClassification processClassification = getProcessClassification();
if ((processClassification == ProcessClassification.CT75000 || processClassification == ProcessClassification.CT10000)
&& !getAcquisitionRequest().hasAnnouncement()) {
new RCISTAnnouncement(getAcquisitionRequest());
}
}
@Override
public PresentableProcessState getPresentableAcquisitionProcessState() {
return getLastAcquisitionProcessState().getAcquisitionProcessStateType();
}
@Override
public List<? extends PresentableProcessState> getAvailablePresentableStates() {
return getAvailableStates();
}
public boolean getFundAllocationPresent() {
for (final Financer financer : getAcquisitionRequest().getFinancers()) {
if (financer.isFundAllocationPresent()) {
return true;
}
}
return false;
}
public boolean getEffectiveFundAllocationPresent() {
for (final Financer financer : getAcquisitionRequest().getFinancers()) {
if (financer.isEffectiveFundAllocationPresent()) {
return true;
}
}
return false;
}
public boolean hasSomeInvoice() {
return isInvoiceReceived()
|| (getExpenditureTrackingSystem().isInvoiceAllowedToStartAcquisitionProcess() && hasInvoiceFile());
}
@Override
public boolean hasInvoiceFile() {
for (final ProcessFile processFile : getFilesSet()) {
if (processFile instanceof AcquisitionInvoice && !processFile.isArchieved()) {
return true;
}
}
return false;
}
@Override
protected boolean isProcessessStartedWithInvoive() {
return hasInvoiceFile() && !hasAcquisitionProposalDocument();
}
@Override
public AcquisitionItemClassification getGoodsOrServiceClassification() {
final AcquisitionRequest request = getRequest();
return request.getGoodsOrServiceClassification();
}
@Deprecated
public boolean hasProcessClassification() {
return getProcessClassification() != null;
}
}