001/*
002 * Copyright 2007 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.web.struts;
017
018import org.apache.commons.lang.StringUtils;
019import org.apache.struts.action.ActionForm;
020import org.apache.struts.action.ActionForward;
021import org.apache.struts.action.ActionMapping;
022import org.kuali.ole.module.purap.PurapConstants;
023import org.kuali.ole.module.purap.PurapConstants.InvoiceStatuses;
024import org.kuali.ole.module.purap.PurapConstants.PRQSDocumentsStrings;
025import org.kuali.ole.module.purap.PurapKeyConstants;
026import org.kuali.ole.module.purap.PurapPropertyConstants;
027import org.kuali.ole.module.purap.document.AccountsPayableDocument;
028import org.kuali.ole.module.purap.document.InvoiceDocument;
029import org.kuali.ole.module.purap.document.PurchaseOrderDocument;
030import org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocument;
031import org.kuali.ole.module.purap.document.service.InvoiceService;
032import org.kuali.ole.module.purap.document.service.PurapService;
033import org.kuali.ole.module.purap.document.service.PurchaseOrderService;
034import org.kuali.ole.module.purap.document.validation.event.AttributedCalculateAccountsPayableEvent;
035import org.kuali.ole.module.purap.document.validation.event.AttributedContinuePurapEvent;
036import org.kuali.ole.module.purap.document.validation.event.AttributedPreCalculateAccountsPayableEvent;
037import org.kuali.ole.module.purap.service.PurapAccountingService;
038import org.kuali.ole.module.purap.util.PurQuestionCallback;
039import org.kuali.ole.sys.OLEConstants;
040import org.kuali.ole.sys.OLEKeyConstants;
041import org.kuali.ole.sys.OLEPropertyConstants;
042import org.kuali.ole.sys.context.SpringContext;
043import org.kuali.ole.sys.service.UniversityDateService;
044import org.kuali.rice.core.api.config.property.ConfigurationService;
045import org.kuali.rice.core.api.util.RiceConstants;
046import org.kuali.rice.kew.api.exception.WorkflowException;
047import org.kuali.rice.kim.api.KimConstants;
048import org.kuali.rice.kns.question.ConfirmationQuestion;
049import org.kuali.rice.kns.service.DocumentHelperService;
050import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase;
051import org.kuali.rice.krad.service.KualiRuleService;
052import org.kuali.rice.krad.util.GlobalVariables;
053import org.kuali.rice.krad.util.KRADConstants;
054import org.kuali.rice.krad.util.ObjectUtils;
055
056import javax.servlet.http.HttpServletRequest;
057import javax.servlet.http.HttpServletResponse;
058import java.util.HashMap;
059
060/**
061 * Struts Action for Payment Request document.
062 */
063public class InvoiceAction extends AccountsPayableActionBase {
064    static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(InvoiceAction.class);
065
066    /**
067     * Do initialization for a new payment request.
068     *
069     * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#createDocument(org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase)
070     */
071    @Override
072    protected void createDocument(KualiDocumentFormBase kualiDocumentFormBase) throws WorkflowException {
073        super.createDocument(kualiDocumentFormBase);
074        ((InvoiceDocument) kualiDocumentFormBase.getDocument()).initiateDocument();
075    }
076
077    /**
078     * @see org.kuali.rice.kns.web.struts.action.KualiAction#refresh(org.apache.struts.action.ActionMapping,
079     *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
080     */
081    @Override
082    public ActionForward refresh(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
083        InvoiceForm prqsForm = (InvoiceForm) form;
084        InvoiceDocument document = (InvoiceDocument) prqsForm.getDocument();
085
086        return super.refresh(mapping, form, request, response);
087    }
088
089    /**
090     * Executes the continue action on a payment request. Populates and initializes the rest of the payment request besides what was
091     * shown on the init screen.
092     *
093     * @param mapping  An ActionMapping
094     * @param form     An ActionForm
095     * @param request  The HttpServletRequest
096     * @param response The HttpServletResponse
097     * @return An ActionForward
098     * @throws Exception
099     */
100    public ActionForward continuePRQS(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
101        LOG.debug("continuePRQS() method");
102        InvoiceForm prqsForm = (InvoiceForm) form;
103        InvoiceDocument invoiceDocument = (InvoiceDocument) prqsForm.getDocument();
104
105        boolean poNotNull = true;
106
107        boolean rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new AttributedContinuePurapEvent(invoiceDocument));
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(invoiceDocument.getPurchaseOrderIdentifier())) {
117            GlobalVariables.getMessageMap().putError(PurapPropertyConstants.PURCHASE_ORDER_IDENTIFIER, OLEKeyConstants.ERROR_REQUIRED, PRQSDocumentsStrings.PURCHASE_ORDER_ID);
118            poNotNull = false;
119        }
120
121        if (ObjectUtils.isNull(invoiceDocument.getInvoiceDate())) {
122            GlobalVariables.getMessageMap().putError(PurapPropertyConstants.INVOICE_DATE, OLEKeyConstants.ERROR_REQUIRED, PRQSDocumentsStrings.INVOICE_DATE);
123            poNotNull = false;
124        }
125
126        /*if (ObjectUtils.isNull(invoiceDocument.getInvoiceNumber())) {
127            GlobalVariables.getMessageMap().putError(PurapPropertyConstants.INVOICE_NUMBER, OLEKeyConstants.ERROR_REQUIRED, PRQSDocumentsStrings.INVOICE_NUMBER);
128            poNotNull = false;
129        }*/
130        invoiceDocument.setInvoiceNumber(invoiceDocument.getInvoiceNumber().toUpperCase());
131
132        if (ObjectUtils.isNull(invoiceDocument.getVendorInvoiceAmount())) {
133            GlobalVariables.getMessageMap().putError(PurapPropertyConstants.VENDOR_INVOICE_AMOUNT, OLEKeyConstants.ERROR_REQUIRED, PRQSDocumentsStrings.VENDOR_INVOICE_AMOUNT);
134            poNotNull = false;
135        }
136
137        //exit early as the po is null, no need to proceed further until this is taken care of
138        if (poNotNull == false) {
139            return mapping.findForward(OLEConstants.MAPPING_BASIC);
140        }
141
142
143        PurchaseOrderDocument po = SpringContext.getBean(PurchaseOrderService.class).getCurrentPurchaseOrder(invoiceDocument.getPurchaseOrderIdentifier());
144        if (ObjectUtils.isNotNull(po)) {
145            // 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
146            invoiceDocument.setAccountsPayablePurchasingDocumentLinkIdentifier(po.getAccountsPayablePurchasingDocumentLinkIdentifier());
147
148            //check to see if user is allowed to initiate doc based on PO sensitive data
149            if (!SpringContext.getBean(DocumentHelperService.class).getDocumentAuthorizer(invoiceDocument).isAuthorizedByTemplate(invoiceDocument, KRADConstants.KNS_NAMESPACE, KimConstants.PermissionTemplateNames.OPEN_DOCUMENT, GlobalVariables.getUserSession().getPrincipalId())) {
150                throw buildAuthorizationException("initiate document", invoiceDocument);
151            }
152        }
153
154        if (!SpringContext.getBean(InvoiceService.class).isPurchaseOrderValidForInvoiceDocumentCreation(invoiceDocument, po)) {
155            return mapping.findForward(OLEConstants.MAPPING_BASIC);
156        }
157
158        // perform duplicate check which will forward to a question prompt if one is found
159        ActionForward forward = performDuplicateInvoiceAndEncumberFiscalYearCheck(mapping, form, request, response, invoiceDocument);
160        if (forward != null) {
161            return forward;
162        }
163
164        // If we are here either there was no duplicate or there was a duplicate and the user hits continue, in either case we need
165        // to validate the business rules
166        SpringContext.getBean(InvoiceService.class).populateAndSaveInvoice(invoiceDocument);
167
168        // force calculation
169        prqsForm.setCalculated(false);
170
171        //TODO if better, move this to the action just before prqs goes into ATAX status
172        // force calculation for tax
173        prqsForm.setCalculatedTax(false);
174
175        // sort below the line
176        SpringContext.getBean(PurapService.class).sortBelowTheLine(invoiceDocument);
177
178        // update the counts on the form
179        prqsForm.updateItemCounts();
180
181        return mapping.findForward(OLEConstants.MAPPING_BASIC);
182    }
183
184
185    /**
186     * Clears the initial fields on the <code>InvoiceDocument</code> which should be accessible from the given form.
187     *
188     * @param mapping  An ActionMapping
189     * @param form     An ActionForm, which must be a InvoiceForm
190     * @param request  The HttpServletRequest
191     * @param response The HttpServletResponse
192     * @return An ActionForward
193     * @throws Exception
194     */
195    public ActionForward clearInitFields(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
196        LOG.debug("clearInitValues() method");
197        InvoiceForm prqsForm = (InvoiceForm) form;
198        InvoiceDocument invoiceDocument = (InvoiceDocument) prqsForm.getDocument();
199        invoiceDocument.clearInitFields();
200
201        return super.refresh(mapping, form, request, response);
202    }
203
204    /**
205     * This method runs two checks based on the user input on PRQS initiate screen: Encumber next fiscal year check and Duplicate
206     * payment request check. Encumber next fiscal year is checked first and will display a warning message to the user if it's the
207     * case. Duplicate payment request check calls <code>InvoiceService</code> to perform the duplicate payment request
208     * check. If one is found, a question is setup and control is forwarded to the question action method. Coming back from the
209     * question prompt the button that was clicked is checked and if 'no' was selected they are forward back to the page still in
210     * init mode.
211     *
212     * @param mapping         An ActionMapping
213     * @param form            An ActionForm
214     * @param request         The HttpServletRequest
215     * @param response        The HttpServletResponse
216     * @param invoiceDocument The InvoiceDocument
217     * @return An ActionForward
218     * @throws Exception
219     * @see org.kuali.ole.module.purap.document.service.InvoiceService
220     */
221    protected ActionForward performDuplicateInvoiceAndEncumberFiscalYearCheck(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, InvoiceDocument invoiceDocument) throws Exception {
222        ActionForward forward = null;
223        Object question = request.getParameter(OLEConstants.QUESTION_INST_ATTRIBUTE_NAME);
224        if (question == null) {
225            // perform encumber next fiscal year check and prompt warning message if needs
226            if (isEncumberNextFiscalYear(invoiceDocument)) {
227                String questionText = SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(PurapKeyConstants.WARNING_ENCUMBER_NEXT_FY);
228                return this.performQuestionWithoutInput(mapping, form, request, response, PRQSDocumentsStrings.ENCUMBER_NEXT_FISCAL_YEAR_QUESTION, questionText, OLEConstants.CONFIRMATION_QUESTION, OLEConstants.ROUTE_METHOD, "");
229            } else {
230                // perform duplicate payment request check
231                HashMap<String, String> duplicateMessages = SpringContext.getBean(InvoiceService.class).invoiceDuplicateMessages(invoiceDocument);
232                if (!duplicateMessages.isEmpty()) {
233                    return this.performQuestionWithoutInput(mapping, form, request, response, PRQSDocumentsStrings.DUPLICATE_INVOICE_QUESTION, duplicateMessages.get(PRQSDocumentsStrings.DUPLICATE_INVOICE_QUESTION), OLEConstants.CONFIRMATION_QUESTION, OLEConstants.ROUTE_METHOD, "");
234                }
235            }
236        } else {
237            Object buttonClicked = request.getParameter(OLEConstants.QUESTION_CLICKED_BUTTON);
238            // If the user replies 'Yes' to the encumber-next-year-question, proceed with duplicate payment check
239            if (PRQSDocumentsStrings.ENCUMBER_NEXT_FISCAL_YEAR_QUESTION.equals(question) && ConfirmationQuestion.YES.equals(buttonClicked)) {
240                HashMap<String, String> duplicateMessages = SpringContext.getBean(InvoiceService.class).invoiceDuplicateMessages(invoiceDocument);
241                if (!duplicateMessages.isEmpty()) {
242                    return this.performQuestionWithoutInput(mapping, form, request, response, PRQSDocumentsStrings.DUPLICATE_INVOICE_QUESTION, duplicateMessages.get(PRQSDocumentsStrings.DUPLICATE_INVOICE_QUESTION), OLEConstants.CONFIRMATION_QUESTION, OLEConstants.ROUTE_METHOD, "");
243                }
244            }
245            // If the user replies 'No' to either of the questions, redirect to the PRQS initiate page.
246            else if ((PRQSDocumentsStrings.ENCUMBER_NEXT_FISCAL_YEAR_QUESTION.equals(question) || PRQSDocumentsStrings.DUPLICATE_INVOICE_QUESTION.equals(question)) && ConfirmationQuestion.NO.equals(buttonClicked)) {
247                invoiceDocument.updateAndSaveAppDocStatus(InvoiceStatuses.APPDOC_INITIATE);
248                forward = mapping.findForward(OLEConstants.MAPPING_BASIC);
249            }
250        }
251
252        return forward;
253    }
254
255    /**
256     * Check if the current PRQS encumber next fiscal year from PO document.
257     *
258     * @param invoiceDocument
259     * @return
260     */
261    protected boolean isEncumberNextFiscalYear(InvoiceDocument invoiceDocument) {
262        Integer fiscalYear = SpringContext.getBean(UniversityDateService.class).getCurrentFiscalYear();
263        if (invoiceDocument.getPurchaseOrderDocument().getPostingYear().intValue() > fiscalYear) {
264            return true;
265        }
266        return false;
267    }
268
269    /**
270     * Puts a payment on hold, prompting for a reason beforehand. This stops further approvals or routing.
271     *
272     * @param mapping  An ActionMapping
273     * @param form     An ActionForm
274     * @param request  The HttpServletRequest
275     * @param response The HttpServletResponse
276     * @return An ActionForward
277     * @throws Exception
278     */
279    public ActionForward addHoldOnPayment(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
280        String operation = "Hold ";
281
282        PurQuestionCallback callback = new PurQuestionCallback() {
283            @Override
284            public AccountsPayableDocument doPostQuestion(AccountsPayableDocument document, String noteText) throws Exception {
285                document = SpringContext.getBean(InvoiceService.class).addHoldOnInvoice((InvoiceDocument) document, noteText);
286                return document;
287            }
288        };
289
290        return askQuestionWithInput(mapping, form, request, response, PRQSDocumentsStrings.HOLD_PRQS_QUESTION, PRQSDocumentsStrings.HOLD_NOTE_PREFIX, operation, PurapKeyConstants.PAYMENT_REQUEST_MESSAGE_HOLD_DOCUMENT, callback);
291    }
292
293    /**
294     * Removes a hold on the payment request.
295     *
296     * @param mapping  An ActionMapping
297     * @param form     An ActionForm
298     * @param request  The HttpServletRequest
299     * @param response The HttpServletResponse
300     * @return An ActionForward
301     * @throws Exception
302     */
303    public ActionForward removeHoldFromPayment(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
304        String operation = "Remove ";
305
306        PurQuestionCallback callback = new PurQuestionCallback() {
307            @Override
308            public AccountsPayableDocument doPostQuestion(AccountsPayableDocument document, String noteText) throws Exception {
309                document = SpringContext.getBean(InvoiceService.class).removeHoldOnInvoice((InvoiceDocument) document, noteText);
310                return document;
311            }
312        };
313
314        return askQuestionWithInput(mapping, form, request, response, PRQSDocumentsStrings.REMOVE_HOLD_PRQS_QUESTION, PRQSDocumentsStrings.REMOVE_HOLD_NOTE_PREFIX, operation, PurapKeyConstants.PAYMENT_REQUEST_MESSAGE_REMOVE_HOLD_DOCUMENT, callback);
315    }
316
317    /**
318     * This action requests a cancel on a prqs, prompting for a reason before hand. This stops further approvals or routing.
319     *
320     * @param mapping  An ActionMapping
321     * @param form     An ActionForm
322     * @param request  The HttpServletRequest
323     * @param response The HttpServletResponse
324     * @return An ActionForward
325     * @throws Exception
326     */
327    public ActionForward requestCancelOnPayment(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
328        String operation = "Cancel ";
329
330        PurQuestionCallback callback = new PurQuestionCallback() {
331            @Override
332            public AccountsPayableDocument doPostQuestion(AccountsPayableDocument document, String noteText) throws Exception {
333                SpringContext.getBean(InvoiceService.class).requestCancelOnInvoice((InvoiceDocument) document, noteText);
334                return document;
335            }
336        };
337
338        return askQuestionWithInput(mapping, form, request, response, PRQSDocumentsStrings.CANCEL_PRQS_QUESTION, PRQSDocumentsStrings.CANCEL_NOTE_PREFIX, operation, PurapKeyConstants.PAYMENT_REQUEST_MESSAGE_CANCEL_DOCUMENT, callback);
339    }
340
341    /**
342     * @see AccountsPayableActionBase#cancelPOActionCallbackMethod()
343     */
344//    @Override
345//    protected PurQuestionCallback cancelPOActionCallbackMethod() {
346//
347//        return new PurQuestionCallback() {
348//            public AccountsPayableDocument doPostQuestion(AccountsPayableDocument document, String noteText) throws Exception {
349//                InvoiceDocument prqsDocument = (InvoiceDocument) document;
350//                prqsDocument.setReopenPurchaseOrderIndicator(true);
351//                return prqsDocument;
352//            }
353//        };
354//    }
355
356    /**
357     * Removes a request for cancel on a payment request.
358     *
359     * @param mapping  An ActionMapping
360     * @param form     An ActionForm
361     * @param request  The HttpServletRequest
362     * @param response The HttpServletResponse
363     * @return An ActionForward
364     * @throws Exception
365     */
366    public ActionForward removeCancelRequestFromPayment(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
367        String operation = "Cancel ";
368
369        PurQuestionCallback callback = new PurQuestionCallback() {
370            @Override
371            public AccountsPayableDocument doPostQuestion(AccountsPayableDocument document, String noteText) throws Exception {
372                SpringContext.getBean(InvoiceService.class).removeRequestCancelOnInvoice((InvoiceDocument) document, noteText);
373                return document;
374            }
375        };
376
377        return askQuestionWithInput(mapping, form, request, response, PRQSDocumentsStrings.REMOVE_CANCEL_PRQS_QUESTION, PRQSDocumentsStrings.REMOVE_CANCEL_NOTE_PREFIX, operation, PurapKeyConstants.PAYMENT_REQUEST_MESSAGE_REMOVE_CANCEL_DOCUMENT, callback);
378    }
379
380    /**
381     * Calls a service method to calculate for a payment request document.
382     *
383     * @param apDoc The AccountsPayableDocument
384     */
385    @Override
386    protected void customCalculate(PurchasingAccountsPayableDocument apDoc) {
387        InvoiceDocument prqsDoc = (InvoiceDocument) apDoc;
388
389        // set amounts on any empty
390        prqsDoc.updateExtendedPriceOnItems();
391
392        // calculation just for the tax area, only at tax review stage
393        // by now, the general calculation shall have been done.
394        if (StringUtils.equals(prqsDoc.getApplicationDocumentStatus(), InvoiceStatuses.APPDOC_AWAITING_TAX_REVIEW)) {
395            SpringContext.getBean(InvoiceService.class).calculateTaxArea(prqsDoc);
396            return;
397        }
398
399        // notice we're ignoring whether the boolean, because these are just warnings they shouldn't halt anything
400        //Calculate Payment request before rules since the rule check totalAmount.
401        SpringContext.getBean(InvoiceService.class).calculateInvoice(prqsDoc, true);
402        SpringContext.getBean(KualiRuleService.class).applyRules(new AttributedCalculateAccountsPayableEvent(prqsDoc));
403    }
404
405    /**
406     * @see AccountsPayableActionBase#getActionName()
407     */
408    @Override
409    public String getActionName() {
410        return PurapConstants.INVOICE_ACTION_NAME;
411    }
412
413    public ActionForward useAlternateVendor(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
414        InvoiceForm prqsForm = (InvoiceForm) form;
415        InvoiceDocument document = (InvoiceDocument) prqsForm.getDocument();
416
417        SpringContext.getBean(InvoiceService.class).changeVendor(
418                document, document.getAlternateVendorHeaderGeneratedIdentifier(), document.getAlternateVendorDetailAssignedIdentifier());
419
420        return mapping.findForward(OLEConstants.MAPPING_BASIC);
421    }
422
423    public ActionForward useOriginalVendor(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
424        InvoiceForm prqsForm = (InvoiceForm) form;
425        InvoiceDocument document = (InvoiceDocument) prqsForm.getDocument();
426
427        SpringContext.getBean(InvoiceService.class).changeVendor(
428                document, document.getOriginalVendorHeaderGeneratedIdentifier(), document.getOriginalVendorDetailAssignedIdentifier());
429
430        return mapping.findForward(OLEConstants.MAPPING_BASIC);
431    }
432
433    @Override
434    public ActionForward route(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
435        InvoiceDocument prqs = ((InvoiceForm) form).getInvoiceDocument();
436        SpringContext.getBean(PurapService.class).prorateForTradeInAndFullOrderDiscount(prqs);
437        SpringContext.getBean(PurapAccountingService.class).updateAccountAmounts(prqs);
438        if (prqs.isClosePurchaseOrderIndicator()) {
439            PurchaseOrderDocument po = prqs.getPurchaseOrderDocument();
440            if (po.canClosePOForTradeIn()) {
441                return super.route(mapping, form, request, response);
442            } else {
443                return mapping.findForward(OLEConstants.MAPPING_BASIC);
444            }
445        } else {
446            return super.route(mapping, form, request, response);
447        }
448    }
449
450    /**
451     * Overrides to invoke the updateAccountAmounts so that the account percentage will be
452     * correctly updated before validation for account percent is called.
453     *
454     * @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)
455     */
456    @Override
457    public ActionForward approve(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
458        InvoiceDocument prqs = ((InvoiceForm) form).getInvoiceDocument();
459
460        SpringContext.getBean(PurapService.class).prorateForTradeInAndFullOrderDiscount(prqs);
461        // if tax is required but not yet calculated, return and prompt user to calculate
462        if (requiresCalculateTax((InvoiceForm) form)) {
463            GlobalVariables.getMessageMap().putError(OLEConstants.DOCUMENT_ERRORS, PurapKeyConstants.ERROR_APPROVE_REQUIRES_CALCULATE);
464            return mapping.findForward(OLEConstants.MAPPING_BASIC);
465        }
466
467        // enforce calculating tax again upon approval, just in case user changes tax data without calculation
468        // other wise there will be a loophole, because the taxCalculated indicator is already set upon first calculation
469        // and thus system wouldn't know it's not re-calculated after tax data are changed
470        if (SpringContext.getBean(KualiRuleService.class).applyRules(new AttributedPreCalculateAccountsPayableEvent(prqs))) {
471            // pre-calculation rules succeed, calculate tax again and go ahead with approval
472            customCalculate(prqs);
473            SpringContext.getBean(PurapAccountingService.class).updateAccountAmounts(prqs);
474            return super.approve(mapping, form, request, response);
475        } else {
476            // pre-calculation rules fail, go back to same page with error messages
477            return mapping.findForward(OLEConstants.MAPPING_BASIC);
478        }
479    }
480
481    /**
482     * Checks if tax calculation is required.
483     * Currently it is required when prqs is awaiting for tax approval and tax has not already been calculated.
484     *
485     * @param invoiceForm A Form, which must inherit from <code>AccountsPayableFormBase</code>
486     * @return true if calculation is required, false otherwise
487     */
488    protected boolean requiresCalculateTax(InvoiceForm invoiceForm) {
489        InvoiceDocument prqs = (InvoiceDocument) invoiceForm.getDocument();
490        boolean requiresCalculateTax = StringUtils.equals(prqs.getApplicationDocumentStatus(), InvoiceStatuses.APPDOC_AWAITING_TAX_REVIEW) && !invoiceForm.isCalculatedTax();
491        return requiresCalculateTax;
492    }
493
494    public ActionForward changeUseTaxIndicator(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
495        PurchasingAccountsPayableDocument document = (PurchasingAccountsPayableDocument) ((PurchasingAccountsPayableFormBase) form).getDocument();
496
497        //clear/recalculate tax and recreate GL entries
498        SpringContext.getBean(PurapService.class).updateUseTaxIndicator(document, !document.isUseTaxIndicator());
499        SpringContext.getBean(PurapService.class).calculateTax(document);
500
501        //TODO: add recalculate GL entries hook here
502
503        return mapping.findForward(OLEConstants.MAPPING_BASIC);
504    }
505
506    /**
507     * Calls service to clear tax info.
508     */
509    public ActionForward clearTaxInfo(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
510        InvoiceForm prForm = (InvoiceForm) form;
511        InvoiceDocument document = (InvoiceDocument) prForm.getDocument();
512
513        InvoiceService taxService = SpringContext.getBean(InvoiceService.class);
514
515        /* call service to clear previous lines */
516        taxService.clearTax(document);
517
518        return mapping.findForward(OLEConstants.MAPPING_BASIC);
519    }
520
521    //MSU Contribution OLEMI-8558 DTT-3765 OLECNTRB-963
522    @Override
523    public ActionForward cancel(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
524        InvoiceForm prqsForm = (InvoiceForm) form;
525
526        InvoiceDocument prqsDocument = (InvoiceDocument) prqsForm.getDocument();
527
528        ActionForward forward = mapping.findForward(RiceConstants.MAPPING_BASIC);
529        if (prqsDocument.getPurchaseOrderDocument().isPendingActionIndicator()) {
530            GlobalVariables.getMessageMap().putError(
531                    OLEPropertyConstants.DOCUMENT + "." + OLEPropertyConstants.DOCUMENT_NUMBER,
532                    PurapKeyConstants.ERROR_PAYMENT_REQUEST_CANNOT_BE_CANCELLED);
533        } else {
534            forward = super.cancel(mapping, form, request, response);
535        }
536
537        return forward;
538    }
539}