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.apache.struts.upload.FormFile; 023import org.kuali.ole.module.purap.PurapConstants; 024import org.kuali.ole.module.purap.PurapPropertyConstants; 025import org.kuali.ole.module.purap.businessobject.PurApAccountingLine; 026import org.kuali.ole.module.purap.businessobject.PurApAccountingLineParser; 027import org.kuali.ole.module.purap.businessobject.PurApItem; 028import org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocument; 029import org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocumentBase; 030import org.kuali.ole.module.purap.document.service.PurapService; 031import org.kuali.ole.module.purap.service.PurapAccountingService; 032import org.kuali.ole.sys.OLEConstants; 033import org.kuali.ole.sys.OLEPropertyConstants; 034import org.kuali.ole.sys.businessobject.AccountingLine; 035import org.kuali.ole.sys.businessobject.SourceAccountingLine; 036import org.kuali.ole.sys.context.SpringContext; 037import org.kuali.ole.sys.document.validation.event.AddAccountingLineEvent; 038import org.kuali.ole.sys.exception.AccountingLineParserException; 039import org.kuali.ole.sys.web.struts.KualiAccountingDocumentActionBase; 040import org.kuali.ole.sys.web.struts.KualiAccountingDocumentFormBase; 041import org.kuali.rice.core.api.util.RiceConstants; 042import org.kuali.rice.kew.api.WorkflowDocument; 043import org.kuali.rice.kew.api.exception.WorkflowException; 044import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase; 045import org.kuali.rice.kns.web.struts.form.KualiForm; 046import org.kuali.rice.krad.service.DocumentService; 047import org.kuali.rice.krad.service.KualiRuleService; 048import org.kuali.rice.krad.service.PersistenceService; 049import org.kuali.rice.krad.util.GlobalVariables; 050import org.kuali.rice.krad.util.ObjectUtils; 051 052import javax.servlet.http.HttpServletRequest; 053import javax.servlet.http.HttpServletResponse; 054import java.io.FileNotFoundException; 055import java.io.IOException; 056import java.math.BigDecimal; 057import java.util.HashMap; 058import java.util.Iterator; 059import java.util.List; 060import java.util.Map; 061import java.util.Map.Entry; 062 063/** 064 * Struts Action for Purchasing and Accounts Payable documents 065 */ 066public class PurchasingAccountsPayableActionBase extends KualiAccountingDocumentActionBase { 067 068 /** 069 * @see org.kuali.rice.kns.web.struts.action.KualiTransactionalDocumentActionBase#copy(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) 070 */ 071 @Override 072 public ActionForward copy(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 073 ActionForward actionForward = super.copy(mapping, form, request, response); 074 075 076 KualiDocumentFormBase kualiDocumentFormBase = (KualiDocumentFormBase) form; 077 PurchasingAccountsPayableDocument purapDocument = (PurchasingAccountsPayableDocument) kualiDocumentFormBase.getDocument(); 078 079 //refresh accounts in each item.... 080 List<PurApItem> items = purapDocument.getItems(); 081 082 for (PurApItem item : items) { 083 item.getNewSourceLine().setAccountLinePercent(new BigDecimal(0)); 084 //set default sequence number. 085 for (PurApAccountingLine account : item.getSourceAccountingLines()) { 086 account.setSequenceNumber(0); 087 } 088 } 089 090 return actionForward; 091 } 092 093 /** 094 * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#loadDocument(org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase) 095 */ 096 @Override 097 protected void loadDocument(KualiDocumentFormBase kualiDocumentFormBase) throws WorkflowException { 098 super.loadDocument(kualiDocumentFormBase); 099 PurchasingAccountsPayableFormBase purapForm = (PurchasingAccountsPayableFormBase) kualiDocumentFormBase; 100 PurchasingAccountsPayableDocument document = (PurchasingAccountsPayableDocument) purapForm.getDocument(); 101 102 // refresh the account summary (note this also updates the account amounts) 103 purapForm.refreshAccountSummmary(); 104 105 for (org.kuali.rice.krad.bo.Note note : (java.util.List<org.kuali.rice.krad.bo.Note>) document.getNotes()) { 106 note.refreshReferenceObject("attachment"); 107 } 108 109 // sort the below the line 110 SpringContext.getBean(PurapService.class).sortBelowTheLine(document); 111 112 updateBaseline(document, (PurchasingAccountsPayableFormBase) kualiDocumentFormBase); 113 } 114 115 /** 116 * Updates the baseline accounts on form and doc. 117 * 118 * @param document A descendant of PurchasingAccountsPayableDocument 119 */ 120 protected <T extends PurchasingAccountsPayableDocument, V extends KualiAccountingDocumentFormBase> void updateBaseline(T document, V form) { 121 // clear out the old lines first 122 for (PurApItem item : document.getItems()) { 123 // clear out the old lines first 124 item.getBaselineSourceAccountingLines().clear(); 125 126 for (PurApAccountingLine sourceAccount : item.getSourceAccountingLines()) { 127 // JHK: KFSMI-287 - removed deep copy since this object will be thrown away after the page renders, we just need a 128 // different path to have them stored on the form 129 // ESPECIALLY since PURAP does not allow lines to be reverted (see calls to setRevertible) 130 item.getBaselineSourceAccountingLines().add(sourceAccount); 131 } 132 } 133 } 134 135 /** 136 * Invokes a service method to refresh the account summary. 137 * 138 * @param mapping An ActionMapping 139 * @param form An ActionForm 140 * @param request The HttpServletRequest 141 * @param response The HttpServletResponse 142 * @return An ActionForward 143 * @throws Exception 144 */ 145 public ActionForward refreshAccountSummary(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 146 PurchasingAccountsPayableFormBase purapForm = (PurchasingAccountsPayableFormBase) form; 147 PurchasingAccountsPayableDocument document = (PurchasingAccountsPayableDocument) purapForm.getDocument(); 148 SpringContext.getBean(PurapAccountingService.class).updateAccountAmounts(document); 149 purapForm.refreshAccountSummmary(); 150 return mapping.findForward(OLEConstants.MAPPING_BASIC); 151 } 152 153 /** 154 * @see org.kuali.ole.sys.web.struts.KualiAccountingDocumentActionBase#uploadAccountingLines(boolean, org.apache.struts.action.ActionForm) 155 */ 156 @Override 157 protected void uploadAccountingLines(boolean isSource, ActionForm form) throws FileNotFoundException, IOException { 158 PurchasingAccountsPayableFormBase purapForm = (PurchasingAccountsPayableFormBase) form; 159 PurchasingAccountsPayableDocumentBase purapDocument = (PurchasingAccountsPayableDocumentBase) purapForm.getFinancialDocument(); 160 PurApAccountingLineParser accountingLineParser = (PurApAccountingLineParser) purapDocument.getAccountingLineParser(); 161 List importedLines = null; 162 String errorPathPrefix = PurapConstants.ACCOUNT_DISTRIBUTION_ERROR_KEY; 163 //String errorPathPrefix = "accountDistributionnewSourceLine"; 164 165 // import the lines 166 try { 167 FormFile sourceFile = purapForm.getSourceFile(); 168 checkUploadFile(sourceFile); 169 GlobalVariables.getMessageMap().clearErrorPath(); 170 GlobalVariables.getMessageMap().addToErrorPath(errorPathPrefix); 171 importedLines = accountingLineParser.importSourceAccountingLines(sourceFile.getFileName(), sourceFile.getInputStream(), purapDocument); 172 GlobalVariables.getMessageMap().removeFromErrorPath(errorPathPrefix); 173 } catch (AccountingLineParserException e) { 174 GlobalVariables.getMessageMap().putError(errorPathPrefix, e.getErrorKey(), e.getErrorParameters()); 175 } 176 177 // add to list those lines successfully imported 178 if (importedLines != null) { 179 for (Iterator iter = importedLines.iterator(); iter.hasNext(); ) { 180 PurApAccountingLine importedLine = (PurApAccountingLine) iter.next(); 181 //boolean rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new AddAccountingLineEvent(errorPathPrefix, purapForm.getDocument(), (AccountingLine) importedLine)); 182 //if (rulePassed) { 183 // add accountingLine 184 SpringContext.getBean(PersistenceService.class).retrieveNonKeyFields(importedLine); 185 ((PurchasingFormBase) purapForm).addAccountDistributionsourceAccountingLine(importedLine); 186 //} 187 } 188 } 189 } 190 191 /** 192 * @see org.kuali.ole.sys.web.struts.KualiAccountingDocumentActionBase#insertSourceLine(org.apache.struts.action.ActionMapping, 193 * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) 194 */ 195 @Override 196 public ActionForward insertSourceLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 197 // It would be preferable to find a way to genericize the KualiAccountingDocument methods but this will work for now 198 PurchasingAccountsPayableFormBase purapForm = (PurchasingAccountsPayableFormBase) form; 199 200 // index of item selected 201 int itemIndex = getSelectedLine(request); 202 PurApItem item = null; 203 204 // if custom processing of an accounting line is not done then insert a line generically. 205 if (processCustomInsertAccountingLine(purapForm, request) == false) { 206 String errorPrefix = null; 207 PurApAccountingLine line = null; 208 boolean rulePassed = false; 209 if (itemIndex >= 0) { 210 item = (PurApItem) ((PurchasingAccountsPayableDocument) purapForm.getDocument()).getItem((itemIndex)); 211 line = (PurApAccountingLine) ObjectUtils.deepCopy(item.getNewSourceLine()); 212 //SpringContext.getBean(AccountService.class).populateAccountingLineChartIfNeeded(line); 213 errorPrefix = OLEPropertyConstants.DOCUMENT + "." + PurapPropertyConstants.ITEM + "[" + Integer.toString(itemIndex) + "]." + OLEConstants.NEW_SOURCE_ACCT_LINE_PROPERTY_NAME; 214 rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new AddAccountingLineEvent(errorPrefix, purapForm.getDocument(), (AccountingLine) line)); 215 } else if (itemIndex == -2) { 216 //corrected: itemIndex == -2 is the only case for distribute account 217 //This is the case when we're inserting an accounting line for distribute account. 218 line = ((PurchasingFormBase) purapForm).getAccountDistributionnewSourceLine(); 219 //SpringContext.getBean(AccountService.class).populateAccountingLineChartIfNeeded(line); 220 errorPrefix = PurapPropertyConstants.ACCOUNT_DISTRIBUTION_NEW_SRC_LINE; 221 rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new AddAccountingLineEvent(errorPrefix, purapForm.getDocument(), (AccountingLine) line)); 222 } 223 224 if (rulePassed) { 225 // add accountingLine 226 SpringContext.getBean(PersistenceService.class).retrieveNonKeyFields(line); 227 if (itemIndex >= 0) { 228 insertAccountingLine(purapForm, item, line); 229 // clear the temp account 230 item.resetAccount(); 231 } else if (itemIndex == -2) { 232 //this is the case for distribute account 233 ((PurchasingFormBase) purapForm).addAccountDistributionsourceAccountingLine(line); 234 } 235 } 236 } 237 238 return mapping.findForward(OLEConstants.MAPPING_BASIC); 239 } 240 241 /** 242 * Insert the given Accounting Line in several appropriate places in the given item and given form. 243 * 244 * @param financialDocumentForm A form that inherits from PurchasingAccountsPaybleFormBase 245 * @param item A PurApItem 246 * @param line A PurApAccountingLine 247 */ 248 protected void insertAccountingLine(PurchasingAccountsPayableFormBase financialDocumentForm, PurApItem item, PurApAccountingLine line) { 249 PurchasingAccountsPayableDocument preq = (PurchasingAccountsPayableDocument) financialDocumentForm.getDocument(); 250 251 Integer index = item.getSourceAccountingLines().size() + 1; 252 line.setSequenceNumber(index); 253 // add it to the item 254 item.getSourceAccountingLines().add(line); 255 } 256 257 /** 258 * Allows the custom processing of an accounting line during a call to insert source line. If a custom method for inserting an 259 * accounting line was performed, then a value of true must be returned. 260 * 261 * @param purapForm 262 * @param request 263 * @return boolean indicating if validation succeeded 264 */ 265 public boolean processCustomInsertAccountingLine(PurchasingAccountsPayableFormBase purapForm, HttpServletRequest request) { 266 return false; 267 } 268 269 /** 270 * Insert the given Accounting Line in several appropriate places in the given item and given form. 271 * 272 * @param financialDocumentForm A form that inherits from KualiAccountingDocumentFormBase 273 * @param item A PurApItem 274 * @param line A PurApAccountingLine 275 */ 276 protected void insertAccountingLine(KualiAccountingDocumentFormBase financialDocumentForm, PurApItem item, PurApAccountingLine line) { 277 // add it to the item 278 item.getSourceAccountingLines().add(line); 279 } 280 281 /** 282 * @see org.kuali.ole.sys.web.struts.KualiAccountingDocumentActionBase#deleteSourceLine(org.apache.struts.action.ActionMapping, 283 * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) 284 */ 285 @Override 286 public ActionForward deleteSourceLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 287 PurchasingAccountsPayableFormBase purapForm = (PurchasingAccountsPayableFormBase) form; 288 289 String[] indexes = getSelectedLineForAccounts(request); 290 int itemIndex = Integer.parseInt(indexes[0]); 291 int accountIndex = Integer.parseInt(indexes[1]); 292 293 PurApItem item = (PurApItem) ((PurchasingAccountsPayableDocument) purapForm.getDocument()).getItem((itemIndex)); 294 if (itemIndex == -2) { 295 item.getSourceAccountingLines().remove(accountIndex); 296 } else { 297 item.getSourceAccountingLines().remove(accountIndex); 298 List<PurApAccountingLine> purApAccountingLineList = item.getSourceAccountingLines(); 299 BigDecimal initialPercent = new BigDecimal(0); 300 for (PurApAccountingLine purApAccountingLine : purApAccountingLineList) { 301 initialPercent = initialPercent.add(purApAccountingLine.getAccountLinePercent()); 302 } 303 initialPercent = new BigDecimal(100).subtract(initialPercent); 304 if(initialPercent.intValue()>0){ 305 item.resetAccount(initialPercent); 306 } 307 else{ 308 item.resetAccount(new BigDecimal(0)); 309 } 310 } 311 return mapping.findForward(OLEConstants.MAPPING_BASIC); 312 } 313 314 /** 315 * @see org.kuali.ole.sys.web.struts.KualiAccountingDocumentActionBase#getSourceAccountingLine(org.apache.struts.action.ActionForm, 316 * javax.servlet.http.HttpServletRequest) 317 */ 318 @Override 319 public SourceAccountingLine getSourceAccountingLine(ActionForm form, HttpServletRequest request) { 320 String[] indexes = getSelectedLineForAccounts(request); 321 int itemIndex = Integer.parseInt(indexes[0]); 322 int accountIndex = Integer.parseInt(indexes[1]); 323 PurchasingAccountsPayableFormBase purchasingAccountsPayableForm = (PurchasingAccountsPayableFormBase) form; 324 SourceAccountingLine line; 325 if (itemIndex == -2) { 326 line = customAccountRetrieval(accountIndex, purchasingAccountsPayableForm); 327 } else { 328 PurApItem item = (PurApItem) ((PurchasingAccountsPayableDocument) purchasingAccountsPayableForm.getDocument()).getItem((itemIndex)); 329 line = (SourceAccountingLine) ObjectUtils.deepCopy(item.getSourceAccountingLines().get(accountIndex)); 330 } 331 return line; 332 } 333 334 /** 335 * Perform custom processing on accounting lines. See <code>getSelectedLineForAccounts</code>. 336 * 337 * @param accountIndex The index of the account into the request parameter 338 * @param purchasingAccountsPayableForm A form which inherits from PurchasingAccountsPayableFormBase 339 * @return A SourceAccountingLine 340 */ 341 protected SourceAccountingLine customAccountRetrieval(int accountIndex, PurchasingAccountsPayableFormBase purchasingAccountsPayableForm) { 342 // default impl returns null 343 return null; 344 } 345 346 /** 347 * Will return an array of Strings containing 2 indexes, the first String is the item index and the second String is the account 348 * index. These are obtained by parsing the method to call parameter from the request, between the word ".line" and "." The 349 * indexes are separated by a semicolon (:) 350 * 351 * @param request The HttpServletRequest 352 * @return An array of Strings containing pairs of two indices, an item index and a account index 353 */ 354 protected String[] getSelectedLineForAccounts(HttpServletRequest request) { 355 String accountString = new String(); 356 String parameterName = (String) request.getAttribute(OLEConstants.METHOD_TO_CALL_ATTRIBUTE); 357 if (StringUtils.isNotBlank(parameterName)) { 358 accountString = StringUtils.substringBetween(parameterName, ".line", "."); 359 } 360 String[] result = StringUtils.split(accountString, ":"); 361 362 return result; 363 } 364 365 /** 366 * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#downloadBOAttachment(org.apache.struts.action.ActionMapping, 367 * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) 368 */ 369 @Override 370 public ActionForward downloadBOAttachment(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 371 PurchasingAccountsPayableDocument document = (PurchasingAccountsPayableDocument) ((PurchasingAccountsPayableFormBase) form).getDocument(); 372 373 for (org.kuali.rice.krad.bo.Note note : (java.util.List<org.kuali.rice.krad.bo.Note>) document.getNotes()) { 374 note.refreshReferenceObject("attachment"); 375 } 376 377 return super.downloadBOAttachment(mapping, form, request, response); 378 } 379 380 @Override 381 protected void processAccountingLineOverrides(List accountingLines) { 382 //do nothing purap handles these differently 383 } 384 385 /** 386 * Perform calculation on item line. 387 * 388 * @param mapping An ActionMapping 389 * @param form An ActionForm 390 * @param request The HttpServletRequest 391 * @param response The HttpServletResponse 392 * @return An ActionForward 393 */ 394 public ActionForward calculate(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 395 return mapping.findForward(OLEConstants.MAPPING_BASIC); 396 } 397 398 public ActionForward clearAllTaxes(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 399 return mapping.findForward(OLEConstants.MAPPING_BASIC); 400 } 401 402 protected void customCalculate(PurchasingAccountsPayableDocument purapDoc) { 403 // do nothing by default 404 } 405 406 /** 407 * Toggles all specific tabs to open 408 * 409 * @param mapping 410 * @param form 411 * @param request 412 * @param response 413 * @return 414 * @throws Exception 415 */ 416 public ActionForward showAllAccounts(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 417 KualiForm kualiForm = (KualiForm) form; 418 String accountingLineTab = "AccountingLines"; 419 String value = null; 420 421 Map<String, String> tabStates = kualiForm.getTabStates(); 422 Map<String, String> newTabStates = new HashMap<String, String>(); 423 for (Entry<String, String> tabEntry : tabStates.entrySet()) { 424 if (tabEntry.getKey().startsWith(accountingLineTab)) { 425 newTabStates.put(tabEntry.getKey(), "OPEN"); 426 } else { 427 if (tabEntry.getValue() instanceof String) { 428 value = tabEntry.getValue(); 429 } else { 430 //This is the case where the value is an Array of String, 431 //so we'll have to get the first element 432 Object result = tabEntry.getValue(); 433 result.getClass(); 434 value = ((String[]) result)[0]; 435 } 436 newTabStates.put(tabEntry.getKey(), value); 437 } 438 } 439 kualiForm.setTabStates(newTabStates); 440 return mapping.findForward(RiceConstants.MAPPING_BASIC); 441 } 442 443 /** 444 * Toggles all specific tabs to closed 445 * 446 * @param mapping 447 * @param form 448 * @param request 449 * @param response 450 * @return 451 * @throws Exception 452 */ 453 public ActionForward hideAllAccounts(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 454 KualiForm kualiForm = (KualiForm) form; 455 String accountingLineTab = "AccountingLines"; 456 String value = null; 457 458 Map<String, String> tabStates = kualiForm.getTabStates(); 459 Map<String, String> newTabStates = new HashMap<String, String>(); 460 for (Entry<String, String> tabEntry : tabStates.entrySet()) { 461 if (tabEntry.getKey().startsWith(accountingLineTab)) { 462 newTabStates.put(tabEntry.getKey(), "CLOSE"); 463 } else { 464 if (tabEntry.getValue() instanceof String) { 465 value = tabEntry.getValue(); 466 } else { 467 //This is the case where the value is an Array of String, 468 //so we'll have to get the first element 469 Object result = tabEntry.getValue(); 470 result.getClass(); 471 value = ((String[]) result)[0]; 472 } 473 newTabStates.put(tabEntry.getKey(), value); 474 } 475 } 476 kualiForm.setTabStates(newTabStates); 477 return mapping.findForward(RiceConstants.MAPPING_BASIC); 478 } 479 480 /** 481 * Override to verify the document has been saved before the note is inserted. This will assure the correct parent object id is 482 * associated with the note. 483 * 484 * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#insertBONote(org.apache.struts.action.ActionMapping, 485 * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) 486 */ 487 @Override 488 public ActionForward insertBONote(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 489 PurchasingAccountsPayableDocument document = (PurchasingAccountsPayableDocument) ((PurchasingAccountsPayableFormBase) form).getDocument(); 490 WorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument(); 491 492 if (workflowDocument.isInitiated()) { 493 SpringContext.getBean(DocumentService.class).saveDocument(document); 494 } 495 496 return super.insertBONote(mapping, form, request, response); 497 } 498 499}