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.Iterator;
020    import java.util.List;
021    import java.util.Set;
022    
023    import org.apache.commons.lang.StringUtils;
024    import org.kuali.kfs.module.purap.PurapConstants;
025    import org.kuali.kfs.module.purap.PurapParameterConstants;
026    import org.kuali.kfs.module.purap.PurapAuthorizationConstants.PaymentRequestEditMode;
027    import org.kuali.kfs.module.purap.PurapConstants.PaymentRequestStatuses;
028    import org.kuali.kfs.module.purap.PurapWorkflowConstants.PaymentRequestDocument.NodeDetailEnum;
029    import org.kuali.kfs.module.purap.businessobject.PaymentRequestItem;
030    import org.kuali.kfs.module.purap.document.PaymentRequestDocument;
031    import org.kuali.kfs.module.purap.document.service.PurapService;
032    import org.kuali.kfs.sys.KFSConstants;
033    import org.kuali.kfs.sys.KfsAuthorizationConstants;
034    import org.kuali.kfs.sys.context.SpringContext;
035    import org.kuali.kfs.sys.service.impl.KfsParameterConstants;
036    import org.kuali.rice.kns.document.Document;
037    import org.kuali.rice.kns.service.ParameterService;
038    import org.kuali.rice.kns.util.ObjectUtils;
039    import org.kuali.rice.kns.workflow.service.KualiWorkflowDocument;
040    
041    
042    public class PaymentRequestDocumentPresentationController extends PurchasingAccountsPayableDocumentPresentationController {
043    
044        
045        @Override
046        protected boolean canSave(Document document) {
047            PaymentRequestDocument paymentRequestDocument = (PaymentRequestDocument) document;
048            
049            if (StringUtils.equals(paymentRequestDocument.getStatusCode(), PaymentRequestStatuses.INITIATE)) {
050                return false;
051            }
052    
053            if (canEditPreExtraction(paymentRequestDocument)) {
054                return true;
055            }
056            
057            return super.canSave(document);
058        }
059        
060        @Override
061        protected boolean canReload(Document document) {
062            PaymentRequestDocument paymentRequestDocument = (PaymentRequestDocument) document;
063    
064            if (StringUtils.equals(paymentRequestDocument.getStatusCode(), PaymentRequestStatuses.INITIATE)) {
065                return false;
066            }
067            
068            if (canEditPreExtraction(paymentRequestDocument)) {
069                return true;
070            }
071    
072            return super.canReload(document);
073        }
074    
075        @Override
076        protected boolean canCancel(Document document) {
077            //controlling the cancel button through getExtraButtons in PaymentRequestForm
078            return false;
079        }
080    
081        @Override
082        public boolean canApprove(Document document) {
083            PaymentRequestDocument paymentRequestDocument = (PaymentRequestDocument) document;
084            
085            if (paymentRequestDocument.isPaymentRequestedCancelIndicator() || paymentRequestDocument.isHoldIndicator()) {
086                return false;
087            }
088            
089            return super.canApprove(document);
090        }
091    
092        @Override
093        protected boolean canDisapprove(Document document) {
094            //disapprove is never allowed for PREQ
095            return false;
096        }
097    
098        /**
099         * @see org.kuali.rice.kns.document.authorization.DocumentPresentationControllerBase#canEdit(org.kuali.rice.kns.document.Document)
100         */
101        @Override
102        protected boolean canEdit(Document document) {
103            PaymentRequestDocument paymentRequestDocument = (PaymentRequestDocument) document;
104            boolean fullDocEntryCompleted = SpringContext.getBean(PurapService.class).isFullDocumentEntryCompleted(paymentRequestDocument);
105            KualiWorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument();
106            
107            //  fiscal officer review gets the doc editable once its enroute, but no one else does
108            if (fullDocEntryCompleted) {
109                if (paymentRequestDocument.isDocumentStoppedInRouteNode(NodeDetailEnum.ACCOUNT_REVIEW)) {
110                    return true;
111                }
112                return false;
113            }
114    
115            // if the hold or cancel indicator is true, don't allow editing
116            if (paymentRequestDocument.isHoldIndicator() || paymentRequestDocument.isPaymentRequestedCancelIndicator()) {
117                return false;
118            }
119    
120            //  in general, the doc should not be editable once its enroute
121            if (workflowDocument.stateIsEnroute() || workflowDocument.stateIsException()) {
122                return false; 
123            }
124            return super.canEdit(document);
125        }
126    
127        /**
128         * 
129         * @see org.kuali.rice.kns.document.authorization.TransactionalDocumentPresentationControllerBase#getEditModes(org.kuali.rice.kns.document.Document)
130         */
131        @Override
132        public Set<String> getEditModes(Document document) {
133            Set<String> editModes = super.getEditModes(document);
134            KualiWorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument();
135            PaymentRequestDocument paymentRequestDocument = (PaymentRequestDocument)document;
136            
137            if (canProcessorCancel(paymentRequestDocument)) {
138                editModes.add(PaymentRequestEditMode.ACCOUNTS_PAYABLE_PROCESSOR_CANCEL);
139            }
140            
141            if (canManagerCancel(paymentRequestDocument)) {
142                editModes.add(PaymentRequestEditMode.ACCOUNTS_PAYABLE_MANAGER_CANCEL);
143            }
144            
145            if (canHold(paymentRequestDocument)) {
146                editModes.add(PaymentRequestEditMode.HOLD);
147            }
148    
149            if (canRequestCancel(paymentRequestDocument)) {
150                editModes.add(PaymentRequestEditMode.REQUEST_CANCEL);
151            }
152    
153            if (canRemoveHold(paymentRequestDocument)) {
154                editModes.add(PaymentRequestEditMode.REMOVE_HOLD);
155            }
156    
157            if (canRemoveRequestCancel(paymentRequestDocument)) {
158                editModes.add(PaymentRequestEditMode.REMOVE_REQUEST_CANCEL);
159            }
160    
161            if (paymentRequestDocument.getStatusCode().equals(PurapConstants.PaymentRequestStatuses.INITIATE)) {
162                editModes.add(PaymentRequestEditMode.DISPLAY_INIT_TAB);
163            }
164            
165            if (ObjectUtils.isNotNull(paymentRequestDocument.getVendorHeaderGeneratedIdentifier())) {
166                editModes.add(PaymentRequestEditMode.LOCK_VENDOR_ENTRY);
167            }
168            
169            if (SpringContext.getBean(PurapService.class).isFullDocumentEntryCompleted(paymentRequestDocument)) {
170                editModes.add(PaymentRequestEditMode.FULL_DOCUMENT_ENTRY_COMPLETED);
171            }
172            else if (ObjectUtils.isNotNull(paymentRequestDocument.getPurchaseOrderDocument()) && PurapConstants.PurchaseOrderStatuses.OPEN.equals(paymentRequestDocument.getPurchaseOrderDocument().getStatusCode())) {
173                editModes.add(PaymentRequestEditMode.ALLOW_CLOSE_PURCHASE_ORDER);
174            }
175    
176            //FIXME hjs: alter to restrict what AP shouldn't be allowed to edit
177            if (canEditPreExtraction(paymentRequestDocument)) {
178                editModes.add(PaymentRequestEditMode.EDIT_PRE_EXTRACT);
179            }
180    
181            // See if purap tax is enabled
182            boolean salesTaxInd = SpringContext.getBean(ParameterService.class).getIndicatorParameter(KfsParameterConstants.PURCHASING_DOCUMENT.class, PurapParameterConstants.ENABLE_SALES_TAX_IND);
183            if (salesTaxInd) {
184                editModes.add(PaymentRequestEditMode.PURAP_TAX_ENABLED);
185    
186                if (paymentRequestDocument.isUseTaxIndicator()) {
187                    // if use tax, don't allow editing of tax fields
188                    editModes.add(PaymentRequestEditMode.LOCK_TAX_AMOUNT_ENTRY);
189                }
190                else {
191                    // display the "clear all taxes" button if doc is not using use tax
192                    editModes.add(PaymentRequestEditMode.CLEAR_ALL_TAXES);
193                    
194                }
195            }
196    
197            // tax area tab is editable while waiting for tax review
198            if (paymentRequestDocument.isDocumentStoppedInRouteNode(NodeDetailEnum.VENDOR_TAX_REVIEW)) {
199                editModes.add(PaymentRequestEditMode.TAX_AREA_EDITABLE);
200            }
201            /*
202            if (PaymentRequestStatuses.AWAITING_TAX_REVIEW.equals(paymentRequestDocument.getStatusCode())) {
203                editModes.add(PaymentRequestEditMode.TAX_AREA_EDITABLE);
204            }
205            */
206            
207            // the tax tab is viewable to everyone after tax is approved
208            if (PaymentRequestStatuses.DEPARTMENT_APPROVED.equals(paymentRequestDocument.getStatusCode()) &&
209                    // if and only if the preq has gone through tax review would TaxClassificationCode be non-empty
210                    !StringUtils.isEmpty(paymentRequestDocument.getTaxClassificationCode())) {
211                editModes.add(PaymentRequestEditMode.TAX_INFO_VIEWABLE);
212            }
213    
214            if (paymentRequestDocument.isDocumentStoppedInRouteNode(NodeDetailEnum.ACCOUNT_REVIEW)) {
215                // remove FULL_ENTRY because FO cannot edit rest of doc; only their own acct lines
216                editModes.add(PaymentRequestEditMode.RESTRICT_FISCAL_ENTRY);
217    
218                // only do line item check if the hold/cancel indicator is false, otherwise document editing should be turned off.
219                if (!paymentRequestDocument.isHoldIndicator() && !paymentRequestDocument.isPaymentRequestedCancelIndicator()) {
220                    List lineList = new ArrayList();
221                    for (Iterator iter = paymentRequestDocument.getItems().iterator(); iter.hasNext();) {
222                        PaymentRequestItem item = (PaymentRequestItem) iter.next();
223                        lineList.addAll(item.getSourceAccountingLines());
224                        // If FO has deleted the last accounting line for an item, set entry mode to full so they can add another one
225                        if (item.getItemType().isLineItemIndicator() && item.getSourceAccountingLines().size() == 0) {
226                            editModes.add(KfsAuthorizationConstants.TransactionalEditMode.EXPENSE_ENTRY);
227                        }
228                    }
229                }
230            }
231    
232            // Remove editBank edit mode if the document has been extracted
233            if (paymentRequestDocument.isExtracted()) {
234                editModes.remove(KFSConstants.BANK_ENTRY_EDITABLE_EDITING_MODE);
235            }
236    
237            return editModes;
238        }
239    
240    
241        protected boolean canProcessorCancel(PaymentRequestDocument paymentRequestDocument) {
242            // if Payment Request is in INITIATE status, user cannot cancel doc
243            if (StringUtils.equals(paymentRequestDocument.getStatusCode(), PaymentRequestStatuses.INITIATE)) {
244                return false;
245            }
246            
247            String docStatus = paymentRequestDocument.getStatusCode();
248            boolean requestCancelIndicator = paymentRequestDocument.getPaymentRequestedCancelIndicator();
249            boolean holdIndicator = paymentRequestDocument.isHoldIndicator();        
250            boolean extracted = paymentRequestDocument.isExtracted();
251            
252            boolean preroute = 
253                PaymentRequestStatuses.IN_PROCESS.equals(docStatus) || 
254                PaymentRequestStatuses.AWAITING_ACCOUNTS_PAYABLE_REVIEW.equals(docStatus);
255            boolean enroute = 
256                PaymentRequestStatuses.AWAITING_SUB_ACCT_MGR_REVIEW.equals(docStatus) ||
257                PaymentRequestStatuses.AWAITING_FISCAL_REVIEW.equals(docStatus) || 
258                PaymentRequestStatuses.AWAITING_ORG_REVIEW.equals(docStatus) || 
259                PaymentRequestStatuses.AWAITING_TAX_REVIEW.equals(docStatus);
260            boolean postroute = 
261                PaymentRequestStatuses.DEPARTMENT_APPROVED.equals(docStatus) || 
262                PaymentRequestStatuses.AUTO_APPROVED.equals(docStatus);
263            
264            boolean can = false;
265            if (preroute) {
266                can = true;
267            }
268            else if (enroute) {
269                can = requestCancelIndicator;
270            }
271            else if (postroute) {
272                can = !requestCancelIndicator && !holdIndicator && !extracted;
273            }
274    
275            return can;
276        }
277    
278        protected boolean canManagerCancel(PaymentRequestDocument paymentRequestDocument) {
279            // if Payment Request is in INITIATE status, user cannot cancel doc
280            if (StringUtils.equals(paymentRequestDocument.getStatusCode(), PaymentRequestStatuses.INITIATE)) {
281                return false;
282            }
283            
284            String docStatus = paymentRequestDocument.getStatusCode();
285            boolean requestCancelIndicator = paymentRequestDocument.getPaymentRequestedCancelIndicator();
286            boolean holdIndicator = paymentRequestDocument.isHoldIndicator();        
287            boolean extracted = paymentRequestDocument.isExtracted();
288            
289            boolean preroute = 
290                PaymentRequestStatuses.IN_PROCESS.equals(docStatus) || 
291                PaymentRequestStatuses.AWAITING_ACCOUNTS_PAYABLE_REVIEW.equals(docStatus);
292            boolean enroute = 
293                PaymentRequestStatuses.AWAITING_SUB_ACCT_MGR_REVIEW.equals(docStatus) ||
294                PaymentRequestStatuses.AWAITING_FISCAL_REVIEW.equals(docStatus) || 
295                PaymentRequestStatuses.AWAITING_ORG_REVIEW.equals(docStatus) || 
296                PaymentRequestStatuses.AWAITING_TAX_REVIEW.equals(docStatus);
297            boolean postroute = 
298                PaymentRequestStatuses.DEPARTMENT_APPROVED.equals(docStatus) || 
299                PaymentRequestStatuses.AUTO_APPROVED.equals(docStatus);
300            
301            boolean can = false;
302            if (preroute || enroute) {
303                can = true;
304            }
305            else if (postroute) {
306                can = !requestCancelIndicator && !holdIndicator && !extracted;
307            }
308    
309            return can;
310        }
311    
312        /**
313         * Determines whether the PaymentRequest Hold button shall be available. Conditions:
314         * - Payment Request is not already on hold, and
315         * - Payment Request is not already being requested to be canceled, and
316         * - Payment Request has not already been extracted to PDP, and
317         * - Payment Request status is not in the list of "STATUSES_DISALLOWING_HOLD" or document is being adhoc routed; and
318         * 
319         * @return True if the document state allows placing the Payment Request on hold.
320         */
321        protected boolean canHold(PaymentRequestDocument paymentRequestDocument) {
322            boolean can = !paymentRequestDocument.isHoldIndicator() && !paymentRequestDocument.isPaymentRequestedCancelIndicator() && !paymentRequestDocument.isExtracted();
323            if (can) {
324                can = paymentRequestDocument.getDocumentHeader().getWorkflowDocument().isAdHocRequested();
325                can = can || !PaymentRequestStatuses.STATUSES_DISALLOWING_HOLD.contains(paymentRequestDocument.getStatusCode());
326            }
327            
328            return can;
329        }
330    
331        /**
332         * Determines whether the Request Cancel PaymentRequest button shall be available. Conditions:
333         * - Payment Request is not already on hold, and
334         * - Payment Request is not already being requested to be canceled, and
335         * - Payment Request has not already been extracted to PDP, and
336         * - Payment Request status is not in the list of "STATUSES_DISALLOWING_REQUEST_CANCEL" or document is being adhoc routed; and
337         * 
338         * @return True if the document state allows placing the request that the Payment Request be canceled.
339         */
340        protected boolean canRequestCancel(PaymentRequestDocument paymentRequestDocument) {
341            boolean can = !paymentRequestDocument.isPaymentRequestedCancelIndicator() && !paymentRequestDocument.isHoldIndicator() && !paymentRequestDocument.isExtracted();
342            if (can) {
343                can = paymentRequestDocument.getDocumentHeader().getWorkflowDocument().isAdHocRequested();
344                can = can || !PaymentRequestStatuses.STATUSES_DISALLOWING_REQUEST_CANCEL.contains(paymentRequestDocument.getStatusCode());
345            }
346    
347            return can;
348        }
349    
350        /**
351         * Determines whether the Remove Hold button shall be available. Conditions:
352         * - the hold indicator is set to true
353         * 
354         * Because the state of the Payment Request cannot be changed while the document is on hold, 
355         * we should not have to check the state of the document to remove the hold.  
356         * For example, the document should not be allowed to be approved or extracted while on hold.
357         * 
358         * @return True if the document state allows removing the Payment Request from hold.
359         */
360        protected boolean canRemoveHold(PaymentRequestDocument paymentRequestDocument) {
361            return paymentRequestDocument.isHoldIndicator();       
362        }
363    
364        /**
365         * Determines whether the Remove Request Cancel button shall be available. Conditions:
366         * - the request cancel indicator is set to true;  and 
367         *   
368         * Because the state of the Payment Request cannot be changed while the document is set to request cancel, 
369         * we should not have to check the state of the document to remove the request cancel.  
370         * For example, the document should not be allowed to be approved or extracted while set to request cancel.
371         *  
372         * @return True if the document state allows removing a request that the Payment Request be canceled.
373         */
374        protected boolean canRemoveRequestCancel(PaymentRequestDocument paymentRequestDocument) {
375            return paymentRequestDocument.isPaymentRequestedCancelIndicator();
376        }
377    
378        protected boolean canEditPreExtraction(PaymentRequestDocument paymentRequestDocument) {
379            return (!paymentRequestDocument.isExtracted() && 
380                    !paymentRequestDocument.getDocumentHeader().getWorkflowDocument().isAdHocRequested() &&
381                    !PurapConstants.PaymentRequestStatuses.CANCELLED_STATUSES.contains(paymentRequestDocument.getStatusCode()));
382        }
383    
384    }