001 /*
002 * Copyright 2011 The Kuali Foundation.
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.kuali.kfs.module.purap.document.web.struts;
017
018 import java.util.HashMap;
019 import java.util.List;
020
021 import javax.servlet.http.HttpServletRequest;
022 import javax.servlet.http.HttpServletResponse;
023
024 import org.apache.commons.lang.StringUtils;
025 import org.apache.struts.action.ActionForm;
026 import org.apache.struts.action.ActionForward;
027 import org.apache.struts.action.ActionMapping;
028 import org.kuali.kfs.module.purap.PurapConstants;
029 import org.kuali.kfs.module.purap.PurapKeyConstants;
030 import org.kuali.kfs.module.purap.PurapPropertyConstants;
031 import org.kuali.kfs.module.purap.PurapConstants.PREQDocumentsStrings;
032 import org.kuali.kfs.module.purap.PurapConstants.PaymentRequestStatuses;
033 import org.kuali.kfs.module.purap.document.AccountsPayableDocument;
034 import org.kuali.kfs.module.purap.document.PaymentRequestDocument;
035 import org.kuali.kfs.module.purap.document.PurchaseOrderDocument;
036 import org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument;
037 import org.kuali.kfs.module.purap.document.service.PaymentRequestService;
038 import org.kuali.kfs.module.purap.document.service.PurapService;
039 import org.kuali.kfs.module.purap.document.service.PurchaseOrderService;
040 import org.kuali.kfs.module.purap.document.validation.event.AttributedCalculateAccountsPayableEvent;
041 import org.kuali.kfs.module.purap.document.validation.event.AttributedContinuePurapEvent;
042 import org.kuali.kfs.module.purap.document.validation.event.AttributedPreCalculateAccountsPayableEvent;
043 import org.kuali.kfs.module.purap.service.PurapAccountingService;
044 import org.kuali.kfs.module.purap.util.PurQuestionCallback;
045 import org.kuali.kfs.sys.KFSConstants;
046 import org.kuali.kfs.sys.KFSKeyConstants;
047 import org.kuali.kfs.sys.KFSPropertyConstants;
048 import org.kuali.kfs.module.purap.PurapKeyConstants;
049 import org.kuali.kfs.sys.context.SpringContext;
050 import org.kuali.kfs.sys.service.UniversityDateService;
051 import org.kuali.rice.kew.exception.WorkflowException;
052 import org.kuali.rice.kim.util.KimConstants;
053 import org.kuali.rice.kns.question.ConfirmationQuestion;
054 import org.kuali.rice.kns.service.DocumentHelperService;
055 import org.kuali.rice.kns.service.KualiConfigurationService;
056 import org.kuali.rice.kns.service.KualiRuleService;
057 import org.kuali.rice.kns.util.GlobalVariables;
058 import org.kuali.rice.kns.util.KNSConstants;
059 import org.kuali.rice.kns.util.ObjectUtils;
060 import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase;
061
062 /**
063 * Struts Action for Payment Request document.
064 */
065 public class PaymentRequestAction extends AccountsPayableActionBase {
066 static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PaymentRequestAction.class);
067
068 /**
069 * Do initialization for a new payment request.
070 *
071 * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#createDocument(org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase)
072 */
073 @Override
074 protected void createDocument(KualiDocumentFormBase kualiDocumentFormBase) throws WorkflowException {
075 super.createDocument(kualiDocumentFormBase);
076 ((PaymentRequestDocument) kualiDocumentFormBase.getDocument()).initiateDocument();
077 }
078
079 /**
080 * @see org.kuali.rice.kns.web.struts.action.KualiAction#refresh(org.apache.struts.action.ActionMapping,
081 * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
082 */
083 @Override
084 public ActionForward refresh(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
085 PaymentRequestForm preqForm = (PaymentRequestForm) form;
086 PaymentRequestDocument document = (PaymentRequestDocument) preqForm.getDocument();
087
088 return super.refresh(mapping, form, request, response);
089 }
090
091 /**
092 * Executes the continue action on a payment request. Populates and initializes the rest of the payment request besides what was
093 * shown on the init screen.
094 *
095 * @param mapping An ActionMapping
096 * @param form An ActionForm
097 * @param request The HttpServletRequest
098 * @param response The HttpServletResponse
099 * @throws Exception
100 * @return An ActionForward
101 */
102 public ActionForward continuePREQ(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
103 LOG.debug("continuePREQ() method");
104 PaymentRequestForm preqForm = (PaymentRequestForm) form;
105 PaymentRequestDocument paymentRequestDocument = (PaymentRequestDocument) preqForm.getDocument();
106
107 boolean poNotNull = true;
108
109 boolean rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new AttributedContinuePurapEvent(paymentRequestDocument));
110 if (!rulePassed){
111 return mapping.findForward(KFSConstants.MAPPING_BASIC);
112 }
113
114 GlobalVariables.getMessageMap().clearErrorPath();
115 GlobalVariables.getMessageMap().addToErrorPath(KFSPropertyConstants.DOCUMENT);
116
117 //check for a po id
118 if (ObjectUtils.isNull(paymentRequestDocument.getPurchaseOrderIdentifier())) {
119 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.PURCHASE_ORDER_IDENTIFIER, KFSKeyConstants.ERROR_REQUIRED, PREQDocumentsStrings.PURCHASE_ORDER_ID);
120 poNotNull = false;
121 }
122
123 if (ObjectUtils.isNull(paymentRequestDocument.getInvoiceDate())) {
124 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.INVOICE_DATE, KFSKeyConstants.ERROR_REQUIRED, PREQDocumentsStrings.INVOICE_DATE);
125 poNotNull = false;
126 }
127
128 if (ObjectUtils.isNull(paymentRequestDocument.getInvoiceNumber())) {
129 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.INVOICE_NUMBER, KFSKeyConstants.ERROR_REQUIRED, PREQDocumentsStrings.INVOICE_NUMBER);
130 poNotNull = false;
131 }
132 paymentRequestDocument.setInvoiceNumber(paymentRequestDocument.getInvoiceNumber().toUpperCase());
133
134 if (ObjectUtils.isNull(paymentRequestDocument.getVendorInvoiceAmount())) {
135 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.VENDOR_INVOICE_AMOUNT, KFSKeyConstants.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(KFSConstants.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, KNSConstants.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 {
158 return mapping.findForward(KFSConstants.MAPPING_BASIC);
159 }
160
161 // perform duplicate check which will forward to a question prompt if one is found
162 ActionForward forward = performDuplicatePaymentRequestAndEncumberFiscalYearCheck(mapping, form, request, response, paymentRequestDocument);
163 if (forward != null) {
164 return forward;
165 }
166
167 // If we are here either there was no duplicate or there was a duplicate and the user hits continue, in either case we need
168 // to validate the business rules
169 SpringContext.getBean(PaymentRequestService.class).populateAndSavePaymentRequest(paymentRequestDocument);
170
171 // force calculation
172 preqForm.setCalculated(false);
173
174 //TODO if better, move this to the action just before preq goes into ATAX status
175 // force calculation for tax
176 preqForm.setCalculatedTax(false);
177
178 // sort below the line
179 SpringContext.getBean(PurapService.class).sortBelowTheLine(paymentRequestDocument);
180
181 // update the counts on the form
182 preqForm.updateItemCounts();
183
184 return mapping.findForward(KFSConstants.MAPPING_BASIC);
185 }
186
187
188 /**
189 * Clears the initial fields on the <code>PaymentRequestDocument</code> which should be accessible from the given form.
190 *
191 * @param mapping An ActionMapping
192 * @param form An ActionForm, which must be a PaymentRequestForm
193 * @param request The HttpServletRequest
194 * @param response The HttpServletResponse
195 * @throws Exception
196 * @return An ActionForward
197 */
198 public ActionForward clearInitFields(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
199 LOG.debug("clearInitValues() method");
200 PaymentRequestForm preqForm = (PaymentRequestForm) form;
201 PaymentRequestDocument paymentRequestDocument = (PaymentRequestDocument) preqForm.getDocument();
202 paymentRequestDocument.clearInitFields();
203
204 return super.refresh(mapping, form, request, response);
205 }
206
207 /**
208 * This method runs two checks based on the user input on PREQ initiate screen: Encumber next fiscal year check and Duplicate
209 * payment request check. Encumber next fiscal year is checked first and will display a warning message to the user if it's the
210 * case. Duplicate payment request check calls <code>PaymentRequestService</code> to perform the duplicate payment request
211 * check. If one is found, a question is setup and control is forwarded to the question action method. Coming back from the
212 * question prompt the button that was clicked is checked and if 'no' was selected they are forward back to the page still in
213 * init mode.
214 *
215 * @param mapping An ActionMapping
216 * @param form An ActionForm
217 * @param request The HttpServletRequest
218 * @param response The HttpServletResponse
219 * @param paymentRequestDocument The PaymentRequestDocument
220 * @throws Exception
221 * @return An ActionForward
222 * @see org.kuali.kfs.module.purap.document.service.PaymentRequestService
223 */
224 protected ActionForward performDuplicatePaymentRequestAndEncumberFiscalYearCheck(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, PaymentRequestDocument paymentRequestDocument) throws Exception {
225 ActionForward forward = null;
226 Object question = request.getParameter(KFSConstants.QUESTION_INST_ATTRIBUTE_NAME);
227 if (question == null) {
228 // perform encumber next fiscal year check and prompt warning message if needs
229 if (isEncumberNextFiscalYear(paymentRequestDocument)) {
230 String questionText = SpringContext.getBean(KualiConfigurationService.class).getPropertyString(PurapKeyConstants.WARNING_ENCUMBER_NEXT_FY);
231 return this.performQuestionWithoutInput(mapping, form, request, response, PREQDocumentsStrings.ENCUMBER_NEXT_FISCAL_YEAR_QUESTION, questionText, KFSConstants.CONFIRMATION_QUESTION, KFSConstants.ROUTE_METHOD, "");
232 }
233 else {
234 // perform duplicate payment request check
235 HashMap<String, String> duplicateMessages = SpringContext.getBean(PaymentRequestService.class).paymentRequestDuplicateMessages(paymentRequestDocument);
236 if (!duplicateMessages.isEmpty()) {
237 return this.performQuestionWithoutInput(mapping, form, request, response, PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION, duplicateMessages.get(PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION), KFSConstants.CONFIRMATION_QUESTION, KFSConstants.ROUTE_METHOD, "");
238 }
239 }
240 }
241 else {
242 Object buttonClicked = request.getParameter(KFSConstants.QUESTION_CLICKED_BUTTON);
243 // If the user replies 'Yes' to the encumber-next-year-question, proceed with duplicate payment check
244 if (PurapConstants.PREQDocumentsStrings.ENCUMBER_NEXT_FISCAL_YEAR_QUESTION.equals(question) && ConfirmationQuestion.YES.equals(buttonClicked)) {
245 HashMap<String, String> duplicateMessages = SpringContext.getBean(PaymentRequestService.class).paymentRequestDuplicateMessages(paymentRequestDocument);
246 if (!duplicateMessages.isEmpty()) {
247 return this.performQuestionWithoutInput(mapping, form, request, response, PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION, duplicateMessages.get(PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION), KFSConstants.CONFIRMATION_QUESTION, KFSConstants.ROUTE_METHOD, "");
248 }
249 }
250 // If the user replies 'No' to either of the questions, redirect to the PREQ initiate page.
251 else if ((PurapConstants.PREQDocumentsStrings.ENCUMBER_NEXT_FISCAL_YEAR_QUESTION.equals(question) || PurapConstants.PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION.equals(question)) && ConfirmationQuestion.NO.equals(buttonClicked)) {
252 paymentRequestDocument.setStatusCode(PurapConstants.PaymentRequestStatuses.INITIATE);
253 forward = mapping.findForward(KFSConstants.MAPPING_BASIC);
254 }
255
256 }
257
258 return forward;
259 }
260
261 /**
262 * Check if the current PREQ encumber next fiscal year from PO document.
263 *
264 * @param paymentRequestDocument
265 * @return
266 */
267 protected boolean isEncumberNextFiscalYear(PaymentRequestDocument paymentRequestDocument) {
268 Integer fiscalYear = SpringContext.getBean(UniversityDateService.class).getCurrentFiscalYear();
269 if (paymentRequestDocument.getPurchaseOrderDocument().getPostingYear().intValue() > fiscalYear) {
270 return true;
271 }
272 return false;
273 }
274
275 /**
276 * Puts a payment on hold, prompting for a reason beforehand. This stops further approvals or routing.
277 *
278 * @param mapping An ActionMapping
279 * @param form An ActionForm
280 * @param request The HttpServletRequest
281 * @param response The HttpServletResponse
282 * @throws Exception
283 * @return An ActionForward
284 */
285 public ActionForward addHoldOnPayment(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
286 String operation = "Hold ";
287
288 PurQuestionCallback callback = new PurQuestionCallback() {
289 public AccountsPayableDocument doPostQuestion(AccountsPayableDocument document, String noteText) throws Exception {
290 document = SpringContext.getBean(PaymentRequestService.class).addHoldOnPaymentRequest((PaymentRequestDocument) document, noteText);
291 return document;
292 }
293 };
294
295 return askQuestionWithInput(mapping, form, request, response, PREQDocumentsStrings.HOLD_PREQ_QUESTION, PREQDocumentsStrings.HOLD_NOTE_PREFIX, operation, PurapKeyConstants.PAYMENT_REQUEST_MESSAGE_HOLD_DOCUMENT, callback);
296 }
297
298 /**
299 * Removes a hold on the payment request.
300 *
301 * @param mapping An ActionMapping
302 * @param form An ActionForm
303 * @param request The HttpServletRequest
304 * @param response The HttpServletResponse
305 * @throws Exception
306 * @return An ActionForward
307 */
308 public ActionForward removeHoldFromPayment(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
309 String operation = "Remove ";
310
311 PurQuestionCallback callback = new PurQuestionCallback() {
312 public AccountsPayableDocument doPostQuestion(AccountsPayableDocument document, String noteText) throws Exception {
313 document = SpringContext.getBean(PaymentRequestService.class).removeHoldOnPaymentRequest((PaymentRequestDocument) document, noteText);
314 return document;
315 }
316 };
317
318 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);
319 }
320
321 /**
322 * This action requests a cancel on a preq, prompting for a reason before hand. This stops further approvals or routing.
323 *
324 * @param mapping An ActionMapping
325 * @param form An ActionForm
326 * @param request The HttpServletRequest
327 * @param response The HttpServletResponse
328 * @throws Exception
329 * @return An ActionForward
330 */
331 public ActionForward requestCancelOnPayment(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
332 String operation = "Cancel ";
333
334 PurQuestionCallback callback = new PurQuestionCallback() {
335 public AccountsPayableDocument doPostQuestion(AccountsPayableDocument document, String noteText) throws Exception {
336 SpringContext.getBean(PaymentRequestService.class).requestCancelOnPaymentRequest((PaymentRequestDocument) document, noteText);
337 return document;
338 }
339 };
340
341 return askQuestionWithInput(mapping, form, request, response, PREQDocumentsStrings.CANCEL_PREQ_QUESTION, PREQDocumentsStrings.CANCEL_NOTE_PREFIX, operation, PurapKeyConstants.PAYMENT_REQUEST_MESSAGE_CANCEL_DOCUMENT, callback);
342 }
343
344 /**
345 * @see org.kuali.kfs.module.purap.document.web.struts.AccountsPayableActionBase#cancelPOActionCallbackMethod()
346 */
347 // @Override
348 // protected PurQuestionCallback cancelPOActionCallbackMethod() {
349 //
350 // return new PurQuestionCallback() {
351 // public AccountsPayableDocument doPostQuestion(AccountsPayableDocument document, String noteText) throws Exception {
352 // PaymentRequestDocument preqDocument = (PaymentRequestDocument) document;
353 // preqDocument.setReopenPurchaseOrderIndicator(true);
354 // return preqDocument;
355 // }
356 // };
357 // }
358
359 /**
360 * Removes a request for cancel on a payment request.
361 *
362 * @param mapping An ActionMapping
363 * @param form An ActionForm
364 * @param request The HttpServletRequest
365 * @param response The HttpServletResponse
366 * @throws Exception
367 * @return An ActionForward
368 */
369 public ActionForward removeCancelRequestFromPayment(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
370 String operation = "Cancel ";
371
372 PurQuestionCallback callback = new PurQuestionCallback() {
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 (preqDoc.getStatusCode().equals(PaymentRequestStatuses.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.kfs.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(KFSConstants.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(KFSConstants.MAPPING_BASIC);
433 }
434
435 public ActionForward route (ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
436 PaymentRequestDocument preq = ((PaymentRequestForm)form).getPaymentRequestDocument();
437 SpringContext.getBean(PurapService.class).prorateForTradeInAndFullOrderDiscount(preq);
438 SpringContext.getBean(PurapAccountingService.class).updateAccountAmounts(preq);
439 if (preq.isClosePurchaseOrderIndicator()) {
440 PurchaseOrderDocument po = preq.getPurchaseOrderDocument();
441 if (po.canClosePOForTradeIn()) {
442 return super.route(mapping, form, request, response);
443 }
444 else {
445 return mapping.findForward(KFSConstants.MAPPING_BASIC);
446 }
447 }
448 else {
449 return super.route(mapping, form, request, response);
450 }
451 }
452
453 /**
454 * Overrides to invoke the updateAccountAmounts so that the account percentage will be
455 * correctly updated before validation for account percent is called.
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 public ActionForward approve(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
459 PaymentRequestDocument preq = ((PaymentRequestForm)form).getPaymentRequestDocument();
460
461 SpringContext.getBean(PurapService.class).prorateForTradeInAndFullOrderDiscount(preq);
462 // if tax is required but not yet calculated, return and prompt user to calculate
463 if (requiresCalculateTax((PaymentRequestForm)form)) {
464 GlobalVariables.getMessageMap().putError(KFSConstants.DOCUMENT_ERRORS, PurapKeyConstants.ERROR_APPROVE_REQUIRES_CALCULATE);
465 return mapping.findForward(KFSConstants.MAPPING_BASIC);
466 }
467
468 // enforce calculating tax again upon approval, just in case user changes tax data without calculation
469 // other wise there will be a loophole, because the taxCalculated indicator is already set upon first calculation
470 // and thus system wouldn't know it's not re-calculated after tax data are changed
471 if (SpringContext.getBean(KualiRuleService.class).applyRules(new AttributedPreCalculateAccountsPayableEvent(preq))) {
472 // pre-calculation rules succeed, calculate tax again and go ahead with approval
473 customCalculate(preq);
474 SpringContext.getBean(PurapAccountingService.class).updateAccountAmounts(preq);
475 return super.approve(mapping, form, request, response);
476 }
477 else {
478 // pre-calculation rules fail, go back to same page with error messages
479 return mapping.findForward(KFSConstants.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.getStatusCode(), PaymentRequestStatuses.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(KFSConstants.MAPPING_BASIC);
506 }
507
508 }