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 }