View Javadoc
1   /*
2    * Copyright 2008-2009 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.ole.module.purap.document.authorization;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.ole.module.purap.PurapAuthorizationConstants.InvoiceEditMode;
20  import org.kuali.ole.module.purap.PurapConstants.InvoiceStatuses;
21  import org.kuali.ole.module.purap.PurapConstants.PurchaseOrderStatuses;
22  import org.kuali.ole.module.purap.PurapParameterConstants;
23  import org.kuali.ole.module.purap.businessobject.InvoiceItem;
24  import org.kuali.ole.module.purap.document.InvoiceDocument;
25  import org.kuali.ole.module.purap.document.service.PurapService;
26  import org.kuali.ole.sys.OLEConstants;
27  import org.kuali.ole.sys.OleAuthorizationConstants;
28  import org.kuali.ole.sys.context.SpringContext;
29  import org.kuali.ole.sys.service.FinancialSystemWorkflowHelperService;
30  import org.kuali.ole.sys.service.impl.OleParameterConstants;
31  import org.kuali.rice.coreservice.framework.parameter.ParameterService;
32  import org.kuali.rice.kew.api.WorkflowDocument;
33  import org.kuali.rice.kew.api.action.ActionType;
34  import org.kuali.rice.kew.api.action.ValidActions;
35  import org.kuali.rice.krad.document.Document;
36  import org.kuali.rice.krad.util.GlobalVariables;
37  import org.kuali.rice.krad.util.ObjectUtils;
38  
39  import java.util.ArrayList;
40  import java.util.Iterator;
41  import java.util.List;
42  import java.util.Set;
43  
44  
45  public class InvoiceDocumentPresentationController extends PurchasingAccountsPayableDocumentPresentationController {
46  
47      Boolean canHold;
48      Boolean canRequestCancel;
49      Boolean canEditPreExtraction;
50  
51      @Override
52      public boolean canSave(Document document) {
53          InvoiceDocument invoiceDocument = (InvoiceDocument) document;
54  
55          if (!StringUtils.equalsIgnoreCase(invoiceDocument.getDocumentHeader().getWorkflowDocument().getStatus().name(), InvoiceStatuses.APPDOC_INITIATE)
56                 && !StringUtils.equalsIgnoreCase(invoiceDocument.getDocumentHeader().getWorkflowDocument().getStatus().name(), OLEConstants.OleInvoice.INVOICE_SAVED)) {
57              return false;
58          }
59  
60          if (canEditPreExtraction(invoiceDocument)) {
61              return true;
62          }
63  
64          return super.canSave(document);
65      }
66  
67      @Override
68      public boolean canReload(Document document) {
69          InvoiceDocument invoiceDocument = (InvoiceDocument) document;
70  
71          if (StringUtils.equals(invoiceDocument.getApplicationDocumentStatus(), InvoiceStatuses.APPDOC_INITIATE)) {
72              return false;
73          }
74  
75          if (canEditPreExtraction(invoiceDocument)) {
76              return true;
77          }
78  
79          return super.canReload(document);
80      }
81  
82      @Override
83      public boolean canCancel(Document document) {
84          //controlling the cancel button through getExtraButtons in InvoiceForm
85          return false;
86      }
87  
88      @Override
89      public boolean canApprove(Document document) {
90          InvoiceDocument invoiceDocument = (InvoiceDocument) document;
91  
92          if (invoiceDocument.isInvoiceCancelIndicator() || invoiceDocument.isHoldIndicator()) {
93              return false;
94          }
95  
96          return super.canApprove(document);
97      }
98  
99      @Override
100     public boolean canCopy (Document document) {
101         InvoiceDocument invoiceDocument = (InvoiceDocument) document;
102         if (super.canCopy(document)) {
103             if (!StringUtils.equalsIgnoreCase(invoiceDocument.getDocumentHeader().getWorkflowDocument().getStatus().name(), InvoiceStatuses.APPDOC_INITIATE)) {
104                 return true;
105             }
106         }
107         return false;
108 
109     }
110 
111     @Override
112     public boolean canDisapprove(Document document) {
113 
114         WorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument();
115         if (workflowDocument.isEnroute()) {
116             ValidActions validActions = workflowDocument.getValidActions();
117             return validActions.getValidActions().contains(ActionType.DISAPPROVE);
118         }
119 
120         return super.canDisapprove(document);
121     }
122 
123     /**
124      * @see org.kuali.rice.krad.document.DocumentPresentationControllerBase#canEdit(org.kuali.rice.krad.document.Document)
125      */
126     @Override
127     public boolean canEdit(Document document) {
128         InvoiceDocument invoiceDocument = (InvoiceDocument) document;
129         boolean fullDocEntryCompleted = SpringContext.getBean(PurapService.class).isFullDocumentEntryCompleted(invoiceDocument);
130 
131         // if the hold or cancel indicator is true, don't allow editing
132         if (invoiceDocument.isHoldIndicator() || invoiceDocument.isInvoiceCancelIndicator()) {
133             return false;
134         }
135         if (fullDocEntryCompleted) {
136             //  after fullDocEntry is completed, only fiscal officer reviewers can edit
137             if (invoiceDocument.isDocumentStoppedInRouteNode(InvoiceStatuses.NODE_ACCOUNT_REVIEW)) {
138                 return true;
139             }
140             return false;
141         } else {
142             //before fullDocEntry is completed, document can be edited (could be preroute or enroute)
143             return true;
144         }
145     }
146 
147     /**
148      * @see org.kuali.rice.kns.document.authorization.TransactionalDocumentPresentationControllerBase#getEditModes(org.kuali.rice.krad.document.Document)
149      */
150     @Override
151     public Set<String> getEditModes(Document document) {
152         Set<String> editModes = super.getEditModes(document);
153 
154         InvoiceDocument invoiceDocument = (InvoiceDocument) document;
155 
156         if (canProcessorCancel(invoiceDocument)) {
157             editModes.add(InvoiceEditMode.ACCOUNTS_PAYABLE_PROCESSOR_CANCEL);
158         }
159 
160         if (canManagerCancel(invoiceDocument)) {
161             editModes.add(InvoiceEditMode.ACCOUNTS_PAYABLE_MANAGER_CANCEL);
162         }
163 
164         if (canHold(invoiceDocument)) {
165             editModes.add(InvoiceEditMode.HOLD);
166         }
167 
168         if (canRequestCancel(invoiceDocument)) {
169             editModes.add(InvoiceEditMode.REQUEST_CANCEL);
170         }
171 
172         if (canRemoveHold(invoiceDocument)) {
173             editModes.add(InvoiceEditMode.REMOVE_HOLD);
174         }
175 
176         if (canRemoveRequestCancel(invoiceDocument)) {
177             editModes.add(InvoiceEditMode.REMOVE_REQUEST_CANCEL);
178         }
179 
180         if (canProcessorInit(invoiceDocument)) {
181             editModes.add(InvoiceEditMode.DISPLAY_INIT_TAB);
182         }
183 
184         if (ObjectUtils.isNotNull(invoiceDocument.getVendorHeaderGeneratedIdentifier())) {
185             editModes.add(InvoiceEditMode.LOCK_VENDOR_ENTRY);
186         }
187 
188         if (SpringContext.getBean(PurapService.class).isFullDocumentEntryCompleted(invoiceDocument)) {
189             editModes.add(InvoiceEditMode.FULL_DOCUMENT_ENTRY_COMPLETED);
190         }
191         //else if (ObjectUtils.isNotNull(invoiceDocument.getPurchaseOrderDocument()) && PurchaseOrderStatuses.APPDOC_OPEN.equals(invoiceDocument.getPurchaseOrderDocument().getApplicationDocumentStatus())) {
192           /*
193             String documentTypeName = OLEConstants.FinancialDocumentTypeCodes.PAYMENT_REQUEST;
194             String nameSpaceCode = OLEConstants.CoreModuleNamespaces.SELECT;
195 
196             AttributeSet permissionDetails = new AttributeSet();
197             permissionDetails.put(KimAttributes.DOCUMENT_TYPE_NAME,documentTypeName);
198 
199             boolean canClosePO = KIMServiceLocator.getIdentityManagementService().hasPermission(GlobalVariables.getUserSession().getPerson().getPrincipalId(), nameSpaceCode,
200                     OLEConstants.OleInvoice.CAN_CLOSE_PO, permissionDetails);
201             if(canClosePO) {
202             editModes.add(InvoiceEditMode.ALLOW_CLOSE_PURCHASE_ORDER);
203             }*/
204         //  editModes.add(InvoiceEditMode.ALLOW_CLOSE_PURCHASE_ORDER);
205         // }
206 
207         //FIXME hjs: alter to restrict what AP shouldn't be allowed to edit
208         if (canEditPreExtraction(invoiceDocument)) {
209             editModes.add(InvoiceEditMode.EDIT_PRE_EXTRACT);
210         }
211 
212         // See if purap tax is enabled
213         boolean salesTaxInd = SpringContext.getBean(ParameterService.class).getParameterValueAsBoolean(OleParameterConstants.PURCHASING_DOCUMENT.class, PurapParameterConstants.ENABLE_SALES_TAX_IND);
214         if (salesTaxInd) {
215             editModes.add(InvoiceEditMode.PURAP_TAX_ENABLED);
216 
217             if (invoiceDocument.isUseTaxIndicator()) {
218                 // if use tax, don't allow editing of tax fields
219                 editModes.add(InvoiceEditMode.LOCK_TAX_AMOUNT_ENTRY);
220             } else {
221                 // display the "clear all taxes" button if doc is not using use tax
222                 editModes.add(InvoiceEditMode.CLEAR_ALL_TAXES);
223 
224             }
225         }
226 
227         // tax area tab is editable while waiting for tax review
228         if (invoiceDocument.isDocumentStoppedInRouteNode(InvoiceStatuses.NODE_VENDOR_TAX_REVIEW)) {
229             editModes.add(InvoiceEditMode.TAX_AREA_EDITABLE);
230         }
231 
232         if (PurchaseOrderStatuses.APPDOC_AWAIT_TAX_REVIEW
233                 .equals(invoiceDocument.getApplicationDocumentStatus())) {
234             editModes.add(InvoiceEditMode.TAX_AREA_EDITABLE);
235         }
236 
237 
238         // the tax tab is viewable to everyone after tax is approved
239         if (InvoiceStatuses.APPDOC_DEPARTMENT_APPROVED.equals(invoiceDocument.getApplicationDocumentStatus()) &&
240                 // if and only if the invoice has gone through tax review would TaxClassificationCode be non-empty
241                 !StringUtils.isEmpty(invoiceDocument.getTaxClassificationCode())) {
242             editModes.add(InvoiceEditMode.TAX_INFO_VIEWABLE);
243         }
244 
245         if (invoiceDocument.isDocumentStoppedInRouteNode(InvoiceStatuses.NODE_ACCOUNT_REVIEW)) {
246             // remove FULL_ENTRY because FO cannot edit rest of doc; only their own acct lines
247             editModes.add(InvoiceEditMode.RESTRICT_FISCAL_ENTRY);
248 
249             // only do line item check if the hold/cancel indicator is false, otherwise document editing should be turned off.
250             if (!invoiceDocument.isHoldIndicator() && !invoiceDocument.isInvoiceCancelIndicator()) {
251                 List lineList = new ArrayList();
252                 for (Iterator iter = invoiceDocument.getItems().iterator(); iter.hasNext(); ) {
253                     InvoiceItem item = (InvoiceItem) iter.next();
254                     lineList.addAll(item.getSourceAccountingLines());
255                     // If FO has deleted the last accounting line for an item, set entry mode to full so they can add another one
256                     if (item.getItemType().isLineItemIndicator() && item.getSourceAccountingLines().size() == 0) {
257                         editModes.add(OleAuthorizationConstants.TransactionalEditMode.EXPENSE_ENTRY);
258                     }
259                 }
260             }
261         }
262 
263         // Remove editBank edit mode if the document has been extracted
264         if (invoiceDocument.isExtracted()) {
265             editModes.remove(OLEConstants.BANK_ENTRY_EDITABLE_EDITING_MODE);
266         }
267 
268         return editModes;
269     }
270 
271     protected boolean canProcessorInit(InvoiceDocument invoiceDocument) {
272         // if Payment Request is in INITIATE status or NULL returned from getAppDocStatus
273         String status = invoiceDocument.getApplicationDocumentStatus();
274         if (StringUtils.equals(status, InvoiceStatuses.APPDOC_INITIATE)) {
275             return true;
276         }
277         return false;
278     }
279 
280 
281     protected boolean canProcessorCancel(InvoiceDocument invoiceDocument) {
282         // if Payment Request is in INITIATE status, user cannot cancel doc
283         if (canProcessorInit(invoiceDocument)) {
284             return false;
285         }
286 
287         String docStatus = invoiceDocument.getApplicationDocumentStatus();
288         boolean requestCancelIndicator = invoiceDocument.getInvoiceCancelIndicator();
289         boolean holdIndicator = invoiceDocument.isHoldIndicator();
290         boolean extracted = invoiceDocument.isExtracted();
291 
292         boolean preroute =
293                 InvoiceStatuses.APPDOC_IN_PROCESS.equals(docStatus) ||
294                         InvoiceStatuses.APPDOC_AWAITING_ACCOUNTS_PAYABLE_REVIEW.equals(docStatus);
295         boolean enroute =
296                 InvoiceStatuses.APPDOC_AWAITING_SUB_ACCT_MGR_REVIEW.equals(docStatus) ||
297                         InvoiceStatuses.APPDOC_AWAITING_FISCAL_REVIEW.equals(docStatus) ||
298                         InvoiceStatuses.APPDOC_AWAITING_ORG_REVIEW.equals(docStatus) ||
299                         InvoiceStatuses.APPDOC_AWAITING_PAYMENT_REVIEW.equals(docStatus)
300                         ||
301                         InvoiceStatuses.APPDOC_AWAITING_TAX_REVIEW.equals(docStatus);
302         boolean postroute =
303                 InvoiceStatuses.APPDOC_DEPARTMENT_APPROVED.equals(docStatus) ||
304                         InvoiceStatuses.APPDOC_AUTO_APPROVED.equals(docStatus);
305 
306         boolean can = false;
307         if (InvoiceStatuses.STATUSES_PREROUTE.contains(docStatus)) {
308             can = true;
309         } else if (InvoiceStatuses.STATUSES_ENROUTE.contains(docStatus)) {
310             can = requestCancelIndicator;
311         } else if (InvoiceStatuses.STATUSES_POSTROUTE.contains(docStatus)) {
312             can = !requestCancelIndicator && !holdIndicator && !extracted;
313         }
314 
315         return can;
316     }
317 
318     protected boolean canManagerCancel(InvoiceDocument invoiceDocument) {
319         // if Payment Request is in INITIATE status, user cannot cancel doc
320         if (canProcessorInit(invoiceDocument)) {
321             return false;
322         }
323 
324         String docStatus = invoiceDocument.getApplicationDocumentStatus();
325         boolean requestCancelIndicator = invoiceDocument.getInvoiceCancelIndicator();
326         boolean holdIndicator = invoiceDocument.isHoldIndicator();
327         boolean extracted = invoiceDocument.isExtracted();
328 
329         boolean preroute =
330                 InvoiceStatuses.APPDOC_IN_PROCESS.equals(docStatus) ||
331                         InvoiceStatuses.APPDOC_AWAITING_ACCOUNTS_PAYABLE_REVIEW.equals(docStatus);
332         boolean enroute =
333                 InvoiceStatuses.APPDOC_AWAITING_SUB_ACCT_MGR_REVIEW.equals(docStatus) ||
334                         InvoiceStatuses.APPDOC_AWAITING_FISCAL_REVIEW.equals(docStatus) ||
335                         InvoiceStatuses.APPDOC_AWAITING_ORG_REVIEW.equals(docStatus) ||
336                         InvoiceStatuses.APPDOC_AWAITING_PAYMENT_REVIEW.equals(docStatus)
337                         ||
338                         InvoiceStatuses.APPDOC_AWAITING_TAX_REVIEW.equals(docStatus);
339         boolean postroute =
340                 InvoiceStatuses.APPDOC_DEPARTMENT_APPROVED.equals(docStatus) ||
341                         InvoiceStatuses.APPDOC_AUTO_APPROVED.equals(docStatus);
342 
343         boolean can = false;
344         if (InvoiceStatuses.STATUSES_PREROUTE.contains(docStatus) ||
345                 InvoiceStatuses.STATUSES_ENROUTE.contains(docStatus)) {
346             can = true;
347         } else if (InvoiceStatuses.STATUSES_POSTROUTE.contains(docStatus)) {
348             can = !requestCancelIndicator && !holdIndicator && !extracted;
349         }
350 
351         return can;
352     }
353 
354     /**
355      * Determines whether the Invoice Hold button shall be available. Conditions:
356      * - Payment Request is not already on hold, and
357      * - Payment Request is not already being requested to be canceled, and
358      * - Payment Request has not already been extracted to PDP, and
359      * - Payment Request status is not in the list of "STATUSES_DISALLOWING_HOLD" or document is being adhoc routed; and
360      *
361      * @return True if the document state allows placing the Payment Request on hold.
362      */
363     protected boolean canHold(InvoiceDocument invoiceDocument) {
364         if (canHold == null) {
365 
366             boolean can = !invoiceDocument.isHoldIndicator()
367                     && !invoiceDocument.isInvoiceCancelIndicator()
368                     && !invoiceDocument.isExtracted();
369             if (can) {
370                 can = SpringContext.getBean(FinancialSystemWorkflowHelperService.class)
371                         .isAdhocApprovalRequestedForPrincipal(
372                                 invoiceDocument.getFinancialSystemDocumentHeader().getWorkflowDocument(),
373                                 GlobalVariables.getUserSession().getPrincipalId());
374                 can = can
375                         || !InvoiceStatuses.STATUSES_DISALLOWING_HOLD.contains(invoiceDocument
376                         .getApplicationDocumentStatus());
377             }
378             canHold = can;
379         }
380 
381         return canHold;
382     }
383 
384     /**
385      * Determines whether the Request Cancel Invoice button shall be available. Conditions:
386      * - Payment Request is not already on hold, and
387      * - Payment Request is not already being requested to be canceled, and
388      * - Payment Request has not already been extracted to PDP, and
389      * - Payment Request status is not in the list of "STATUSES_DISALLOWING_REQUEST_CANCEL" or document is being adhoc routed; and
390      *
391      * @return True if the document state allows placing the request that the Payment Request be canceled.
392      */
393     protected boolean canRequestCancel(InvoiceDocument invoiceDocument) {
394         if (canRequestCancel == null) {
395             boolean can = !invoiceDocument.isInvoiceCancelIndicator()
396                     && !invoiceDocument.isHoldIndicator() && !invoiceDocument.isExtracted();
397             if (can) {
398                 can = SpringContext.getBean(FinancialSystemWorkflowHelperService.class)
399                         .isAdhocApprovalRequestedForPrincipal(
400                                 invoiceDocument.getFinancialSystemDocumentHeader().getWorkflowDocument(),
401                                 GlobalVariables.getUserSession().getPrincipalId());
402                 can = can
403                         || !InvoiceStatuses.STATUSES_DISALLOWING_REQUEST_CANCEL.contains(invoiceDocument
404                         .getApplicationDocumentStatus());
405             }
406             canRequestCancel = can;
407         }
408         return canRequestCancel;
409     }
410 
411     /**
412      * Determines whether the Remove Hold button shall be available. Conditions:
413      * - the hold indicator is set to true
414      * <p/>
415      * Because the state of the Payment Request cannot be changed while the document is on hold,
416      * we should not have to check the state of the document to remove the hold.
417      * For example, the document should not be allowed to be approved or extracted while on hold.
418      *
419      * @return True if the document state allows removing the Payment Request from hold.
420      */
421     protected boolean canRemoveHold(InvoiceDocument invoiceDocument) {
422         return invoiceDocument.isHoldIndicator();
423     }
424 
425     /**
426      * Determines whether the Remove Request Cancel button shall be available. Conditions:
427      * - the request cancel indicator is set to true;  and
428      * <p/>
429      * Because the state of the Payment Request cannot be changed while the document is set to request cancel,
430      * we should not have to check the state of the document to remove the request cancel.
431      * For example, the document should not be allowed to be approved or extracted while set to request cancel.
432      *
433      * @return True if the document state allows removing a request that the Payment Request be canceled.
434      */
435     protected boolean canRemoveRequestCancel(InvoiceDocument invoiceDocument) {
436         return invoiceDocument.isInvoiceCancelIndicator();
437     }
438 
439     protected boolean canEditPreExtraction(InvoiceDocument invoiceDocument) {
440         if (canEditPreExtraction == null) {
441             boolean can = (!invoiceDocument.isExtracted()
442                     && !SpringContext.getBean(FinancialSystemWorkflowHelperService.class)
443                     .isAdhocApprovalRequestedForPrincipal(
444                             invoiceDocument.getFinancialSystemDocumentHeader().getWorkflowDocument(),
445                             GlobalVariables.getUserSession().getPrincipalId()) && !InvoiceStatuses.CANCELLED_STATUSES
446                     .contains(invoiceDocument.getApplicationDocumentStatus()));
447             canEditPreExtraction = can;
448         }
449         return canEditPreExtraction;
450     }
451 
452 }