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.sys.web.struts; 017 018import java.util.ArrayList; 019import java.util.HashMap; 020import java.util.Iterator; 021import java.util.List; 022import java.util.Map; 023 024import javax.servlet.http.HttpServletRequest; 025 026import org.apache.commons.lang.StringUtils; 027import org.apache.struts.upload.FormFile; 028import org.kuali.ole.coa.businessobject.Account; 029import org.kuali.ole.coa.businessobject.ObjectCode; 030import org.kuali.ole.coa.businessobject.SubAccount; 031import org.kuali.ole.coa.businessobject.SubObjectCode; 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.AccountingLineOverride; 036import org.kuali.ole.sys.businessobject.SourceAccountingLine; 037import org.kuali.ole.sys.businessobject.TargetAccountingLine; 038import org.kuali.ole.sys.context.SpringContext; 039import org.kuali.ole.sys.document.AccountingDocument; 040import org.kuali.ole.sys.document.web.struts.FinancialSystemTransactionalDocumentFormBase; 041import org.kuali.ole.sys.service.impl.OleParameterConstants; 042import org.kuali.rice.core.api.config.property.ConfigurationService; 043import org.kuali.rice.core.web.format.CurrencyFormatter; 044import org.kuali.rice.coreservice.framework.parameter.ParameterService; 045import org.kuali.rice.kns.service.BusinessObjectDictionaryService; 046import org.kuali.rice.krad.util.KRADConstants; 047import org.kuali.rice.krad.util.ObjectUtils; 048 049/** 050 * This class is the base action form for all financial documents. 051 */ 052public class KualiAccountingDocumentFormBase extends FinancialSystemTransactionalDocumentFormBase { 053 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(KualiAccountingDocumentFormBase.class); 054 055 protected SourceAccountingLine newSourceLine; 056 protected TargetAccountingLine newTargetLine; 057 058 protected Map editableAccounts; 059 protected Map forcedLookupOptionalFields; 060 061 // TODO: FormFile isn't Serializable, so mark these fields need as transient or create a Serializable subclass of FormFile 062 protected FormFile sourceFile; 063 protected FormFile targetFile; 064 protected boolean hideDetails = false; 065 066 /** 067 * This constructor sets up empty instances for the dependent objects... 068 */ 069 public KualiAccountingDocumentFormBase() { 070 super(); 071 072 // create an empty editableAccounts map, for safety's sake 073 editableAccounts = new HashMap(); 074 forcedReadOnlyFields = new HashMap(); 075 forcedLookupOptionalFields = new HashMap(); 076 } 077 078 079 /** 080 * Overrides the parent to call super.populate and then to call the accounting lines populate method that is specific to loading 081 * the two select lists on the page. 082 * 083 * @see org.kuali.rice.kns.web.struts.pojo.PojoForm#populate(javax.servlet.http.HttpServletRequest) 084 */ 085 @Override 086 public void populate(HttpServletRequest request) { 087 super.populate(request); 088 final String methodToCall = this.getMethodToCall(); 089 final Map parameterMap = request.getParameterMap(); 090 091 populateAccountingLinesForResponse(methodToCall, parameterMap); 092 093 setDocTypeName(discoverDocumentTypeName()); 094 } 095 096 /** 097 * Populates the accounting lines which need to be updated to successfully complete a response to the request 098 * @param methodToCall the method to call in the action to complete this request transaction 099 * @param parameterMap the map of parameters which came in with the transaction 100 */ 101 protected void populateAccountingLinesForResponse(String methodToCall, Map parameterMap) { 102 populateSourceAccountingLine(getNewSourceLine(), OLEPropertyConstants.NEW_SOURCE_LINE, parameterMap); 103 populateTargetAccountingLine(getNewTargetLine(), OLEPropertyConstants.NEW_TARGET_LINE, parameterMap); 104 105 // don't call populateAccountingLines if you are copying or errorCorrecting a document, 106 // since you want the accountingLines in the copy to be "identical" to those in the original 107 if (!StringUtils.equals(methodToCall, OLEConstants.COPY_METHOD) && !StringUtils.equals(methodToCall, OLEConstants.ERRORCORRECT_METHOD)) { 108 populateAccountingLines(parameterMap); 109 } 110 } 111 112 /** 113 * This method iterates over all of the source lines and all of the target lines in a transactional document, and calls 114 * prepareAccountingLineForValidationAndPersistence on each one. This is called because a user could have updated already 115 * existing accounting lines that had blank values in composite key fields. 116 * 117 * @param parameterMap the map of parameters that were sent in with the request 118 */ 119 protected void populateAccountingLines(Map parameterMap) { 120 Iterator sourceLines = getFinancialDocument().getSourceAccountingLines().iterator(); 121 int count = 0; 122 while (sourceLines.hasNext()) { 123 SourceAccountingLine sourceLine = (SourceAccountingLine) sourceLines.next(); 124 populateSourceAccountingLine(sourceLine, OLEPropertyConstants.DOCUMENT+"."+OLEPropertyConstants.SOURCE_ACCOUNTING_LINE+"["+count+"]", parameterMap); 125 count += 1; 126 } 127 128 Iterator targetLines = getFinancialDocument().getTargetAccountingLines().iterator(); 129 count = 0; 130 while (targetLines.hasNext()) { 131 TargetAccountingLine targetLine = (TargetAccountingLine) targetLines.next(); 132 populateTargetAccountingLine(targetLine, OLEPropertyConstants.DOCUMENT+"."+OLEPropertyConstants.TARGET_ACCOUNTING_LINE+"["+count+"]", parameterMap); 133 count += 1; 134 } 135 } 136 137 /** 138 * Populates a source accounting line bo using values from the struts form. This is in place to make sure that all of the 139 * composite key objects have the correct values in them. This should be overridden by children forms in the situation where 140 * document level attributes need to be pushed down into the accounting lines. 141 * 142 * @param sourceLine 143 * @param accountingLinePropertyName the property path from the form to the accounting line 144 * @param parameterMap the map of parameters that were sent in with the request 145 */ 146 public void populateSourceAccountingLine(SourceAccountingLine sourceLine, String accountingLinePropertyName, Map parameterMap) { 147 populateAccountingLine(sourceLine, accountingLinePropertyName, parameterMap); 148 } 149 150 /** 151 * Populates a target accounting line bo using values from the struts form. This is in place to make sure that all of the 152 * composite key objects have the correct values in them. This should be overridden by children forms in the situation where 153 * document level attributes need to be pushed down into the accounting lines. 154 * 155 * @param targetLine 156 * @param accountingLinePropertyName the property path from the form to the accounting line 157 * @param parameterMap the map of parameters that were sent in with the request 158 */ 159 public void populateTargetAccountingLine(TargetAccountingLine targetLine, String accountingLinePropertyName, Map parameterMap) { 160 populateAccountingLine(targetLine, accountingLinePropertyName, parameterMap); 161 } 162 163 /** 164 * Populates the dependent fields of objects contained within the given accountingLine 165 * 166 * @param line 167 * @param accountingLinePropertyName the property path from the form to the accounting line 168 * @param parameterMap the map of parameters that were sent in with the request 169 */ 170 @SuppressWarnings("deprecation") 171 protected void populateAccountingLine(AccountingLine line, String accountingLinePropertyName, Map parameterMap) { 172 SpringContext.getBean(BusinessObjectDictionaryService.class).performForceUppercase(line); 173 174 line.setDocumentNumber(getDocument().getDocumentNumber()); 175 176 if (ObjectUtils.isNull(line.getAccount())) { 177 line.setAccount(new Account()); 178 } 179 line.getAccount().setChartOfAccountsCode(line.getChartOfAccountsCode()); 180 181 if (ObjectUtils.isNull(line.getObjectCode())) { 182 line.setObjectCode(new ObjectCode()); 183 } 184 line.getObjectCode().setUniversityFiscalYear(getFinancialDocument().getPostingYear()); 185 line.getObjectCode().setChartOfAccountsCode(line.getChartOfAccountsCode()); 186 187 if (ObjectUtils.isNull(line.getSubAccount())) { 188 line.setSubAccount(new SubAccount()); 189 } 190 line.getSubAccount().setChartOfAccountsCode(line.getChartOfAccountsCode()); 191 line.getSubAccount().setAccountNumber(line.getAccountNumber()); 192 193 if (ObjectUtils.isNull(line.getSubObjectCode())) { 194 line.setSubObjectCode(new SubObjectCode()); 195 } 196 line.getSubObjectCode().setChartOfAccountsCode(line.getChartOfAccountsCode()); 197 line.getSubObjectCode().setAccountNumber(line.getAccountNumber()); 198 line.getSubObjectCode().setFinancialObjectCode(line.getFinancialObjectCode()); 199 line.getSubObjectCode().setUniversityFiscalYear(getFinancialDocument().getPostingYear()); 200 201 repopulateOverrides(line, accountingLinePropertyName, parameterMap); 202 203 AccountingLineOverride.populateFromInput(line); 204 } 205 206 /** 207 * This repopulates the override values from the request 208 * @param line the line to repopulate override values for 209 * @param accountingLinePropertyName the property path from the form to the accounting line 210 * @param parameterMap the map of parameters that were sent in with the request 211 */ 212 protected void repopulateOverrides(AccountingLine line, String accountingLinePropertyName, Map parameterMap) { 213 AccountingLineOverride.determineNeededOverrides(getFinancialDocument() , line); 214 if (line.getAccountExpiredOverrideNeeded()) { 215 if (LOG.isDebugEnabled()) { 216 StringUtils.join(parameterMap.keySet(), "\n"); 217 } 218 if (parameterMap.containsKey(accountingLinePropertyName+".accountExpiredOverride.present")) { 219 line.setAccountExpiredOverride(parameterMap.containsKey(accountingLinePropertyName+".accountExpiredOverride")); 220 } 221 } else { 222 line.setAccountExpiredOverride(false); 223 } 224 if (line.isObjectBudgetOverrideNeeded()) { 225 if (parameterMap.containsKey(accountingLinePropertyName+".objectBudgetOverride.present")) { 226 line.setObjectBudgetOverride(parameterMap.containsKey(accountingLinePropertyName+".objectBudgetOverride")); 227 } 228 } else { 229 line.setObjectBudgetOverride(false); 230 } 231 } 232 233 /** 234 * This method retrieves an instance of the form. 235 * 236 * @return 237 */ 238 public AccountingDocument getFinancialDocument() { 239 return (AccountingDocument) getDocument(); 240 } 241 242 /** 243 * @return Returns the newTargetLine. 244 */ 245 public TargetAccountingLine getNewTargetLine() { 246 if (newTargetLine == null) { 247 newTargetLine = createNewTargetAccountingLine(getFinancialDocument()); 248 } 249 return newTargetLine; 250 } 251 252 /** 253 * @param newExpenseLine The newTargetLine to set. 254 */ 255 public void setNewTargetLine(TargetAccountingLine newExpenseLine) { 256 this.newTargetLine = newExpenseLine; 257 } 258 259 /** 260 * @return Returns the newSourceLine. 261 */ 262 public SourceAccountingLine getNewSourceLine() { 263 if (newSourceLine == null) { 264 newSourceLine = createNewSourceAccountingLine(getFinancialDocument()); 265 } 266 return newSourceLine; 267 } 268 269 /** 270 * @param newIncomeLine The newSourceLine to set. 271 */ 272 public void setNewSourceLine(SourceAccountingLine newIncomeLine) { 273 this.newSourceLine = newIncomeLine; 274 } 275 276 /** 277 * @return Returns the sourceFile. 278 */ 279 public FormFile getSourceFile() { 280 return sourceFile; 281 } 282 283 /** 284 * @param sourceFile The sourceFile to set. 285 */ 286 public void setSourceFile(FormFile sourceFile) { 287 this.sourceFile = sourceFile; 288 } 289 290 /** 291 * @return Returns the targetFile. 292 */ 293 public FormFile getTargetFile() { 294 return targetFile; 295 } 296 297 /** 298 * @param targetFile The targetFile to set. 299 */ 300 public void setTargetFile(FormFile targetFile) { 301 this.targetFile = targetFile; 302 } 303 304 305 /** 306 * @return current Map of editableAccounts 307 */ 308 public Map getEditableAccounts() { 309 return editableAccounts; 310 } 311 312 /** 313 * @param editableAccounts the account Map to set 314 */ 315 public void setEditableAccounts(Map editableAccounts) { 316 this.editableAccounts = editableAccounts; 317 } 318 319 /** 320 * @return hideDetails attribute 321 */ 322 public boolean isHideDetails() { 323 return hideDetails; 324 } 325 326 /** 327 * @return hideDetails attribute 328 * @see #isHideDetails() 329 */ 330 public boolean getHideDetails() { 331 return isHideDetails(); 332 } 333 334 /** 335 * @param hideDetails 336 */ 337 public void setHideDetails(boolean hideDetails) { 338 this.hideDetails = hideDetails; 339 } 340 341 /** 342 * Retrieves the source accounting lines total in a currency format with commas. 343 * 344 * @return String 345 */ 346 public String getCurrencyFormattedSourceTotal() { 347 return (String) new CurrencyFormatter().format(getFinancialDocument().getSourceTotal()); 348 } 349 350 /** 351 * Retrieves the source accounting lines total in a currency format with commas. 352 * 353 * @return String 354 */ 355 public String getCurrencyFormattedTargetTotal() { 356 return (String) new CurrencyFormatter().format(getFinancialDocument().getTargetTotal()); 357 } 358 359 /** 360 * @return the URL to the accounting line import instructions 361 */ 362 public String getAccountingLineImportInstructionsUrl() { 363 return SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(OLEConstants.EXTERNALIZABLE_HELP_URL_KEY) + SpringContext.getBean(ParameterService.class).getParameterValueAsString(OleParameterConstants.FINANCIAL_SYSTEM_DOCUMENT.class, OLEConstants.FinancialApcParms.ACCOUNTING_LINE_IMPORT_HELP); 364 } 365 366 /** 367 * @param financialDocument 368 * @return a new source accounting line for the document 369 */ 370 protected SourceAccountingLine createNewSourceAccountingLine(AccountingDocument financialDocument) { 371 if (financialDocument == null) { 372 throw new IllegalArgumentException("invalid (null) document"); 373 } 374 try { 375 return (SourceAccountingLine) financialDocument.getSourceAccountingLineClass().newInstance(); 376 } 377 catch (Exception e) { 378 throw new IllegalArgumentException("unable to create a new source accounting line", e); 379 } 380 } 381 382 /** 383 * @param financialDocument 384 * @return a new target accounting line for the documet 385 */ 386 protected TargetAccountingLine createNewTargetAccountingLine(AccountingDocument financialDocument) { 387 if (financialDocument == null) { 388 throw new IllegalArgumentException("invalid (null) document"); 389 } 390 try { 391 return (TargetAccountingLine) financialDocument.getTargetAccountingLineClass().newInstance(); 392 } 393 catch (Exception e) { 394 throw new IllegalArgumentException("unable to create a new target accounting line", e); 395 } 396 } 397 398 /** 399 * This method takes a generic list, hopefully with some AccountingLine objects in it, and returns a list of AccountingLine 400 * objects, because Java generics are just so wonderful. 401 * 402 * @param lines a list of objects 403 * @return a list of the accounting lines that were in the lines parameter 404 */ 405 protected List<AccountingLine> harvestAccountingLines(List lines) { 406 List<AccountingLine> accountingLines = new ArrayList<AccountingLine>(); 407 for (Object o : lines) { 408 if (o instanceof AccountingLine) { 409 accountingLines.add((AccountingLine) o); 410 } 411 } 412 return accountingLines; 413 } 414 415 /** 416 * A <code>{@link Map}</code> of names of optional accounting line fields that require a quickfinder. 417 * 418 * @return a Map of fields 419 */ 420 public void setForcedLookupOptionalFields(Map fieldMap) { 421 forcedLookupOptionalFields = fieldMap; 422 } 423 424 /** 425 * A <code>{@link Map}</code> of names of optional accounting line fields that require a quickfinder. 426 * 427 * @return a Map of fields 428 */ 429 public Map getForcedLookupOptionalFields() { 430 return forcedLookupOptionalFields; 431 } 432 433 /** 434 * Adds the accounting line file size to the list of max file sizes. 435 * 436 * @see org.kuali.rice.kns.web.struts.form.pojo.PojoFormBase#customInitMaxUploadSizes() 437 */ 438 @Override 439 protected void customInitMaxUploadSizes() { 440 super.customInitMaxUploadSizes(); 441 addMaxUploadSize(SpringContext.getBean(ParameterService.class).getParameterValueAsString(OleParameterConstants.FINANCIAL_SYSTEM_DOCUMENT.class, OLEConstants.ACCOUNTING_LINE_IMPORT_MAX_FILE_SIZE_PARM_NM)); 442 } 443 444 /** 445 * @see org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase#shouldMethodToCallParameterBeUsed(java.lang.String, java.lang.String, javax.servlet.http.HttpServletRequest) 446 */ 447 @Override 448 public boolean shouldMethodToCallParameterBeUsed(String methodToCallParameterName, String methodToCallParameterValue, HttpServletRequest request) { 449 if(StringUtils.equals(methodToCallParameterName, KRADConstants.DISPATCH_REQUEST_PARAMETER)) { 450 if(this.getExcludedmethodToCall().contains(methodToCallParameterValue)) { 451 return true; 452 } 453 } 454 return super.shouldMethodToCallParameterBeUsed(methodToCallParameterName, methodToCallParameterValue, request); 455 } 456 457 /** 458 * get the names of the methods to call that can be excluded from the "be used" check. 459 * @return the names of the methods to call that can be excluded from the "be used" check 460 */ 461 protected List<String> getExcludedmethodToCall() { 462 return new ArrayList<String>(); 463 } 464}