001    /*
002     * Copyright 2011 The Kuali Foundation.
003     * 
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     * 
008     * http://www.opensource.org/licenses/ecl2.php
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.kfs.module.purap.document.authorization;
017    
018    import java.util.ArrayList;
019    import java.util.Arrays;
020    import java.util.Iterator;
021    import java.util.List;
022    import java.util.Set;
023    
024    import org.kuali.kfs.module.purap.PurapAuthorizationConstants;
025    import org.kuali.kfs.module.purap.PurapConstants;
026    import org.kuali.kfs.module.purap.PurapParameterConstants;
027    import org.kuali.kfs.module.purap.PurapAuthorizationConstants.RequisitionEditMode;
028    import org.kuali.kfs.module.purap.PurapConstants.RequisitionSources;
029    import org.kuali.kfs.module.purap.PurapConstants.RequisitionStatuses;
030    import org.kuali.kfs.module.purap.PurapWorkflowConstants.NodeDetails;
031    import org.kuali.kfs.module.purap.PurapWorkflowConstants.RequisitionDocument.NodeDetailEnum;
032    import org.kuali.kfs.module.purap.businessobject.RequisitionItem;
033    import org.kuali.kfs.module.purap.document.RequisitionDocument;
034    import org.kuali.kfs.module.purap.document.service.PurapService;
035    import org.kuali.kfs.sys.context.SpringContext;
036    import org.kuali.kfs.sys.service.impl.KfsParameterConstants;
037    import org.kuali.rice.kew.exception.WorkflowException;
038    import org.kuali.rice.kns.document.Document;
039    import org.kuali.rice.kns.service.KualiConfigurationService;
040    import org.kuali.rice.kns.service.ParameterService;
041    import org.kuali.rice.kns.util.ObjectUtils;
042    import org.kuali.rice.kns.workflow.service.KualiWorkflowDocument;
043    
044    
045    public class RequisitionDocumentPresentationController extends PurchasingAccountsPayableDocumentPresentationController {
046    
047        @Override
048        protected boolean canEdit(Document document) {
049            RequisitionDocument reqDocument = (RequisitionDocument)document;
050            if (!RequisitionStatuses.IN_PROCESS.equals(reqDocument.getStatusCode()) &&
051                    !RequisitionStatuses.AWAIT_CONTENT_REVIEW.equals(reqDocument.getStatusCode()) &&
052                    !RequisitionStatuses.AWAIT_HAS_ACCOUNTING_LINES.equals(reqDocument.getStatusCode()) &&
053                    !RequisitionStatuses.AWAIT_FISCAL_REVIEW.equals(reqDocument.getStatusCode())) {
054                //unless the Requisition is in process, awaiting content, awaiting accounting lines or awaiting fiscal, editing is not allowed
055                return false;
056            }
057            return super.canEdit(document);
058        }
059    
060        @Override
061        public Set<String> getEditModes(Document document) {
062            Set<String> editModes = super.getEditModes(document);
063            RequisitionDocument reqDocument = (RequisitionDocument)document;
064    
065            //if the ENABLE_COMMODITY_CODE_IND system parameter is Y then add this edit mode so that the commodity code fields would display on the document.
066            boolean enableCommodityCode = SpringContext.getBean(ParameterService.class).getIndicatorParameter(KfsParameterConstants.PURCHASING_DOCUMENT.class, PurapParameterConstants.ENABLE_COMMODITY_CODE_IND);
067            if (enableCommodityCode) {
068                editModes.add(RequisitionEditMode.ENABLE_COMMODITY_CODE);
069            }
070            
071            // if vendor has been selected from DB, certain vendor fields are not allowed to be edited
072            if (ObjectUtils.isNotNull(reqDocument.getVendorHeaderGeneratedIdentifier())) {
073                editModes.add(RequisitionEditMode.LOCK_VENDOR_ENTRY);
074            }
075            
076            // if B2B requisition, certain fields are not allowed to be edited
077            if (RequisitionSources.B2B.equals(reqDocument.getRequisitionSourceCode())) {
078                editModes.add(RequisitionEditMode.LOCK_B2B_ENTRY);
079            }
080    
081            // if not B2B requisition, the posting year cannot be edited if within a given amount of time set in a parameter
082            if (!RequisitionSources.B2B.equals(reqDocument.getRequisitionSourceCode()) && 
083                    SpringContext.getBean(PurapService.class).allowEncumberNextFiscalYear()) {
084                editModes.add(RequisitionEditMode.ALLOW_POSTING_YEAR_ENTRY);
085            }
086    
087            // check if purap tax is enabled
088            boolean salesTaxInd = SpringContext.getBean(ParameterService.class).getIndicatorParameter(KfsParameterConstants.PURCHASING_DOCUMENT.class, PurapParameterConstants.ENABLE_SALES_TAX_IND);
089            if (salesTaxInd) {
090                editModes.add(PurapAuthorizationConstants.PURAP_TAX_ENABLED);
091                editModes.add(RequisitionEditMode.CLEAR_ALL_TAXES); // always available now if taxes
092    
093                if (reqDocument.isUseTaxIndicator()) {
094                    // don't allow tax editing if doc using use tax
095                    editModes.add(RequisitionEditMode.LOCK_TAX_AMOUNT_ENTRY);
096                }
097            }
098    
099            // set display mode for Receiving Address section according to parameter value
100            boolean displayReceivingAddress = SpringContext.getBean(ParameterService.class).getIndicatorParameter(KfsParameterConstants.PURCHASING_DOCUMENT.class, PurapParameterConstants.ENABLE_RECEIVING_ADDRESS_IND);                
101            if (displayReceivingAddress) {
102                editModes.add(RequisitionEditMode.DISPLAY_RECEIVING_ADDRESS);
103            }
104                
105            // set display mode for Address to Vendor section according to parameter value 
106            boolean lockAddressToVendor = !SpringContext.getBean(ParameterService.class).getIndicatorParameter(PurapConstants.PURAP_NAMESPACE, "Requisition", PurapParameterConstants.ENABLE_ADDRESS_TO_VENDOR_SELECTION_IND);                
107            if (lockAddressToVendor) {
108                editModes.add(RequisitionEditMode.LOCK_ADDRESS_TO_VENDOR);
109            }
110    
111            // CONTENT ROUTE LEVEL - Approvers can edit full detail on Requisition except they cannot change the CHART/ORG.
112            if (reqDocument.isDocumentStoppedInRouteNode(NodeDetailEnum.CONTENT_REVIEW) ||
113                    reqDocument.isDocumentStoppedInRouteNode(NodeDetailEnum.HAS_ACCOUNTING_LINES)) {
114                editModes.add(RequisitionEditMode.LOCK_CONTENT_ENTRY);
115            }
116    
117             // FISCAL OFFICER ROUTE LEVEL - Approvers can edit only the accounting lines that they own and no other detail on REQ.
118            else if (reqDocument.isDocumentStoppedInRouteNode(NodeDetailEnum.ACCOUNT_REVIEW)) {
119    
120                // remove FULL_ENTRY because FO cannot edit rest of doc; only their own acct lines
121                editModes.add(RequisitionEditMode.RESTRICT_FISCAL_ENTRY);
122    
123                List lineList = new ArrayList();
124                for (Iterator iter = reqDocument.getItems().iterator(); iter.hasNext();) {
125                    RequisitionItem item = (RequisitionItem) iter.next();
126                    lineList.addAll(item.getSourceAccountingLines());
127                    // If FO has deleted the last accounting line for an item, set entry mode to full so they can add another one
128                    
129                    if (item.getSourceAccountingLines().size() == 0) {
130                        editModes.add(RequisitionEditMode.RESTRICT_FISCAL_ENTRY);
131                        //FIXME hjs-this is a problem because we can't put the id in the map anymore
132    //                    editModeMap.put(RequisitionEditMode.ALLOW_ITEM_ENTRY, item.getItemIdentifier());
133                    }
134                }
135    
136            }
137    
138            return editModes;
139        }
140    
141        @Override
142        protected boolean canCopy(Document document) {
143            //  disallow copying until the doc is saved
144            KualiWorkflowDocument workflowDoc = document.getDocumentHeader().getWorkflowDocument();
145            if (workflowDoc.stateIsInitiated() && !workflowDoc.stateIsSaved()) {
146                return false;
147            }
148            return super.canCopy(document);
149        }
150    
151        @Override
152        protected boolean canReload(Document document) {
153            RequisitionDocument reqDocument = (RequisitionDocument) document;
154            
155            //  this is a global rule, if the doc is in your queue for ACK, then you lose the reload button
156            KualiWorkflowDocument workflowDoc = document.getDocumentHeader().getWorkflowDocument();
157            if (workflowDoc.isAcknowledgeRequested()) {
158                return false;
159            }
160            
161            //  while in subAccountReview ... sub account approvers do NOT get reload button
162            if (reqDocument.isDocumentStoppedInRouteNode(NodeDetailEnum.SUB_ACCOUNT_REVIEW)) {
163                return false;
164            }
165            //  but the non-approvers do 
166            else if (isDocInRouteNodeNotForCurrentUser(reqDocument, NodeDetailEnum.SUB_ACCOUNT_REVIEW)) {
167                return true;
168            }
169            
170            //  while in AccountingHierarchyOrgReview ... org reviewers do NOT get reload button 
171            else if (reqDocument.isDocumentStoppedInRouteNode(NodeDetailEnum.ORG_REVIEW)) {
172                return false;
173            }
174            // but the non-approvers do
175            else if (isDocInRouteNodeNotForCurrentUser(reqDocument, NodeDetailEnum.ORG_REVIEW)) {
176                return true;
177            }
178    
179            //  while in SeparationOfDuties ... approvers do NOT get reload button 
180            else if (reqDocument.isDocumentStoppedInRouteNode(NodeDetailEnum.SEPARATION_OF_DUTIES_REVIEW)) {
181                return false;
182            }
183            // but the non-approvers do
184            else if (isDocInRouteNodeNotForCurrentUser(reqDocument, NodeDetailEnum.SEPARATION_OF_DUTIES_REVIEW)) {
185                return true;
186            }
187    
188            return super.canReload(document);
189        }
190    
191        @Override
192        protected boolean canSave(Document document) {
193            RequisitionDocument reqDocument = (RequisitionDocument) document;
194    
195            //  while in OrgReview ... org reviewers do NOT get reload button 
196            if (reqDocument.isDocumentStoppedInRouteNode(NodeDetailEnum.ORG_REVIEW)) {
197                return false;
198            }
199            return super.canSave(document);
200        }
201    
202        protected boolean isDocInRouteNodeNotForCurrentUser(Document document, NodeDetails nodeDetails) {
203            List<String> currentRouteLevels = new ArrayList<String>();
204                KualiWorkflowDocument workflowDoc = document.getDocumentHeader().getWorkflowDocument();
205                try {
206                    currentRouteLevels = Arrays.asList(document.getDocumentHeader().getWorkflowDocument().getNodeNames());
207                }
208                catch (WorkflowException e) {
209                    throw new RuntimeException(e);
210                }
211                if (currentRouteLevels.contains(nodeDetails.getName()) && !workflowDoc.isApprovalRequested()) {
212                    return true;
213                }
214                return false;
215        }
216    }