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.fp.document.service.impl; 017 018 import static org.kuali.kfs.sys.document.validation.impl.AccountingDocumentRuleBaseConstants.ERROR_PATH.DOCUMENT_ERROR_PREFIX; 019 020 import java.util.ArrayList; 021 import java.util.Arrays; 022 import java.util.HashMap; 023 import java.util.Iterator; 024 import java.util.List; 025 import java.util.Map; 026 027 import org.apache.commons.lang.StringUtils; 028 import org.kuali.kfs.fp.businessobject.CashDrawer; 029 import org.kuali.kfs.fp.businessobject.CashieringTransaction; 030 import org.kuali.kfs.fp.businessobject.CoinDetail; 031 import org.kuali.kfs.fp.businessobject.CurrencyDetail; 032 import org.kuali.kfs.fp.document.CashReceiptDocument; 033 import org.kuali.kfs.fp.document.CashReceiptFamilyBase; 034 import org.kuali.kfs.fp.document.dataaccess.CashManagementDao; 035 import org.kuali.kfs.fp.document.service.CashReceiptService; 036 import org.kuali.kfs.fp.service.CashDrawerService; 037 import org.kuali.kfs.sys.KFSConstants; 038 import org.kuali.kfs.sys.KFSKeyConstants; 039 import org.kuali.kfs.sys.KFSPropertyConstants; 040 import org.kuali.kfs.sys.KFSKeyConstants.CashReceipt; 041 import org.kuali.kfs.sys.context.SpringContext; 042 import org.kuali.rice.kew.exception.WorkflowException; 043 import org.kuali.rice.kim.bo.Person; 044 import org.kuali.rice.kns.bo.Campus; 045 import org.kuali.rice.kns.bo.CampusImpl; 046 import org.kuali.rice.kns.bo.DocumentHeader; 047 import org.kuali.rice.kns.exception.InfrastructureException; 048 import org.kuali.rice.kns.service.BusinessObjectService; 049 import org.kuali.rice.kns.service.DataDictionaryService; 050 import org.kuali.rice.kns.service.DictionaryValidationService; 051 import org.kuali.rice.kns.service.KualiModuleService; 052 import org.kuali.rice.kns.service.ParameterService; 053 import org.kuali.rice.kns.util.GlobalVariables; 054 import org.kuali.rice.kns.util.KualiDecimal; 055 import org.kuali.rice.kns.workflow.service.KualiWorkflowDocument; 056 import org.kuali.rice.kns.workflow.service.WorkflowDocumentService; 057 import org.springframework.transaction.annotation.Transactional; 058 059 /** 060 * 061 * This is the default implementation of the CashReceiptService interface. 062 */ 063 @Transactional 064 public class CashReceiptServiceImpl implements CashReceiptService { 065 066 private BusinessObjectService businessObjectService; 067 private WorkflowDocumentService workflowDocumentService; 068 private CashManagementDao cashManagementDao; 069 private CashDrawerService cashDrawerService; 070 private ParameterService parameterService; 071 private DictionaryValidationService dictionaryValidationService; 072 073 /** 074 * This method verifies the campus code provided exists. This is done by retrieving all the available campuses from 075 * the BusinessObjectService and then looking for a matching campus code within the result set. 076 * 077 * @param campusCode The campus code to be verified. 078 * @return True if the campus code provided is valid and exists, false otherwise. 079 */ 080 protected boolean verifyCampus(String campusCode) { 081 List campusList = SpringContext.getBean(KualiModuleService.class).getResponsibleModuleService( 082 Campus.class).getExternalizableBusinessObjectsList(Campus.class, new HashMap<String, Object>()); 083 Iterator campiiIter = campusList.iterator(); 084 boolean foundCampus = false; 085 while (campiiIter.hasNext() && !foundCampus) { 086 Campus campus = (Campus)campiiIter.next(); 087 if (campus.getCampusCode().equals(campusCode)) { 088 foundCampus = true; 089 } 090 } 091 return foundCampus; 092 093 } 094 095 096 /** 097 * This method retrieves the cash receipt verification unit based on the user provided. This is done by retrieving the campus 098 * code associated with the user provided and then performing the lookup using this campus code. 099 * 100 * @param user The user to be used to retrieve the verification unit. 101 * @return The cash receipt verification unit associated with the user provided. 102 * 103 * @see org.kuali.kfs.fp.document.service.CashReceiptService#getCashReceiptVerificationUnit(org.kuali.rice.kns.bo.user.KualiUser) 104 */ 105 public String getCashReceiptVerificationUnitForUser(Person user) { 106 String unitName = null; 107 108 if (user == null) { 109 throw new IllegalArgumentException("invalid (null) user"); 110 } 111 112 return user.getCampusCode(); 113 } 114 115 116 /** 117 * This method retrieves a collection of cash receipts using the verification unit and the status provided to 118 * retrieve the cash receipts. 119 * 120 * @param verificationUnit The verification unit used to retrieve a collection of associated cash receipts. 121 * @param statusCode The status code of the cash receipts to be retrieved. 122 * @return A collection of cash receipt documents which match the search criteria provided. 123 * 124 * @see org.kuali.kfs.fp.document.service.CashReceiptService#getCashReceipts(java.lang.String, java.lang.String) 125 */ 126 public List getCashReceipts(String verificationUnit, String statusCode) { 127 if (StringUtils.isBlank(statusCode)) { 128 throw new IllegalArgumentException("invalid (blank) statusCode"); 129 } 130 131 String[] statii = new String[] { statusCode }; 132 return getCashReceipts(verificationUnit, statii); 133 } 134 135 /** 136 * This method retrieves a collection of cash receipts using the verification unit and the statuses provided to 137 * retrieve the cash receipts. 138 * 139 * @param verificationUnit The verification unit used to retrieve a collection of associated cash receipts. 140 * @param statii A collection of possible statuses that will be used in the lookup of cash receipts. 141 * @return A collection of cash receipt documents which match the search criteria provided. 142 * 143 * @see org.kuali.kfs.fp.document.service.CashReceiptService#getCashReceipts(java.lang.String, java.lang.String[]) 144 */ 145 public List getCashReceipts(String verificationUnit, String[] statii) { 146 if (StringUtils.isBlank(verificationUnit)) { 147 throw new IllegalArgumentException("invalid (blank) verificationUnit"); 148 } 149 if (statii == null) { 150 throw new IllegalArgumentException("invalid (null) statii"); 151 } 152 else { 153 if (statii.length == 0) { 154 throw new IllegalArgumentException("invalid (empty) statii"); 155 } 156 else { 157 for (int i = 0; i < statii.length; ++i) { 158 if (StringUtils.isBlank(statii[i])) { 159 throw new IllegalArgumentException("invalid (blank) status code " + i); 160 } 161 } 162 } 163 } 164 165 return getPopulatedCashReceipts(verificationUnit, statii); 166 } 167 168 /** 169 * This method retrieves a populated collection of cash receipts using the lookup parameters provided. A populated 170 * cash receipt document is a cash receipt document with fully populated workflow fields. 171 * 172 * @param verificationUnit The verification unit used to retrieve a collection of associated cash receipts. 173 * @param statii A collection of possible statuses that will be used in the lookup of the cash receipts. 174 * @return List of CashReceiptDocument instances with their associated workflowDocuments populated. 175 */ 176 public List getPopulatedCashReceipts(String verificationUnit, String[] statii) { 177 Map queryCriteria = buildCashReceiptCriteriaMap(verificationUnit, statii); 178 179 List documents = new ArrayList(getBusinessObjectService().findMatchingOrderBy(CashReceiptDocument.class, queryCriteria, KFSPropertyConstants.DOCUMENT_NUMBER, true)); 180 181 populateWorkflowFields(documents); 182 183 return documents; 184 } 185 186 187 /** 188 * This method builds out a map of search criteria for performing cash receipt lookups using the values provided. 189 * 190 * @param campusCode The campus code to use as search criteria for looking up cash receipts. 191 * @param statii A collection of possible statuses to use as search criteria for looking up cash receipts. 192 * @return The search criteria provided in a map with CashReceiptConstants used as keys to the parameters given. 193 */ 194 protected Map buildCashReceiptCriteriaMap(String campusCode, String[] statii) { 195 Map queryCriteria = new HashMap(); 196 197 if (statii.length == 1) { 198 queryCriteria.put(KFSConstants.CashReceiptConstants.CASH_RECEIPT_DOC_HEADER_STATUS_CODE_PROPERTY_NAME, statii[0]); 199 } 200 else if (statii.length > 0) { 201 List<String> statusList = Arrays.asList(statii); 202 queryCriteria.put(KFSConstants.CashReceiptConstants.CASH_RECEIPT_DOC_HEADER_STATUS_CODE_PROPERTY_NAME, statusList); 203 } 204 205 queryCriteria.put(KFSConstants.CashReceiptConstants.CASH_RECEIPT_CAMPUS_LOCATION_CODE_PROPERTY_NAME, campusCode); 206 207 return queryCriteria; 208 } 209 210 /** 211 * This method populates the workflowDocument field of each CashReceiptDocument in the given List 212 * 213 * @param documents A collection of CashReceiptDocuments to be populated with workflow document data. 214 */ 215 protected void populateWorkflowFields(List documents) { 216 for (Iterator i = documents.iterator(); i.hasNext();) { 217 CashReceiptDocument cr = (CashReceiptDocument) i.next(); 218 219 KualiWorkflowDocument workflowDocument = null; 220 DocumentHeader docHeader = cr.getDocumentHeader(); 221 try { 222 Long documentHeaderId = Long.valueOf(docHeader.getDocumentNumber()); 223 Person user = GlobalVariables.getUserSession().getPerson(); 224 225 workflowDocument = getWorkflowDocumentService().createWorkflowDocument(documentHeaderId, user); 226 } 227 catch (WorkflowException e) { 228 throw new InfrastructureException("unable to retrieve workflow document for documentHeaderId '" + docHeader.getDocumentNumber() + "'", e); 229 } 230 231 docHeader.setWorkflowDocument(workflowDocument); 232 } 233 } 234 235 /** 236 * This method retrieves the cash details from the cash receipt document provided and adds those details to the 237 * associated cash drawer. After the details are added to the drawer, the drawer is persisted to the database. 238 * 239 * @param crDoc The cash receipt document the cash details will be retrieved from. 240 * 241 * @see org.kuali.kfs.fp.document.service.CashReceiptService#addCashDetailsToCashDrawer(org.kuali.kfs.fp.document.CashReceiptDocument) 242 */ 243 public void addCashDetailsToCashDrawer(CashReceiptDocument crDoc) { 244 CashDrawer drawer = retrieveCashDrawer(crDoc); 245 // we need to to add the currency and coin to the cash management doc's cumulative CR as well 246 if (crDoc.getCurrencyDetail() != null && !crDoc.getCurrencyDetail().isEmpty()) { 247 CurrencyDetail cumulativeCurrencyDetail = cashManagementDao.findCurrencyDetailByCashieringRecordSource(drawer.getReferenceFinancialDocumentNumber(), CashieringTransaction.DETAIL_DOCUMENT_TYPE, KFSConstants.CurrencyCoinSources.CASH_RECEIPTS); 248 cumulativeCurrencyDetail.add(crDoc.getCurrencyDetail()); 249 businessObjectService.save(cumulativeCurrencyDetail); 250 251 drawer.addCurrency(crDoc.getCurrencyDetail()); 252 } 253 if (crDoc.getCoinDetail() != null && !crDoc.getCoinDetail().isEmpty()) { 254 CoinDetail cumulativeCoinDetail = cashManagementDao.findCoinDetailByCashieringRecordSource(drawer.getReferenceFinancialDocumentNumber(), CashieringTransaction.DETAIL_DOCUMENT_TYPE, KFSConstants.CurrencyCoinSources.CASH_RECEIPTS); 255 cumulativeCoinDetail.add(crDoc.getCoinDetail()); 256 businessObjectService.save(cumulativeCoinDetail); 257 258 drawer.addCoin(crDoc.getCoinDetail()); 259 } 260 SpringContext.getBean(BusinessObjectService.class).save(drawer); 261 } 262 263 /** 264 * This method finds the appropriate cash drawer for this cash receipt document to add cash to. 265 * 266 * @param crDoc The document the cash drawer will be retrieved from. 267 * @return An instance of a cash drawer associated with the cash receipt document provided. 268 */ 269 protected CashDrawer retrieveCashDrawer(CashReceiptDocument crDoc) { 270 String campusCode = crDoc.getCampusLocationCode(); 271 if (campusCode == null) { 272 throw new RuntimeException("Cannot find workgroup name for Cash Receipt document: "+crDoc.getDocumentNumber()); 273 } 274 275 CashDrawer drawer = cashDrawerService.getByCampusCode(campusCode); 276 if (drawer == null) { 277 throw new RuntimeException("There is no Cash Drawer for Workgroup "+campusCode); 278 } 279 return drawer; 280 } 281 282 /** 283 * @see org.kuali.module.financial.service.CashReceiptTotalsVerificationService#areCashTotalsInvalid(org.kuali.kfs.fp.document.CashReceiptDocument) 284 */ 285 public boolean areCashTotalsInvalid(CashReceiptDocument cashReceiptDocument) { 286 String documentEntryName = cashReceiptDocument.getDocumentHeader().getWorkflowDocument().getDocumentType(); 287 288 boolean isInvalid = isTotalInvalid(cashReceiptDocument, cashReceiptDocument.getTotalCheckAmount(), documentEntryName, KFSPropertyConstants.TOTAL_CHECK_AMOUNT); 289 isInvalid |= isTotalInvalid(cashReceiptDocument, cashReceiptDocument.getTotalCashAmount(), documentEntryName, KFSPropertyConstants.TOTAL_CASH_AMOUNT); 290 isInvalid |= isTotalInvalid(cashReceiptDocument, cashReceiptDocument.getTotalCoinAmount(), documentEntryName, KFSPropertyConstants.TOTAL_COIN_AMOUNT); 291 292 isInvalid |= isTotalInvalid(cashReceiptDocument, cashReceiptDocument.getTotalDollarAmount(), documentEntryName, KFSPropertyConstants.SUM_TOTAL_AMOUNT); 293 294 return isInvalid; 295 } 296 297 /** 298 * Puts an error message in the error map for that property if the amount is negative. 299 * 300 * @param cashReceiptDocument submitted cash receipt document 301 * @param totalAmount total amount (cash total, check total, etc) 302 * @param documentEntryName document type 303 * @param propertyName property type (i.e totalCashAmount, totalCheckAmount, etc) 304 * @return true if the totalAmount is an invalid value 305 */ 306 protected boolean isTotalInvalid(CashReceiptFamilyBase cashReceiptDocument, KualiDecimal totalAmount, String documentEntryName, String propertyName) { 307 boolean isInvalid = false; 308 String errorProperty = DOCUMENT_ERROR_PREFIX + propertyName; 309 310 if (totalAmount != null) { 311 DataDictionaryService dds = SpringContext.getBean(DataDictionaryService.class); 312 String errorLabel = dds.getAttributeLabel(documentEntryName, propertyName); 313 314 if (totalAmount.isNegative()) { 315 GlobalVariables.getMessageMap().putError(errorProperty, CashReceipt.ERROR_NEGATIVE_TOTAL, errorLabel); 316 317 isInvalid = true; 318 } 319 else { 320 int precount = GlobalVariables.getMessageMap().size(); 321 322 getDictionaryValidationService().validateDocumentAttribute(cashReceiptDocument, propertyName, DOCUMENT_ERROR_PREFIX); 323 324 // replace generic error message, if any, with something more readable 325 GlobalVariables.getMessageMap().replaceError(errorProperty, KFSKeyConstants.ERROR_MAX_LENGTH, CashReceipt.ERROR_EXCESSIVE_TOTAL, errorLabel); 326 327 int postcount = GlobalVariables.getMessageMap().size(); 328 isInvalid = (postcount > precount); 329 } 330 } 331 332 return isInvalid; 333 } 334 335 // injection-molding 336 /** 337 * Gets the businessObjectService attribute. 338 * @return current value of businessObjectService. 339 */ 340 public BusinessObjectService getBusinessObjectService() { 341 return businessObjectService; 342 } 343 344 /** 345 * Sets the businessObjectService attribute value. 346 * @param businessObjectService The businessObjectService to set. 347 */ 348 public void setBusinessObjectService(BusinessObjectService businessObjectService) { 349 this.businessObjectService = businessObjectService; 350 } 351 352 353 /** 354 * Gets the workflowDocumentService attribute. 355 * @return current value of workflowDocumentService. 356 */ 357 public WorkflowDocumentService getWorkflowDocumentService() { 358 return workflowDocumentService; 359 } 360 361 /** 362 * Sets the workflowDocumentService attribute value. 363 * @param workflowDocumentService The workflowDocumentService to set. 364 */ 365 public void setWorkflowDocumentService(WorkflowDocumentService workflowDocumentService) { 366 this.workflowDocumentService = workflowDocumentService; 367 } 368 369 /** 370 * Gets the cashManagementDao attribute. 371 * 372 * @return Returns the cashManagementDao. 373 */ 374 public CashManagementDao getCashManagementDao() { 375 return cashManagementDao; 376 } 377 378 379 /** 380 * Sets the cashManagementDao attribute value. 381 * 382 * @param cashManagementDao The cashManagementDao to set. 383 */ 384 public void setCashManagementDao(CashManagementDao cashManagementDao) { 385 this.cashManagementDao = cashManagementDao; 386 } 387 388 /** 389 * Gets the cashDrawerService attribute. 390 * 391 * @return Returns the cashDrawerService. 392 */ 393 public CashDrawerService getCashDrawerService() { 394 return cashDrawerService; 395 } 396 397 398 /** 399 * Sets the cashDrawerService attribute value. 400 * 401 * @param cashDrawerService The cashDrawerService to set. 402 */ 403 public void setCashDrawerService(CashDrawerService cashDrawerService) { 404 this.cashDrawerService = cashDrawerService; 405 } 406 407 /** 408 * Gets the parameterService attribute. 409 * 410 * @return Returns the parameterService. 411 */ 412 public ParameterService getParameterService() { 413 return parameterService; 414 } 415 416 417 /** 418 * Sets the parameterService attribute value. 419 * 420 * @param parameterService The parameterService to set. 421 */ 422 public void setParameterService(ParameterService parameterService) { 423 this.parameterService = parameterService; 424 } 425 426 /** 427 * Gets the dictionaryValidationService attribute. 428 * @return Returns the dictionaryValidationService. 429 */ 430 public DictionaryValidationService getDictionaryValidationService() { 431 return dictionaryValidationService; 432 } 433 434 /** 435 * Sets the dictionaryValidationService attribute value. 436 * @param dictionaryValidationService The dictionaryValidationService to set. 437 */ 438 public void setDictionaryValidationService(DictionaryValidationService dictionaryValidationService) { 439 this.dictionaryValidationService = dictionaryValidationService; 440 } 441 } 442