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