View Javadoc
1   /*
2    * Copyright 2007 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.web.struts;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.apache.struts.action.ActionForm;
20  import org.apache.struts.action.ActionForward;
21  import org.apache.struts.action.ActionMapping;
22  import org.kuali.ole.module.purap.PurapConstants;
23  import org.kuali.ole.module.purap.PurapConstants.PREQDocumentsStrings;
24  import org.kuali.ole.module.purap.PurapConstants.PaymentRequestStatuses;
25  import org.kuali.ole.module.purap.PurapKeyConstants;
26  import org.kuali.ole.module.purap.PurapPropertyConstants;
27  import org.kuali.ole.module.purap.document.AccountsPayableDocument;
28  import org.kuali.ole.module.purap.document.PaymentRequestDocument;
29  import org.kuali.ole.module.purap.document.PurchaseOrderDocument;
30  import org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocument;
31  import org.kuali.ole.module.purap.document.service.PaymentRequestService;
32  import org.kuali.ole.module.purap.document.service.PurapService;
33  import org.kuali.ole.module.purap.document.service.PurchaseOrderService;
34  import org.kuali.ole.module.purap.document.validation.event.AttributedCalculateAccountsPayableEvent;
35  import org.kuali.ole.module.purap.document.validation.event.AttributedContinuePurapEvent;
36  import org.kuali.ole.module.purap.document.validation.event.AttributedPreCalculateAccountsPayableEvent;
37  import org.kuali.ole.module.purap.service.PurapAccountingService;
38  import org.kuali.ole.module.purap.util.PurQuestionCallback;
39  import org.kuali.ole.sys.OLEConstants;
40  import org.kuali.ole.sys.OLEKeyConstants;
41  import org.kuali.ole.sys.OLEPropertyConstants;
42  import org.kuali.ole.sys.context.SpringContext;
43  import org.kuali.ole.sys.service.UniversityDateService;
44  import org.kuali.rice.core.api.config.property.ConfigurationService;
45  import org.kuali.rice.core.api.util.RiceConstants;
46  import org.kuali.rice.kew.api.exception.WorkflowException;
47  import org.kuali.rice.kim.api.KimConstants;
48  import org.kuali.rice.kns.question.ConfirmationQuestion;
49  import org.kuali.rice.kns.service.DocumentHelperService;
50  import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase;
51  import org.kuali.rice.krad.service.KualiRuleService;
52  import org.kuali.rice.krad.util.GlobalVariables;
53  import org.kuali.rice.krad.util.KRADConstants;
54  import org.kuali.rice.krad.util.ObjectUtils;
55  
56  import javax.servlet.http.HttpServletRequest;
57  import javax.servlet.http.HttpServletResponse;
58  import java.util.HashMap;
59  
60  /**
61   * Struts Action for Payment Request document.
62   */
63  public class PaymentRequestAction extends AccountsPayableActionBase {
64      static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PaymentRequestAction.class);
65  
66      /**
67       * Do initialization for a new payment request.
68       *
69       * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#createDocument(org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase)
70       */
71      @Override
72      protected void createDocument(KualiDocumentFormBase kualiDocumentFormBase) throws WorkflowException {
73          super.createDocument(kualiDocumentFormBase);
74          ((PaymentRequestDocument) kualiDocumentFormBase.getDocument()).initiateDocument();
75      }
76  
77      /**
78       * @see org.kuali.rice.kns.web.struts.action.KualiAction#refresh(org.apache.struts.action.ActionMapping,
79       *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
80       */
81      @Override
82      public ActionForward refresh(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
83          PaymentRequestForm preqForm = (PaymentRequestForm) form;
84          PaymentRequestDocument document = (PaymentRequestDocument) preqForm.getDocument();
85  
86          return super.refresh(mapping, form, request, response);
87      }
88  
89      /**
90       * Executes the continue action on a payment request. Populates and initializes the rest of the payment request besides what was
91       * shown on the init screen.
92       *
93       * @param mapping  An ActionMapping
94       * @param form     An ActionForm
95       * @param request  The HttpServletRequest
96       * @param response The HttpServletResponse
97       * @return An ActionForward
98       * @throws Exception
99       */
100     public ActionForward continuePREQ(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
101         LOG.debug("continuePREQ() method");
102         PaymentRequestForm preqForm = (PaymentRequestForm) form;
103         PaymentRequestDocument paymentRequestDocument = (PaymentRequestDocument) preqForm.getDocument();
104 
105         boolean poNotNull = true;
106 
107         boolean rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new AttributedContinuePurapEvent(paymentRequestDocument));
108         if (!rulePassed) {
109             return mapping.findForward(OLEConstants.MAPPING_BASIC);
110         }
111 
112         GlobalVariables.getMessageMap().clearErrorPath();
113         GlobalVariables.getMessageMap().addToErrorPath(OLEPropertyConstants.DOCUMENT);
114 
115         //check for a po id
116         if (ObjectUtils.isNull(paymentRequestDocument.getPurchaseOrderIdentifier())) {
117             GlobalVariables.getMessageMap().putError(PurapPropertyConstants.PURCHASE_ORDER_IDENTIFIER, OLEKeyConstants.ERROR_REQUIRED, PREQDocumentsStrings.PURCHASE_ORDER_ID);
118             poNotNull = false;
119         }
120 
121         if (ObjectUtils.isNull(paymentRequestDocument.getInvoiceDate())) {
122             GlobalVariables.getMessageMap().putError(PurapPropertyConstants.INVOICE_DATE, OLEKeyConstants.ERROR_REQUIRED, PREQDocumentsStrings.INVOICE_DATE);
123             poNotNull = false;
124         }
125 
126         /*if (ObjectUtils.isNull(paymentRequestDocument.getInvoiceNumber())) {
127             GlobalVariables.getMessageMap().putError(PurapPropertyConstants.INVOICE_NUMBER, OLEKeyConstants.ERROR_REQUIRED, PREQDocumentsStrings.INVOICE_NUMBER);
128             poNotNull = false;
129         }*/
130         if (ObjectUtils.isNotNull(paymentRequestDocument.getInvoiceNumber())) {
131             paymentRequestDocument.setInvoiceNumber(paymentRequestDocument.getInvoiceNumber().toUpperCase());
132         }
133 
134         if (ObjectUtils.isNull(paymentRequestDocument.getVendorInvoiceAmount())) {
135             GlobalVariables.getMessageMap().putError(PurapPropertyConstants.VENDOR_INVOICE_AMOUNT, OLEKeyConstants.ERROR_REQUIRED, PREQDocumentsStrings.VENDOR_INVOICE_AMOUNT);
136             poNotNull = false;
137         }
138 
139         //exit early as the po is null, no need to proceed further until this is taken care of
140         if (poNotNull == false) {
141             return mapping.findForward(OLEConstants.MAPPING_BASIC);
142         }
143 
144 
145         PurchaseOrderDocument po = SpringContext.getBean(PurchaseOrderService.class).getCurrentPurchaseOrder(paymentRequestDocument.getPurchaseOrderIdentifier());
146         if (ObjectUtils.isNotNull(po)) {
147             // TODO figure out a more straightforward way to do this.  ailish put this in so the link id would be set and the perm check would work
148             paymentRequestDocument.setAccountsPayablePurchasingDocumentLinkIdentifier(po.getAccountsPayablePurchasingDocumentLinkIdentifier());
149 
150             //check to see if user is allowed to initiate doc based on PO sensitive data
151             if (!SpringContext.getBean(DocumentHelperService.class).getDocumentAuthorizer(paymentRequestDocument).isAuthorizedByTemplate(paymentRequestDocument, KRADConstants.KNS_NAMESPACE, KimConstants.PermissionTemplateNames.OPEN_DOCUMENT, GlobalVariables.getUserSession().getPrincipalId())) {
152                 throw buildAuthorizationException("initiate document", paymentRequestDocument);
153             }
154         }
155 
156         if (!SpringContext.getBean(PaymentRequestService.class).isPurchaseOrderValidForPaymentRequestDocumentCreation(paymentRequestDocument, po)) {
157             return mapping.findForward(OLEConstants.MAPPING_BASIC);
158         }
159 
160         // perform duplicate check which will forward to a question prompt if one is found
161         ActionForward forward = performDuplicatePaymentRequestAndEncumberFiscalYearCheck(mapping, form, request, response, paymentRequestDocument);
162         if (forward != null) {
163             return forward;
164         }
165 
166         // If we are here either there was no duplicate or there was a duplicate and the user hits continue, in either case we need
167         // to validate the business rules
168         SpringContext.getBean(PaymentRequestService.class).populateAndSavePaymentRequest(paymentRequestDocument);
169 
170         // force calculation
171         preqForm.setCalculated(false);
172 
173         //TODO if better, move this to the action just before preq goes into ATAX status
174         // force calculation for tax
175         preqForm.setCalculatedTax(false);
176 
177         // sort below the line
178         SpringContext.getBean(PurapService.class).sortBelowTheLine(paymentRequestDocument);
179 
180         // update the counts on the form
181         preqForm.updateItemCounts();
182 
183         return mapping.findForward(OLEConstants.MAPPING_BASIC);
184     }
185 
186 
187     /**
188      * Clears the initial fields on the <code>PaymentRequestDocument</code> which should be accessible from the given form.
189      *
190      * @param mapping  An ActionMapping
191      * @param form     An ActionForm, which must be a PaymentRequestForm
192      * @param request  The HttpServletRequest
193      * @param response The HttpServletResponse
194      * @return An ActionForward
195      * @throws Exception
196      */
197     public ActionForward clearInitFields(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
198         LOG.debug("clearInitValues() method");
199         PaymentRequestForm preqForm = (PaymentRequestForm) form;
200         PaymentRequestDocument paymentRequestDocument = (PaymentRequestDocument) preqForm.getDocument();
201         paymentRequestDocument.clearInitFields();
202 
203         return super.refresh(mapping, form, request, response);
204     }
205 
206     /**
207      * This method runs two checks based on the user input on PREQ initiate screen: Encumber next fiscal year check and Duplicate
208      * payment request check. Encumber next fiscal year is checked first and will display a warning message to the user if it's the
209      * case. Duplicate payment request check calls <code>PaymentRequestService</code> to perform the duplicate payment request
210      * check. If one is found, a question is setup and control is forwarded to the question action method. Coming back from the
211      * question prompt the button that was clicked is checked and if 'no' was selected they are forward back to the page still in
212      * init mode.
213      *
214      * @param mapping                An ActionMapping
215      * @param form                   An ActionForm
216      * @param request                The HttpServletRequest
217      * @param response               The HttpServletResponse
218      * @param paymentRequestDocument The PaymentRequestDocument
219      * @return An ActionForward
220      * @throws Exception
221      * @see org.kuali.ole.module.purap.document.service.PaymentRequestService
222      */
223     protected ActionForward performDuplicatePaymentRequestAndEncumberFiscalYearCheck(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, PaymentRequestDocument paymentRequestDocument) throws Exception {
224         ActionForward forward = null;
225         Object question = request.getParameter(OLEConstants.QUESTION_INST_ATTRIBUTE_NAME);
226         if (question == null) {
227             // perform encumber next fiscal year check and prompt warning message if needs
228             if (isEncumberNextFiscalYear(paymentRequestDocument)) {
229                 String questionText = SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(PurapKeyConstants.WARNING_ENCUMBER_NEXT_FY);
230                 return this.performQuestionWithoutInput(mapping, form, request, response, PREQDocumentsStrings.ENCUMBER_NEXT_FISCAL_YEAR_QUESTION, questionText, OLEConstants.CONFIRMATION_QUESTION, OLEConstants.ROUTE_METHOD, "");
231             } else {
232                 // perform duplicate payment request check
233                 HashMap<String, String> duplicateMessages = SpringContext.getBean(PaymentRequestService.class).paymentRequestDuplicateMessages(paymentRequestDocument);
234                 if (!duplicateMessages.isEmpty()) {
235                     return this.performQuestionWithoutInput(mapping, form, request, response, PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION, duplicateMessages.get(PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION), OLEConstants.CONFIRMATION_QUESTION, OLEConstants.ROUTE_METHOD, "");
236                 }
237             }
238         } else {
239             Object buttonClicked = request.getParameter(OLEConstants.QUESTION_CLICKED_BUTTON);
240             // If the user replies 'Yes' to the encumber-next-year-question, proceed with duplicate payment check
241             if (PurapConstants.PREQDocumentsStrings.ENCUMBER_NEXT_FISCAL_YEAR_QUESTION.equals(question) && ConfirmationQuestion.YES.equals(buttonClicked)) {
242                 HashMap<String, String> duplicateMessages = SpringContext.getBean(PaymentRequestService.class).paymentRequestDuplicateMessages(paymentRequestDocument);
243                 if (!duplicateMessages.isEmpty()) {
244                     return this.performQuestionWithoutInput(mapping, form, request, response, PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION, duplicateMessages.get(PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION), OLEConstants.CONFIRMATION_QUESTION, OLEConstants.ROUTE_METHOD, "");
245                 }
246             }
247             // If the user replies 'No' to either of the questions, redirect to the PREQ initiate page.
248             else if ((PurapConstants.PREQDocumentsStrings.ENCUMBER_NEXT_FISCAL_YEAR_QUESTION.equals(question) || PurapConstants.PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION.equals(question)) && ConfirmationQuestion.NO.equals(buttonClicked)) {
249                 paymentRequestDocument.updateAndSaveAppDocStatus(PurapConstants.PaymentRequestStatuses.APPDOC_INITIATE);
250                 forward = mapping.findForward(OLEConstants.MAPPING_BASIC);
251             }
252         }
253 
254         return forward;
255     }
256 
257     /**
258      * Check if the current PREQ encumber next fiscal year from PO document.
259      *
260      * @param paymentRequestDocument
261      * @return
262      */
263     protected boolean isEncumberNextFiscalYear(PaymentRequestDocument paymentRequestDocument) {
264         Integer fiscalYear = SpringContext.getBean(UniversityDateService.class).getCurrentFiscalYear();
265         if (paymentRequestDocument.getPurchaseOrderDocument().getPostingYear().intValue() > fiscalYear) {
266             return true;
267         }
268         return false;
269     }
270 
271     /**
272      * Puts a payment on hold, prompting for a reason beforehand. This stops further approvals or routing.
273      *
274      * @param mapping  An ActionMapping
275      * @param form     An ActionForm
276      * @param request  The HttpServletRequest
277      * @param response The HttpServletResponse
278      * @return An ActionForward
279      * @throws Exception
280      */
281     public ActionForward addHoldOnPayment(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
282         String operation = "Hold ";
283 
284         PurQuestionCallback callback = new PurQuestionCallback() {
285             @Override
286             public AccountsPayableDocument doPostQuestion(AccountsPayableDocument document, String noteText) throws Exception {
287                 document = SpringContext.getBean(PaymentRequestService.class).addHoldOnPaymentRequest((PaymentRequestDocument) document, noteText);
288                 return document;
289             }
290         };
291 
292         return askQuestionWithInput(mapping, form, request, response, PREQDocumentsStrings.HOLD_PREQ_QUESTION, PREQDocumentsStrings.HOLD_NOTE_PREFIX, operation, PurapKeyConstants.PAYMENT_REQUEST_MESSAGE_HOLD_DOCUMENT, callback);
293     }
294 
295     /**
296      * Removes a hold on the payment request.
297      *
298      * @param mapping  An ActionMapping
299      * @param form     An ActionForm
300      * @param request  The HttpServletRequest
301      * @param response The HttpServletResponse
302      * @return An ActionForward
303      * @throws Exception
304      */
305     public ActionForward removeHoldFromPayment(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
306         String operation = "Remove ";
307 
308         PurQuestionCallback callback = new PurQuestionCallback() {
309             @Override
310             public AccountsPayableDocument doPostQuestion(AccountsPayableDocument document, String noteText) throws Exception {
311                 document = SpringContext.getBean(PaymentRequestService.class).removeHoldOnPaymentRequest((PaymentRequestDocument) document, noteText);
312                 return document;
313             }
314         };
315 
316         return askQuestionWithInput(mapping, form, request, response, PREQDocumentsStrings.REMOVE_HOLD_PREQ_QUESTION, PREQDocumentsStrings.REMOVE_HOLD_NOTE_PREFIX, operation, PurapKeyConstants.PAYMENT_REQUEST_MESSAGE_REMOVE_HOLD_DOCUMENT, callback);
317     }
318 
319     /**
320      * This action requests a cancel on a preq, prompting for a reason before hand. This stops further approvals or routing.
321      *
322      * @param mapping  An ActionMapping
323      * @param form     An ActionForm
324      * @param request  The HttpServletRequest
325      * @param response The HttpServletResponse
326      * @return An ActionForward
327      * @throws Exception
328      */
329     public ActionForward requestCancelOnPayment(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
330         String operation = "Cancel ";
331 
332         PurQuestionCallback callback = new PurQuestionCallback() {
333             @Override
334             public AccountsPayableDocument doPostQuestion(AccountsPayableDocument document, String noteText) throws Exception {
335                 SpringContext.getBean(PaymentRequestService.class).requestCancelOnPaymentRequest((PaymentRequestDocument) document, noteText);
336                 return document;
337             }
338         };
339 
340         return askQuestionWithInput(mapping, form, request, response, PREQDocumentsStrings.CANCEL_PREQ_QUESTION, PREQDocumentsStrings.CANCEL_NOTE_PREFIX, operation, PurapKeyConstants.PAYMENT_REQUEST_MESSAGE_CANCEL_DOCUMENT, callback);
341     }
342 
343     /**
344      * @see org.kuali.ole.module.purap.document.web.struts.AccountsPayableActionBase#cancelPOActionCallbackMethod()
345      */
346 //    @Override
347 //    protected PurQuestionCallback cancelPOActionCallbackMethod() {
348 //
349 //        return new PurQuestionCallback() {
350 //            public AccountsPayableDocument doPostQuestion(AccountsPayableDocument document, String noteText) throws Exception {
351 //                PaymentRequestDocument preqDocument = (PaymentRequestDocument) document;
352 //                preqDocument.setReopenPurchaseOrderIndicator(true);
353 //                return preqDocument;
354 //            }
355 //        };
356 //    }
357 
358     /**
359      * Removes a request for cancel on a payment request.
360      *
361      * @param mapping  An ActionMapping
362      * @param form     An ActionForm
363      * @param request  The HttpServletRequest
364      * @param response The HttpServletResponse
365      * @return An ActionForward
366      * @throws Exception
367      */
368     public ActionForward removeCancelRequestFromPayment(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
369         String operation = "Cancel ";
370 
371         PurQuestionCallback callback = new PurQuestionCallback() {
372             @Override
373             public AccountsPayableDocument doPostQuestion(AccountsPayableDocument document, String noteText) throws Exception {
374                 SpringContext.getBean(PaymentRequestService.class).removeRequestCancelOnPaymentRequest((PaymentRequestDocument) document, noteText);
375                 return document;
376             }
377         };
378 
379         return askQuestionWithInput(mapping, form, request, response, PREQDocumentsStrings.REMOVE_CANCEL_PREQ_QUESTION, PREQDocumentsStrings.REMOVE_CANCEL_NOTE_PREFIX, operation, PurapKeyConstants.PAYMENT_REQUEST_MESSAGE_REMOVE_CANCEL_DOCUMENT, callback);
380     }
381 
382     /**
383      * Calls a service method to calculate for a payment request document.
384      *
385      * @param apDoc The AccountsPayableDocument
386      */
387     @Override
388     protected void customCalculate(PurchasingAccountsPayableDocument apDoc) {
389         PaymentRequestDocument preqDoc = (PaymentRequestDocument) apDoc;
390 
391         // set amounts on any empty
392         preqDoc.updateExtendedPriceOnItems();
393 
394         // calculation just for the tax area, only at tax review stage
395         // by now, the general calculation shall have been done.
396         if (StringUtils.equals(preqDoc.getApplicationDocumentStatus(), PaymentRequestStatuses.APPDOC_AWAITING_TAX_REVIEW)) {
397             SpringContext.getBean(PaymentRequestService.class).calculateTaxArea(preqDoc);
398             return;
399         }
400 
401         // notice we're ignoring whether the boolean, because these are just warnings they shouldn't halt anything
402         //Calculate Payment request before rules since the rule check totalAmount.
403         SpringContext.getBean(PaymentRequestService.class).calculatePaymentRequest(preqDoc, true);
404         SpringContext.getBean(KualiRuleService.class).applyRules(new AttributedCalculateAccountsPayableEvent(preqDoc));
405     }
406 
407     /**
408      * @see org.kuali.ole.module.purap.document.web.struts.AccountsPayableActionBase#getActionName()
409      */
410     @Override
411     public String getActionName() {
412         return PurapConstants.PAYMENT_REQUEST_ACTION_NAME;
413     }
414 
415     public ActionForward useAlternateVendor(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
416         PaymentRequestForm preqForm = (PaymentRequestForm) form;
417         PaymentRequestDocument document = (PaymentRequestDocument) preqForm.getDocument();
418 
419         SpringContext.getBean(PaymentRequestService.class).changeVendor(
420                 document, document.getAlternateVendorHeaderGeneratedIdentifier(), document.getAlternateVendorDetailAssignedIdentifier());
421 
422         return mapping.findForward(OLEConstants.MAPPING_BASIC);
423     }
424 
425     public ActionForward useOriginalVendor(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
426         PaymentRequestForm preqForm = (PaymentRequestForm) form;
427         PaymentRequestDocument document = (PaymentRequestDocument) preqForm.getDocument();
428 
429         SpringContext.getBean(PaymentRequestService.class).changeVendor(
430                 document, document.getOriginalVendorHeaderGeneratedIdentifier(), document.getOriginalVendorDetailAssignedIdentifier());
431 
432         return mapping.findForward(OLEConstants.MAPPING_BASIC);
433     }
434 
435     @Override
436     public ActionForward route(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
437         PaymentRequestDocument preq = ((PaymentRequestForm) form).getPaymentRequestDocument();
438         SpringContext.getBean(PurapService.class).prorateForTradeInAndFullOrderDiscount(preq);
439         SpringContext.getBean(PurapAccountingService.class).updateAccountAmounts(preq);
440         if (preq.isClosePurchaseOrderIndicator()) {
441             PurchaseOrderDocument po = preq.getPurchaseOrderDocument();
442             if (po.canClosePOForTradeIn()) {
443                 return super.route(mapping, form, request, response);
444             } else {
445                 return mapping.findForward(OLEConstants.MAPPING_BASIC);
446             }
447         } else {
448             return super.route(mapping, form, request, response);
449         }
450     }
451 
452     /**
453      * Overrides to invoke the updateAccountAmounts so that the account percentage will be
454      * correctly updated before validation for account percent is called.
455      *
456      * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#approve(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
457      */
458     @Override
459     public ActionForward approve(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
460         PaymentRequestDocument preq = ((PaymentRequestForm) form).getPaymentRequestDocument();
461 
462         SpringContext.getBean(PurapService.class).prorateForTradeInAndFullOrderDiscount(preq);
463         // if tax is required but not yet calculated, return and prompt user to calculate
464         if (requiresCalculateTax((PaymentRequestForm) form)) {
465             GlobalVariables.getMessageMap().putError(OLEConstants.DOCUMENT_ERRORS, PurapKeyConstants.ERROR_APPROVE_REQUIRES_CALCULATE);
466             return mapping.findForward(OLEConstants.MAPPING_BASIC);
467         }
468 
469         // enforce calculating tax again upon approval, just in case user changes tax data without calculation
470         // other wise there will be a loophole, because the taxCalculated indicator is already set upon first calculation
471         // and thus system wouldn't know it's not re-calculated after tax data are changed
472         if (SpringContext.getBean(KualiRuleService.class).applyRules(new AttributedPreCalculateAccountsPayableEvent(preq))) {
473             // pre-calculation rules succeed, calculate tax again and go ahead with approval
474             //customCalculate(preq);
475             SpringContext.getBean(PurapAccountingService.class).updateAccountAmounts(preq);
476             return super.approve(mapping, form, request, response);
477         } else {
478             // pre-calculation rules fail, go back to same page with error messages
479             return mapping.findForward(OLEConstants.MAPPING_BASIC);
480         }
481     }
482 
483     /**
484      * Checks if tax calculation is required.
485      * Currently it is required when preq is awaiting for tax approval and tax has not already been calculated.
486      *
487      * @param apForm A Form, which must inherit from <code>AccountsPayableFormBase</code>
488      * @return true if calculation is required, false otherwise
489      */
490     protected boolean requiresCalculateTax(PaymentRequestForm preqForm) {
491         PaymentRequestDocument preq = (PaymentRequestDocument) preqForm.getDocument();
492         boolean requiresCalculateTax = StringUtils.equals(preq.getApplicationDocumentStatus(), PaymentRequestStatuses.APPDOC_AWAITING_TAX_REVIEW) && !preqForm.isCalculatedTax();
493         return requiresCalculateTax;
494     }
495 
496     public ActionForward changeUseTaxIndicator(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
497         PurchasingAccountsPayableDocument document = (PurchasingAccountsPayableDocument) ((PurchasingAccountsPayableFormBase) form).getDocument();
498 
499         //clear/recalculate tax and recreate GL entries
500         SpringContext.getBean(PurapService.class).updateUseTaxIndicator(document, !document.isUseTaxIndicator());
501         SpringContext.getBean(PurapService.class).calculateTax(document);
502 
503         //TODO: add recalculate GL entries hook here
504 
505         return mapping.findForward(OLEConstants.MAPPING_BASIC);
506     }
507 
508     /**
509      * Calls service to clear tax info.
510      */
511     public ActionForward clearTaxInfo(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
512         PaymentRequestForm prForm = (PaymentRequestForm) form;
513         PaymentRequestDocument document = (PaymentRequestDocument) prForm.getDocument();
514 
515         PaymentRequestService taxService = SpringContext.getBean(PaymentRequestService.class);
516 
517         /* call service to clear previous lines */
518         taxService.clearTax(document);
519 
520         return mapping.findForward(OLEConstants.MAPPING_BASIC);
521     }
522 
523     //MSU Contribution OLEMI-8558 DTT-3765 OLECNTRB-963
524     @Override
525     public ActionForward cancel(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
526         PaymentRequestForm preqForm = (PaymentRequestForm) form;
527 
528         PaymentRequestDocument preqDocument = (PaymentRequestDocument) preqForm.getDocument();
529 
530         ActionForward forward = mapping.findForward(RiceConstants.MAPPING_BASIC);
531         if (preqDocument.getPurchaseOrderDocument().isPendingActionIndicator()) {
532             GlobalVariables.getMessageMap().putError(
533                     OLEPropertyConstants.DOCUMENT + "." + OLEPropertyConstants.DOCUMENT_NUMBER,
534                     PurapKeyConstants.ERROR_PAYMENT_REQUEST_CANNOT_BE_CANCELLED);
535         } else {
536             forward = super.cancel(mapping, form, request, response);
537         }
538 
539         return forward;
540     }
541 }