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.service.impl; 017 018import org.apache.commons.collections.CollectionUtils; 019import org.apache.commons.lang.StringUtils; 020import org.apache.commons.lang.text.StrBuilder; 021import org.kuali.ole.module.purap.PurapConstants; 022import org.kuali.ole.module.purap.PurapConstants.CreditMemoStatuses; 023import org.kuali.ole.module.purap.PurapKeyConstants; 024import org.kuali.ole.module.purap.PurapParameterConstants; 025import org.kuali.ole.module.purap.PurapPropertyConstants; 026import org.kuali.ole.module.purap.businessobject.*; 027import org.kuali.ole.module.purap.document.*; 028import org.kuali.ole.module.purap.document.dataaccess.CreditMemoDao; 029import org.kuali.ole.module.purap.document.service.*; 030import org.kuali.ole.module.purap.document.validation.event.AttributedContinuePurapEvent; 031import org.kuali.ole.module.purap.service.PurapAccountingService; 032import org.kuali.ole.module.purap.service.PurapGeneralLedgerService; 033import org.kuali.ole.module.purap.util.ExpiredOrClosedAccountEntry; 034import org.kuali.ole.module.purap.util.VendorGroupingHelper; 035import org.kuali.ole.select.document.OleVendorCreditMemoDocument; 036import org.kuali.ole.sys.businessobject.Bank; 037import org.kuali.ole.sys.businessobject.SourceAccountingLine; 038import org.kuali.ole.sys.context.SpringContext; 039import org.kuali.ole.sys.service.BankService; 040import org.kuali.ole.vnd.VendorConstants; 041import org.kuali.ole.vnd.VendorUtils; 042import org.kuali.ole.vnd.businessobject.VendorAddress; 043import org.kuali.ole.vnd.businessobject.VendorDetail; 044import org.kuali.ole.vnd.document.service.VendorService; 045import org.kuali.rice.core.api.config.property.ConfigurationService; 046import org.kuali.rice.core.api.util.type.KualiDecimal; 047import org.kuali.rice.coreservice.framework.parameter.ParameterService; 048import org.kuali.rice.kew.api.KewApiServiceLocator; 049import org.kuali.rice.kew.api.WorkflowDocument; 050import org.kuali.rice.kew.api.document.search.DocumentSearchCriteria; 051import org.kuali.rice.kew.api.document.search.DocumentSearchResult; 052import org.kuali.rice.kew.api.document.search.DocumentSearchResults; 053import org.kuali.rice.kew.api.exception.WorkflowException; 054import org.kuali.rice.kim.api.identity.Person; 055import org.kuali.rice.kns.service.DataDictionaryService; 056import org.kuali.rice.krad.bo.DocumentHeader; 057import org.kuali.rice.krad.bo.Note; 058import org.kuali.rice.krad.exception.ValidationException; 059import org.kuali.rice.krad.service.DocumentService; 060import org.kuali.rice.krad.service.NoteService; 061import org.kuali.rice.krad.util.GlobalVariables; 062import org.kuali.rice.krad.util.KRADPropertyConstants; 063import org.kuali.rice.krad.util.ObjectUtils; 064import org.kuali.rice.krad.workflow.service.WorkflowDocumentService; 065import org.springframework.transaction.annotation.Transactional; 066 067import java.math.BigDecimal; 068import java.sql.Date; 069import java.sql.Timestamp; 070import java.util.*; 071 072/** 073 * Provides services to support the creation of a Credit Memo Document. 074 */ 075@Transactional 076public class CreditMemoServiceImpl implements CreditMemoService { 077 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(CreditMemoServiceImpl.class); 078 079 private AccountsPayableService accountsPayableService; 080 private CreditMemoDao creditMemoDao; 081 private DataDictionaryService dataDictionaryService; 082 private DocumentService documentService; 083 private ConfigurationService kualiConfigurationService; 084 private NoteService noteService; 085 private PaymentRequestService paymentRequestService; 086 private PurapAccountingService purapAccountingService; 087 private PurapGeneralLedgerService purapGeneralLedgerService; 088 private PurapService purapService; 089 private PurchaseOrderService purchaseOrderService; 090 private VendorService vendorService; 091 private WorkflowDocumentService workflowDocumentService; 092 093 094 public void setAccountsPayableService(AccountsPayableService accountsPayableService) { 095 this.accountsPayableService = accountsPayableService; 096 } 097 098 public void setCreditMemoDao(CreditMemoDao creditMemoDao) { 099 this.creditMemoDao = creditMemoDao; 100 } 101 102 public void setDataDictionaryService(DataDictionaryService dataDictionaryService) { 103 this.dataDictionaryService = dataDictionaryService; 104 } 105 106 public void setDocumentService(DocumentService documentService) { 107 this.documentService = documentService; 108 } 109 110 public void setConfigurationService(ConfigurationService kualiConfigurationService) { 111 this.kualiConfigurationService = kualiConfigurationService; 112 } 113 114 public void setNoteService(NoteService noteService) { 115 this.noteService = noteService; 116 } 117 118 public void setPaymentRequestService(PaymentRequestService paymentRequestService) { 119 this.paymentRequestService = paymentRequestService; 120 } 121 122 public void setPurapAccountingService(PurapAccountingService purapAccountingService) { 123 this.purapAccountingService = purapAccountingService; 124 } 125 126 public void setPurapGeneralLedgerService(PurapGeneralLedgerService purapGeneralLedgerService) { 127 this.purapGeneralLedgerService = purapGeneralLedgerService; 128 } 129 130 public void setPurapService(PurapService purapService) { 131 this.purapService = purapService; 132 } 133 134 public void setPurchaseOrderService(PurchaseOrderService purchaseOrderService) { 135 this.purchaseOrderService = purchaseOrderService; 136 } 137 138 public void setVendorService(VendorService vendorService) { 139 this.vendorService = vendorService; 140 } 141 142 public void setWorkflowDocumentService(WorkflowDocumentService workflowDocumentService) { 143 this.workflowDocumentService = workflowDocumentService; 144 } 145 146 147 /** 148 * @see org.kuali.ole.module.purap.document.service.CreditMemoService#getCreditMemosToExtract(java.lang.String) 149 */ 150 @Override 151 public List<VendorCreditMemoDocument> getCreditMemosToExtract(String chartCode) { 152 LOG.debug("getCreditMemosToExtract() started"); 153 154 List<VendorCreditMemoDocument> docs = creditMemoDao.getCreditMemosToExtract(chartCode); 155 docs = (List<VendorCreditMemoDocument>) filterCreditMemoByAppDocStatus(docs, CreditMemoStatuses.STATUSES_ALLOWED_FOR_EXTRACTION); 156 157 return docs; 158 159 } 160 161 @Override 162 public Collection<VendorCreditMemoDocument> getCreditMemosToExtractByVendor(String chartCode, VendorGroupingHelper vendor) { 163 LOG.debug("getCreditMemosToExtractByVendor() started"); 164 165 Collection<VendorCreditMemoDocument> docs = creditMemoDao.getCreditMemosToExtractByVendor(chartCode, vendor); 166 docs = filterCreditMemoByAppDocStatus(docs, CreditMemoStatuses.STATUSES_ALLOWED_FOR_EXTRACTION); 167 return docs; 168 169 } 170 171 @Override 172 public Set<VendorGroupingHelper> getVendorsOnCreditMemosToExtract(String chartCode) { 173 LOG.debug("getVendorsOnCreditMemosToExtract() started"); 174 HashSet<VendorGroupingHelper> vendors = new HashSet<VendorGroupingHelper>(); 175 176 List<VendorCreditMemoDocument> docs = this.getCreditMemosToExtract(chartCode); 177 178 for(VendorCreditMemoDocument vendorCreditMemoDocument : docs) { 179 vendors.add(new VendorGroupingHelper(vendorCreditMemoDocument)); 180 } 181 182// while ( docs.hasNext() ) { 183 // VendorCreditMemoDocument doc = docs.next(); 184 // vendors.add( new VendorGroupingHelper( doc ) ); 185 // } 186 return vendors; 187 } 188 189 /** 190 * Since PaymentRequest does not have the app doc status, perform an additional lookup 191 * through doc search by using list of PaymentRequest Doc numbers. Query appDocStatus 192 * from workflow document and filter against the provided status 193 * <p/> 194 * DocumentSearch allows for multiple docNumber lookup by docId|docId|docId conversion 195 * 196 * @param lookupDocNumbers 197 * @param appDocStatus 198 * @return 199 */ 200 private List<String> filterCreditMemoByAppDocStatus(List<String> lookupDocNumbers, String... appDocStatus) { 201 boolean valid = false; 202 203 final String DOC_NUM_DELIM = "|"; 204 StrBuilder routerHeaderIdBuilder = new StrBuilder().appendWithSeparators(lookupDocNumbers, DOC_NUM_DELIM); 205 206 List<String> creditMemoDocNumbers = new ArrayList<String>(); 207 208 DocumentSearchCriteria.Builder documentSearchCriteriaDTO = DocumentSearchCriteria.Builder.create(); 209 documentSearchCriteriaDTO.setDocumentId(routerHeaderIdBuilder.toString()); 210 documentSearchCriteriaDTO.setDocumentTypeName(PurapConstants.PurapDocTypeCodes.CREDIT_MEMO_DOCUMENT); 211 212 DocumentSearchResults creditMemoDocumentsList = KewApiServiceLocator.getWorkflowDocumentService().documentSearch( 213 GlobalVariables.getUserSession().getPrincipalId(), documentSearchCriteriaDTO.build()); 214 215 for (DocumentSearchResult creditMemoDocument : creditMemoDocumentsList.getSearchResults()) { 216 ///use the appDocStatus from the KeyValueDTO result to look up custom status 217 if (Arrays.asList(appDocStatus).contains(creditMemoDocument.getDocument().getApplicationDocumentStatus())) { 218 //found the matching status, retrieve the routeHeaderId and add to the list 219 creditMemoDocNumbers.add(creditMemoDocument.getDocument().getDocumentId()); 220 } 221 } 222 223 return creditMemoDocNumbers; 224 } 225 226 /** 227 * Wrapper class to the filterPaymentRequestByAppDocStatus 228 * <p/> 229 * This class first extract the payment request document numbers from the Payment Request Collections, 230 * then perform the filterPaymentRequestByAppDocStatus function. Base on the filtered payment request 231 * doc number, reconstruct the filtered Payment Request Collection 232 * 233 * @param paymentRequestDocuments 234 * @param appDocStatus 235 * @return 236 */ 237 private Collection<VendorCreditMemoDocument> filterCreditMemoByAppDocStatus(Collection<VendorCreditMemoDocument> creditMemoDocuments, String... appDocStatus) { 238 List<String> creditMemoDocNumbers = new ArrayList<String>(); 239 for (VendorCreditMemoDocument creditMemo : creditMemoDocuments) { 240 creditMemoDocNumbers.add(creditMemo.getDocumentNumber()); 241 } 242 243 List<String> filteredCreditMemoDocNumbers = filterCreditMemoByAppDocStatus(creditMemoDocNumbers, appDocStatus); 244 245 Collection<VendorCreditMemoDocument> filteredCreditMemoDocuments = new ArrayList<VendorCreditMemoDocument>(); 246 //add to filtered collection if it is in the filtered payment request doc number list 247 for (VendorCreditMemoDocument creditMemo : creditMemoDocuments) { 248 if (filteredCreditMemoDocNumbers.contains(creditMemo.getDocumentNumber())) { 249 filteredCreditMemoDocuments.add(creditMemo); 250 } 251 } 252 return filteredCreditMemoDocuments; 253 } 254 255 256 /** 257 * Wrapper class to the filterPaymentRequestByAppDocStatus (Collection<PaymentRequestDocument>) 258 * <p/> 259 * This class first construct the Payment Request Collection from the iterator, and then process through 260 * filterPaymentRequestByAppDocStatus 261 * 262 * @param paymentRequestDocuments 263 * @param appDocStatus 264 * @return 265 */ 266 private Iterator<VendorCreditMemoDocument> filterCreditMemoByAppDocStatus(Iterator<VendorCreditMemoDocument> creditMemoIterator, String... appDocStatus) { 267 Collection<VendorCreditMemoDocument> creditMemoDocuments = new ArrayList<VendorCreditMemoDocument>(); 268 for (; creditMemoIterator.hasNext(); ) { 269 creditMemoDocuments.add(creditMemoIterator.next()); 270 } 271 272 return filterCreditMemoByAppDocStatus(creditMemoDocuments, appDocStatus).iterator(); 273 } 274 275 /** 276 * @see org.kuali.ole.module.purap.document.service.CreditMemoService#creditMemoDuplicateMessages(org.kuali.ole.module.purap.document.CreditMemoDocument) 277 */ 278 @Override 279 public String creditMemoDuplicateMessages(VendorCreditMemoDocument cmDocument) { 280 String duplicateMessage = null; 281 282 String vendorNumber = cmDocument.getVendorNumber(); 283 if (StringUtils.isEmpty(vendorNumber)) { 284 PurchasingAccountsPayableDocument sourceDocument = cmDocument.getPurApSourceDocumentIfPossible(); 285 if (ObjectUtils.isNotNull(sourceDocument)) { 286 vendorNumber = sourceDocument.getVendorNumber(); 287 } 288 } 289 290 if (StringUtils.isNotEmpty(vendorNumber)) { 291 // check for existence of another credit memo with the same vendor and vendor credit memo number 292 if (creditMemoDao.duplicateExists(VendorUtils.getVendorHeaderId(vendorNumber), VendorUtils.getVendorDetailId(vendorNumber), cmDocument.getCreditMemoNumber())) { 293 duplicateMessage = kualiConfigurationService.getPropertyValueAsString(PurapKeyConstants.MESSAGE_DUPLICATE_CREDIT_MEMO_VENDOR_NUMBER); 294 } 295 296 // check for existence of another credit memo with the same vendor and credit memo date 297 if (creditMemoDao.duplicateExists(VendorUtils.getVendorHeaderId(vendorNumber), VendorUtils.getVendorDetailId(vendorNumber), cmDocument.getCreditMemoDate(), cmDocument.getCreditMemoAmount())) { 298 duplicateMessage = kualiConfigurationService.getPropertyValueAsString(PurapKeyConstants.MESSAGE_DUPLICATE_CREDIT_MEMO_VENDOR_NUMBER_DATE_AMOUNT); 299 } 300 } 301 302 return duplicateMessage; 303 } 304 305 /** 306 * @see org.kuali.ole.module.purap.document.service.CreditMemoService#getPOInvoicedItems(org.kuali.ole.module.purap.document.PurchaseOrderDocument) 307 */ 308 @Override 309 public List<PurchaseOrderItem> getPOInvoicedItems(PurchaseOrderDocument poDocument) { 310 List<PurchaseOrderItem> invoicedItems = new ArrayList<PurchaseOrderItem>(); 311 312 for (Iterator iter = poDocument.getItems().iterator(); iter.hasNext(); ) { 313 PurchaseOrderItem poItem = (PurchaseOrderItem) iter.next(); 314 315 // only items of type above the line can be considered for being invoiced 316 if (poItem.getItemType().isAdditionalChargeIndicator()) { 317 continue; 318 } 319 320 if (poItem.getItemType().isQuantityBasedGeneralLedgerIndicator() && poItem.getItemInvoicedTotalQuantity().isGreaterThan(KualiDecimal.ZERO)) { 321 invoicedItems.add(poItem); 322 } else { 323 BigDecimal unitPrice = (poItem.getItemUnitPrice() == null ? new BigDecimal(0) : poItem.getItemUnitPrice()); 324 if (unitPrice.doubleValue() > poItem.getItemOutstandingEncumberedAmount().doubleValue()) { 325 invoicedItems.add(poItem); 326 } 327 } 328 } 329 330 return invoicedItems; 331 } 332 333 334 /** 335 * @see org.kuali.ole.module.purap.document.service.CreditMemoService#calculateCreditMemo(org.kuali.ole.module.purap.document.CreditMemoDocument) 336 */ 337 @Override 338 public void calculateCreditMemo(VendorCreditMemoDocument cmDocument) { 339 340 cmDocument.updateExtendedPriceOnItems(); 341 342 for (CreditMemoItem item : (List<CreditMemoItem>) cmDocument.getItems()) { 343 // make sure restocking fee is negative 344 if (StringUtils.equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_RESTCK_FEE_CODE, item.getItemTypeCode())) { 345 if (item.getItemUnitPrice() != null) { 346 item.setExtendedPrice(item.getExtendedPrice().abs().negated()); 347 item.setItemUnitPrice(item.getItemUnitPrice().abs().negate()); 348 } 349 } 350 } 351 352 //calculate tax if cm not based on vendor 353 if (cmDocument.isSourceVendor() == false) { 354 purapService.calculateTax(cmDocument); 355 } 356 357 // proration 358 if (cmDocument.isSourceVendor()) { 359 // no proration on vendor 360 return; 361 } 362 363 for (CreditMemoItem item : (List<CreditMemoItem>) cmDocument.getItems()) { 364 365 // skip above the line 366 if (item.getItemType().isLineItemIndicator()) { 367 continue; 368 } 369 370 if ((item.getSourceAccountingLines().isEmpty()) && (ObjectUtils.isNotNull(item.getExtendedPrice())) && (KualiDecimal.ZERO.compareTo(item.getExtendedPrice()) != 0)) { 371 372 KualiDecimal totalAmount = KualiDecimal.ZERO; 373 List<PurApAccountingLine> distributedAccounts = null; 374 List<SourceAccountingLine> summaryAccounts = null; 375 376 totalAmount = cmDocument.getPurApSourceDocumentIfPossible().getTotalDollarAmount(); 377 // this should do nothing on preq which is fine 378 purapAccountingService.updateAccountAmounts(cmDocument.getPurApSourceDocumentIfPossible()); 379 summaryAccounts = purapAccountingService.generateSummary(cmDocument.getPurApSourceDocumentIfPossible().getItems()); 380 distributedAccounts = purapAccountingService.generateAccountDistributionForProration(summaryAccounts, totalAmount, PurapConstants.PRORATION_SCALE, CreditMemoAccount.class); 381 382 if (CollectionUtils.isNotEmpty(distributedAccounts) && CollectionUtils.isEmpty(item.getSourceAccountingLines())) { 383 item.setSourceAccountingLines(distributedAccounts); 384 } 385 } 386 } 387 // end proration 388 } 389 390 /** 391 * @see org.kuali.ole.module.purap.document.service.CreditMemoService#getCreditMemoByDocumentNumber(java.lang.String) 392 */ 393 @Override 394 public VendorCreditMemoDocument getCreditMemoByDocumentNumber(String documentNumber) { 395 LOG.debug("getCreditMemoByDocumentNumber() started"); 396 397 if (ObjectUtils.isNotNull(documentNumber)) { 398 try { 399 VendorCreditMemoDocument doc = (VendorCreditMemoDocument) documentService.getByDocumentHeaderId(documentNumber); 400 return doc; 401 } catch (WorkflowException e) { 402 String errorMessage = "Error getting credit memo document from document service"; 403 LOG.error("getCreditMemoByDocumentNumber() " + errorMessage, e); 404 throw new RuntimeException(errorMessage, e); 405 } 406 } 407 return null; 408 } 409 410 /** 411 * @see org.kuali.ole.module.purap.document.service.CreditMemoService#getCreditMemoDocumentById(java.lang.Integer) 412 */ 413 @Override 414 public VendorCreditMemoDocument getCreditMemoDocumentById(Integer purchasingDocumentIdentifier) { 415 return getCreditMemoByDocumentNumber(creditMemoDao.getDocumentNumberByCreditMemoId(purchasingDocumentIdentifier)); 416 } 417 418 /** 419 * @see org.kuali.ole.module.purap.document.service.CreditMemoService#saveDocument(org.kuali.ole.module.purap.document.CreditMemoDocument) 420 */ 421 @Override 422 public void populateAndSaveCreditMemo(VendorCreditMemoDocument document) { 423 try { 424 // document.setApplicationDocumentStatus(PurapConstants.CreditMemoStatuses.APPDOC_IN_PROCESS); 425 // document.getDocumentHeader().getWorkflowDocument().setApplicationDocumentStatus(PurapConstants.CreditMemoStatuses.APPDOC_IN_PROCESS); 426 document.updateAndSaveAppDocStatus(PurapConstants.CreditMemoStatuses.APPDOC_IN_PROCESS); 427 428 if (document.isSourceDocumentPaymentRequest()) { 429 document.setBankCode(document.getPaymentRequestDocument().getBankCode()); 430 document.setBank(document.getPaymentRequestDocument().getBank()); 431 } else { 432 // set bank code to default bank code in the system parameter 433 Bank defaultBank = SpringContext.getBean(BankService.class).getDefaultBankByDocType(document.getClass()); 434 if (defaultBank != null) { 435 document.setBankCode(defaultBank.getBankCode()); 436 document.setBank(defaultBank); 437 } 438 } 439 440 documentService.saveDocument(document, AttributedContinuePurapEvent.class); 441 } catch (ValidationException ve) { 442 // set the status back to initiate 443 try { 444 document.updateAndSaveAppDocStatus(PurapConstants.CreditMemoStatuses.APPDOC_INITIATE); 445 } catch (WorkflowException workflowException) { 446 447 } 448 } catch (WorkflowException we) { 449 // set the status back to initiate 450 try { 451 document.updateAndSaveAppDocStatus(PurapConstants.CreditMemoStatuses.APPDOC_INITIATE); 452 } catch (WorkflowException workflowException) { 453 454 } 455 String errorMsg = "Error saving document # " + document.getDocumentNumber() + " " + we.getMessage(); 456 LOG.error(errorMsg, we); 457 throw new RuntimeException(errorMsg, we); 458 } 459 } 460 461 /** 462 * @see org.kuali.ole.module.purap.document.service.CreditMemoService#reopenClosedPO(org.kuali.ole.module.purap.document.CreditMemoDocument) 463 */ 464 @Override 465 public void reopenClosedPO(VendorCreditMemoDocument cmDocument) { 466 // reopen PO if closed 467 Integer purchaseOrderDocumentId = cmDocument.getPurchaseOrderIdentifier(); 468 if (cmDocument.isSourceDocumentPaymentRequest() && ObjectUtils.isNull(purchaseOrderDocumentId)) { 469 PaymentRequestDocument paymentRequestDocument = paymentRequestService.getPaymentRequestById(cmDocument.getPaymentRequestIdentifier()); 470 purchaseOrderDocumentId = paymentRequestDocument.getPurchaseOrderIdentifier(); 471 } 472 // if we found a valid po id number then check it for reopening 473 if (ObjectUtils.isNotNull(purchaseOrderDocumentId)) { 474 PurchaseOrderDocument purchaseOrderDocument = purchaseOrderService.getCurrentPurchaseOrder(purchaseOrderDocumentId); 475 // only reopen if the po is not null, it does not have a pending change already scheduled, and it is in closed status 476 if (ObjectUtils.isNotNull(purchaseOrderDocument) && (!purchaseOrderDocument.isPendingActionIndicator()) && PurapConstants.PurchaseOrderStatuses.APPDOC_CLOSED.equals(purchaseOrderDocument.getApplicationDocumentStatus())) { 477 478 } 479 } 480 } 481 482 /** 483 * @see org.kuali.ole.module.purap.document.service.CreditMemoService#addHoldOnPaymentRequest(org.kuali.ole.module.purap.document.CreditMemoDocument, 484 * java.lang.String) 485 */ 486 @Override 487 public VendorCreditMemoDocument addHoldOnCreditMemo(VendorCreditMemoDocument cmDocument, String note) throws Exception { 488 // save the note 489 Note noteObj = documentService.createNoteFromDocument(cmDocument, note); 490 cmDocument.addNote(noteObj); 491 noteService.save(noteObj); 492 493 // retrieve and save with hold indicator set to true 494 VendorCreditMemoDocument cmDoc = getCreditMemoDocumentById(cmDocument.getPurapDocumentIdentifier()); 495 cmDoc.setHoldIndicator(true); 496 cmDoc.setLastActionPerformedByPersonId(GlobalVariables.getUserSession().getPerson().getPrincipalId()); 497 purapService.saveDocumentNoValidation(cmDoc); 498 499 // must also save it on the incoming document 500 cmDocument.setHoldIndicator(true); 501 cmDocument.setLastActionPerformedByPersonId(GlobalVariables.getUserSession().getPerson().getPrincipalId()); 502 503 return cmDoc; 504 } 505 506 /** 507 * @see org.kuali.ole.module.purap.document.service.CreditMemoService#removeHoldOnCreditMemo(org.kuali.ole.module.purap.document.CreditMemoDocument, 508 * java.lang.String) 509 */ 510 @Override 511 public VendorCreditMemoDocument removeHoldOnCreditMemo(VendorCreditMemoDocument cmDocument, String note) throws Exception { 512 // save the note 513 Note noteObj = documentService.createNoteFromDocument(cmDocument, note); 514 cmDocument.addNote(noteObj); 515 noteService.save(noteObj); 516 517 // retrieve and save with hold indicator set to false 518 VendorCreditMemoDocument cmDoc = getCreditMemoDocumentById(cmDocument.getPurapDocumentIdentifier()); 519 cmDoc.setHoldIndicator(false); 520 cmDoc.setLastActionPerformedByPersonId(null); 521 purapService.saveDocumentNoValidation(cmDoc); 522 523 // must also save it on the incoming document 524 cmDocument.setHoldIndicator(false); 525 cmDocument.setLastActionPerformedByPersonId(null); 526 527 return cmDoc; 528 } 529 530 /** 531 * @see org.kuali.ole.module.purap.document.service.AccountsPayableDocumentSpecificService#updateStatusByNode(java.lang.String, org.kuali.ole.module.purap.document.AccountsPayableDocument) 532 */ 533 @Override 534 public String updateStatusByNode(String currentNodeName, AccountsPayableDocument apDoc) { 535 return updateStatusByNode(currentNodeName, (VendorCreditMemoDocument) apDoc); 536 } 537 538 /** 539 * Updates the status of a credit memo document, currently this is used by the cancel action 540 * 541 * @param currentNodeName The string representing the current node to be used to obtain the canceled status code. 542 * @param cmDoc The credit memo document to be updated. 543 * @return The string representing the canceledStatusCode, if empty it is assumed to be not from workflow. 544 */ 545 protected String updateStatusByNode(String currentNodeName, VendorCreditMemoDocument cmDoc) { 546 // update the status on the document 547 548 String cancelledStatusCode = ""; 549 if (StringUtils.isEmpty(currentNodeName)) { 550 cancelledStatusCode = PurapConstants.CreditMemoStatuses.APPDOC_CANCELLED_POST_AP_APPROVE; 551 } else { 552 cancelledStatusCode = CreditMemoStatuses.getCreditMemoAppDocDisapproveStatuses().get(currentNodeName); 553 } 554 555 if (StringUtils.isNotBlank(cancelledStatusCode)) { 556 try { 557 cmDoc.updateAndSaveAppDocStatus(cancelledStatusCode); 558 } catch (WorkflowException we) { 559 throw new RuntimeException("Unable to save the workflow document with document id: " + cmDoc.getDocumentNumber()); 560 } 561 purapService.saveDocumentNoValidation(cmDoc); 562 return cancelledStatusCode; 563 } else { 564 logAndThrowRuntimeException("No status found to set for document being disapproved in node '" + currentNodeName + "'"); 565 } 566 return cancelledStatusCode; 567 } 568 569 /** 570 * @see org.kuali.ole.module.purap.document.service.CreditMemoService#cancelExtractedCreditMemo(org.kuali.ole.module.purap.document.CreditMemoDocument, 571 * java.lang.String) 572 */ 573 @Override 574 public void cancelExtractedCreditMemo(VendorCreditMemoDocument cmDocument, String note) { 575 LOG.debug("cancelExtractedCreditMemo() started"); 576 if (CreditMemoStatuses.CANCELLED_STATUSES.contains(cmDocument.getApplicationDocumentStatus())) { 577 LOG.debug("cancelExtractedCreditMemo() ended"); 578 return; 579 } 580 581 try { 582 Note noteObj = documentService.createNoteFromDocument(cmDocument, note); 583 cmDocument.addNote(noteObj); 584 } catch (Exception e) { 585 throw new RuntimeException(e.getMessage()); 586 } 587 588 accountsPayableService.cancelAccountsPayableDocument(cmDocument, ""); 589 if (LOG.isDebugEnabled()) { 590 LOG.debug("cancelExtractedCreditMemo() CM " + cmDocument.getPurapDocumentIdentifier() + " Cancelled Without Workflow"); 591 } 592 LOG.debug("cancelExtractedCreditMemo() ended"); 593 594 } 595 596 /** 597 * @see org.kuali.ole.module.purap.document.service.CreditMemoService#resetExtractedCreditMemo(org.kuali.ole.module.purap.document.CreditMemoDocument, 598 * java.lang.String) 599 */ 600 @Override 601 public void resetExtractedCreditMemo(VendorCreditMemoDocument cmDocument, String note) { 602 LOG.debug("resetExtractedCreditMemo() started"); 603 if (CreditMemoStatuses.CANCELLED_STATUSES.contains(cmDocument.getApplicationDocumentStatus())) { 604 LOG.debug("resetExtractedCreditMemo() ended"); 605 return; 606 } 607 cmDocument.setExtractedTimestamp(null); 608 cmDocument.setCreditMemoPaidTimestamp(null); 609 610 Note noteObj; 611 try { 612 noteObj = documentService.createNoteFromDocument(cmDocument, note); 613 cmDocument.addNote(noteObj); 614 } catch (Exception e) { 615 throw new RuntimeException(e.getMessage()); 616 } 617 purapService.saveDocumentNoValidation(cmDocument); 618 619 if (LOG.isDebugEnabled()) { 620 LOG.debug("resetExtractedCreditMemo() CM " + cmDocument.getPurapDocumentIdentifier() + " Cancelled Without Workflow"); 621 } 622 LOG.debug("resetExtractedCreditMemo() ended"); 623 } 624 625 /** 626 * @see org.kuali.ole.module.purap.document.service.AccountsPayableDocumentSpecificService#shouldPurchaseOrderBeReversed(org.kuali.ole.module.purap.document.AccountsPayableDocument) 627 */ 628 @Override 629 public boolean shouldPurchaseOrderBeReversed(AccountsPayableDocument apDoc) { 630 // always return false, never reverse 631 return false; 632 } 633 634 /** 635 * @see org.kuali.ole.module.purap.document.service.AccountsPayableDocumentSpecificService#getPersonForCancel(org.kuali.ole.module.purap.document.AccountsPayableDocument) 636 */ 637 @Override 638 public Person getPersonForCancel(AccountsPayableDocument apDoc) { 639 // return null, since superuser is fine for CM 640 return null; 641 } 642 643 /** 644 * @see org.kuali.ole.module.purap.document.service.AccountsPayableDocumentSpecificService#takePurchaseOrderCancelAction(org.kuali.ole.module.purap.document.AccountsPayableDocument) 645 */ 646 @Override 647 public void takePurchaseOrderCancelAction(AccountsPayableDocument apDoc) { 648 VendorCreditMemoDocument cmDocument = (VendorCreditMemoDocument) apDoc; 649 if (cmDocument.isReopenPurchaseOrderIndicator()) { 650 String docType = PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_CLOSE_DOCUMENT; 651 purchaseOrderService.createAndRoutePotentialChangeDocument(cmDocument.getPurchaseOrderDocument().getDocumentNumber(), docType, "reopened by Payment Request " + apDoc.getPurapDocumentIdentifier() + "cancel", new ArrayList(), PurapConstants.PurchaseOrderStatuses.APPDOC_PENDING_CLOSE); 652 } 653 } 654 655 /** 656 * @see org.kuali.ole.module.purap.document.service.CreditMemoService#markPaid(org.kuali.ole.module.purap.document.CreditMemoDocument, 657 * java.sql.Date) 658 */ 659 @Override 660 public void markPaid(VendorCreditMemoDocument cm, Date processDate) { 661 LOG.debug("markPaid() started"); 662 663 cm.setCreditMemoPaidTimestamp(new Timestamp(processDate.getTime())); 664 purapService.saveDocumentNoValidation(cm); 665 } 666 667 /** 668 * @see org.kuali.ole.module.purap.document.service.AccountsPayableDocumentSpecificService#poItemEligibleForAp(org.kuali.ole.module.purap.document.AccountsPayableDocument, org.kuali.ole.module.purap.businessobject.PurchaseOrderItem) 669 */ 670 @Override 671 public boolean poItemEligibleForAp(AccountsPayableDocument apDoc, PurchaseOrderItem poItem) { 672 // if the po item is not active... skip it 673 if (!poItem.isItemActiveIndicator()) { 674 return false; 675 } 676 677 if (poItem.getItemType().isQuantityBasedGeneralLedgerIndicator() && poItem.getItemInvoicedTotalQuantity().isGreaterThan(KualiDecimal.ZERO)) { 678 return true; 679 } else { 680 BigDecimal unitPrice = (poItem.getItemUnitPrice() == null ? new BigDecimal(0) : poItem.getItemUnitPrice()); 681 if (unitPrice.doubleValue() > poItem.getItemOutstandingEncumberedAmount().doubleValue()) { 682 return true; 683 } 684 } 685 return false; 686 } 687 688 /** 689 * The given document here needs to be a Credit Memo. 690 * 691 * @see org.kuali.ole.module.purap.document.service.AccountsPayableDocumentSpecificService#generateGLEntriesCreateAccountsPayableDocument(org.kuali.ole.module.purap.document.AccountsPayableDocument) 692 */ 693 @Override 694 public void generateGLEntriesCreateAccountsPayableDocument(AccountsPayableDocument apDocument) { 695 VendorCreditMemoDocument creditMemo = (VendorCreditMemoDocument) apDocument; 696 purapGeneralLedgerService.generateEntriesCreateCreditMemo(creditMemo); 697 } 698 699 /** 700 * Records the specified error message into the Log file and throws a runtime exception. 701 * 702 * @param errorMessage the error message to be logged. 703 */ 704 protected void logAndThrowRuntimeException(String errorMessage) { 705 this.logAndThrowRuntimeException(errorMessage, null); 706 } 707 708 /** 709 * Records the specified error message into the Log file and throws the specified runtime exception. 710 * 711 * @param errorMessage the specified error message. 712 * @param e the specified runtime exception. 713 */ 714 protected void logAndThrowRuntimeException(String errorMessage, Exception e) { 715 if (ObjectUtils.isNotNull(e)) { 716 LOG.error(errorMessage, e); 717 throw new RuntimeException(errorMessage, e); 718 } else { 719 LOG.error(errorMessage); 720 throw new RuntimeException(errorMessage); 721 } 722 } 723 724 /** 725 * @see org.kuali.ole.module.purap.document.service.CreditMemoService#hasActiveCreditMemosForPurchaseOrder(java.lang.Integer) 726 */ 727 @Override 728 public boolean hasActiveCreditMemosForPurchaseOrder(Integer purchaseOrderIdentifier) { 729 730 boolean hasActiveCreditMemos = false; 731 List<String> docNumbers = null; 732 WorkflowDocument workflowDocument = null; 733 734 docNumbers = creditMemoDao.getActiveCreditMemoDocumentNumbersForPurchaseOrder(purchaseOrderIdentifier); 735 docNumbers = filterCreditMemoByAppDocStatus(docNumbers, CreditMemoStatuses.STATUSES_POTENTIALLY_ACTIVE); 736 737 for (String docNumber : docNumbers) { 738 try { 739 workflowDocument = workflowDocumentService.loadWorkflowDocument(docNumber, GlobalVariables.getUserSession().getPerson()); 740 } catch (WorkflowException we) { 741 throw new RuntimeException(we); 742 } 743 744 //if the document is not in a non-active status then return true and stop evaluation 745 if (!(workflowDocument.isCanceled() || 746 workflowDocument.isException() || 747 workflowDocument.isFinal())) { 748 hasActiveCreditMemos = true; 749 break; 750 } 751 752 } 753 754 return hasActiveCreditMemos; 755 } 756 757 /** 758 * @see org.kuali.ole.module.purap.document.service.CreditMemoCreateService#populateDocumentAfterInit(org.kuali.ole.module.purap.document.CreditMemoDocument) 759 */ 760 @Override 761 public void populateDocumentAfterInit(VendorCreditMemoDocument cmDocument) { 762 763 OleVendorCreditMemoDocument vendorCreditMemoDocument = (OleVendorCreditMemoDocument) cmDocument; 764 // make a call to search for expired/closed accounts 765 HashMap<String, ExpiredOrClosedAccountEntry> expiredOrClosedAccountList = accountsPayableService.getExpiredOrClosedAccountList(cmDocument); 766 767 if (vendorCreditMemoDocument.isSourceDocumentPaymentRequest() && vendorCreditMemoDocument.getInvoiceIdentifier() == null) { 768 populateDocumentFromPreq(vendorCreditMemoDocument, expiredOrClosedAccountList); 769 } else if (vendorCreditMemoDocument.isSourceDocumentPurchaseOrder() && vendorCreditMemoDocument.getInvoiceIdentifier() == null) { 770 populateDocumentFromPO(vendorCreditMemoDocument, expiredOrClosedAccountList); 771 } else if (vendorCreditMemoDocument.getInvoiceIdentifier() != null) { 772 populateDocumentFromVendor(vendorCreditMemoDocument); 773 } 774 775 populateDocumentDescription(vendorCreditMemoDocument); 776 777 // write a note for expired/closed accounts if any exist and add a message stating there were expired/closed accounts at the 778 // top of the document 779 accountsPayableService.generateExpiredOrClosedAccountNote(cmDocument, expiredOrClosedAccountList); 780 781 // set indicator so a message is displayed for accounts that were replaced due to expired/closed status 782 if (ObjectUtils.isNotNull(expiredOrClosedAccountList) && !expiredOrClosedAccountList.isEmpty()) { 783 cmDocument.setContinuationAccountIndicator(true); 784 } 785 786 } 787 788 /** 789 * Populate Credit Memo of type Payment Request. 790 * 791 * @param cmDocument - Credit Memo Document to Populate 792 */ 793 protected void populateDocumentFromPreq(VendorCreditMemoDocument cmDocument, HashMap<String, ExpiredOrClosedAccountEntry> expiredOrClosedAccountList) { 794 PaymentRequestDocument paymentRequestDocument = paymentRequestService.getPaymentRequestById(cmDocument.getPaymentRequestIdentifier()); 795 cmDocument.getDocumentHeader().setOrganizationDocumentNumber(paymentRequestDocument.getDocumentHeader().getOrganizationDocumentNumber()); 796 cmDocument.setPaymentRequestDocument(paymentRequestDocument); 797 cmDocument.setPurchaseOrderDocument(paymentRequestDocument.getPurchaseOrderDocument()); 798 cmDocument.setUseTaxIndicator(paymentRequestDocument.isUseTaxIndicator()); 799 800 // credit memo address taken directly from payment request 801 cmDocument.setVendorHeaderGeneratedIdentifier(paymentRequestDocument.getVendorHeaderGeneratedIdentifier()); 802 cmDocument.setVendorDetailAssignedIdentifier(paymentRequestDocument.getVendorDetailAssignedIdentifier()); 803 cmDocument.setVendorAddressGeneratedIdentifier(paymentRequestDocument.getVendorAddressGeneratedIdentifier()); 804 cmDocument.setVendorCustomerNumber(paymentRequestDocument.getVendorCustomerNumber()); 805 cmDocument.setVendorName(paymentRequestDocument.getVendorName()); 806 cmDocument.setVendorLine1Address(paymentRequestDocument.getVendorLine1Address()); 807 cmDocument.setVendorLine2Address(paymentRequestDocument.getVendorLine2Address()); 808 cmDocument.setVendorCityName(paymentRequestDocument.getVendorCityName()); 809 cmDocument.setVendorStateCode(paymentRequestDocument.getVendorStateCode()); 810 cmDocument.setVendorPostalCode(paymentRequestDocument.getVendorPostalCode()); 811 cmDocument.setVendorCountryCode(paymentRequestDocument.getVendorCountryCode()); 812 cmDocument.setVendorAttentionName(paymentRequestDocument.getVendorAttentionName()); 813 cmDocument.setAccountsPayablePurchasingDocumentLinkIdentifier(paymentRequestDocument.getAccountsPayablePurchasingDocumentLinkIdentifier()); 814 cmDocument.setPaymentMethodId(paymentRequestDocument.getVendorDetail().getPaymentMethodId()); 815 // prep the item lines (also collect warnings for later display) this is only done on paymentRequest 816 purapAccountingService.convertMoneyToPercent(paymentRequestDocument); 817 populateItemLinesFromPreq(cmDocument, expiredOrClosedAccountList); 818 } 819 820 /** 821 * Populates the credit memo items from the payment request items. 822 * 823 * @param cmDocument - Credit Memo Document to Populate 824 */ 825 protected void populateItemLinesFromPreq(VendorCreditMemoDocument cmDocument, HashMap<String, ExpiredOrClosedAccountEntry> expiredOrClosedAccountList) { 826 PaymentRequestDocument preqDocument = cmDocument.getPaymentRequestDocument(); 827 828 for (PaymentRequestItem preqItemToTemplate : (List<PaymentRequestItem>) preqDocument.getItems()) { 829 preqItemToTemplate.refreshReferenceObject(PurapPropertyConstants.ITEM_TYPE); 830 831 if (preqItemToTemplate.getItemType().isLineItemIndicator() && ((preqItemToTemplate.getItemType().isQuantityBasedGeneralLedgerIndicator() && preqItemToTemplate.getItemQuantity().isNonZero()) 832 || (preqItemToTemplate.getItemType().isAmountBasedGeneralLedgerIndicator() && preqItemToTemplate.getTotalAmount().isNonZero()))) { 833 cmDocument.getItems().add(new CreditMemoItem(cmDocument, preqItemToTemplate, preqItemToTemplate.getPurchaseOrderItem(), expiredOrClosedAccountList)); 834 } 835 } 836 837 // add below the line items 838 purapService.addBelowLineItems(cmDocument); 839 840 cmDocument.fixItemReferences(); 841 } 842 843 /** 844 * Populate Credit Memo of type Purchase Order. 845 * 846 * @param cmDocument - Credit Memo Document to Populate 847 */ 848 protected void populateDocumentFromPO(VendorCreditMemoDocument cmDocument, HashMap<String, ExpiredOrClosedAccountEntry> expiredOrClosedAccountList) { 849 PurchaseOrderDocument purchaseOrderDocument = purchaseOrderService.getCurrentPurchaseOrder(cmDocument.getPurchaseOrderIdentifier()); 850 cmDocument.setPurchaseOrderDocument(purchaseOrderDocument); 851 cmDocument.getDocumentHeader().setOrganizationDocumentNumber(purchaseOrderDocument.getDocumentHeader().getOrganizationDocumentNumber()); 852 cmDocument.setUseTaxIndicator(cmDocument.isUseTaxIndicator()); 853 854 cmDocument.setVendorHeaderGeneratedIdentifier(purchaseOrderDocument.getVendorHeaderGeneratedIdentifier()); 855 cmDocument.setVendorDetailAssignedIdentifier(purchaseOrderDocument.getVendorDetailAssignedIdentifier()); 856 cmDocument.setVendorCustomerNumber(purchaseOrderDocument.getVendorCustomerNumber()); 857 cmDocument.setVendorName(purchaseOrderDocument.getVendorName()); 858 cmDocument.setAccountsPayablePurchasingDocumentLinkIdentifier(purchaseOrderDocument.getAccountsPayablePurchasingDocumentLinkIdentifier()); 859 cmDocument.setPaymentMethodId(purchaseOrderDocument.getVendorDetail().getPaymentMethodId()); 860 // populate cm vendor address with the default remit address type for the vendor if found 861 String userCampus = GlobalVariables.getUserSession().getPerson().getCampusCode(); 862 VendorAddress vendorAddress = vendorService.getVendorDefaultAddress(purchaseOrderDocument.getVendorHeaderGeneratedIdentifier(), purchaseOrderDocument.getVendorDetailAssignedIdentifier(), VendorConstants.AddressTypes.REMIT, userCampus); 863 if (vendorAddress != null) { 864 cmDocument.templateVendorAddress(vendorAddress); 865 cmDocument.setVendorAddressGeneratedIdentifier(vendorAddress.getVendorAddressGeneratedIdentifier()); 866 cmDocument.setVendorAttentionName(StringUtils.defaultString(vendorAddress.getVendorAttentionName())); 867 } else { 868 // set address from PO 869 cmDocument.setVendorAddressGeneratedIdentifier(purchaseOrderDocument.getVendorAddressGeneratedIdentifier()); 870 cmDocument.setVendorLine1Address(purchaseOrderDocument.getVendorLine1Address()); 871 cmDocument.setVendorLine2Address(purchaseOrderDocument.getVendorLine2Address()); 872 cmDocument.setVendorCityName(purchaseOrderDocument.getVendorCityName()); 873 cmDocument.setVendorStateCode(purchaseOrderDocument.getVendorStateCode()); 874 cmDocument.setVendorPostalCode(purchaseOrderDocument.getVendorPostalCode()); 875 cmDocument.setVendorCountryCode(purchaseOrderDocument.getVendorCountryCode()); 876 877 boolean blankAttentionLine = StringUtils.equalsIgnoreCase("Y", SpringContext.getBean(ParameterService.class).getParameterValueAsString(PurapConstants.PURAP_NAMESPACE, "Document", PurapParameterConstants.BLANK_ATTENTION_LINE_FOR_PO_TYPE_ADDRESS)); 878 if (blankAttentionLine) { 879 cmDocument.setVendorAttentionName(StringUtils.EMPTY); 880 } else { 881 cmDocument.setVendorAttentionName(StringUtils.defaultString(purchaseOrderDocument.getVendorAttentionName())); 882 } 883 } 884 885 populateItemLinesFromPO(cmDocument, expiredOrClosedAccountList); 886 } 887 888 /** 889 * Populates the credit memo items from the payment request items. 890 * 891 * @param cmDocument - Credit Memo Document to Populate 892 */ 893 protected void populateItemLinesFromPO(VendorCreditMemoDocument cmDocument, HashMap<String, ExpiredOrClosedAccountEntry> expiredOrClosedAccountList) { 894 List<PurchaseOrderItem> invoicedItems = getPOInvoicedItems(cmDocument.getPurchaseOrderDocument()); 895 for (PurchaseOrderItem poItem : invoicedItems) { 896 if ((poItem.getItemType().isQuantityBasedGeneralLedgerIndicator() && poItem.getItemInvoicedTotalQuantity().isNonZero()) 897 || (poItem.getItemType().isAmountBasedGeneralLedgerIndicator() && poItem.getItemInvoicedTotalAmount().isNonZero())) { 898 CreditMemoItem creditMemoItem = new CreditMemoItem(cmDocument, poItem, expiredOrClosedAccountList); 899 cmDocument.getItems().add(creditMemoItem); 900 PurchasingCapitalAssetItem purchasingCAMSItem = cmDocument.getPurchaseOrderDocument().getPurchasingCapitalAssetItemByItemIdentifier(poItem.getItemIdentifier()); 901 if (purchasingCAMSItem != null) { 902 creditMemoItem.setCapitalAssetTransactionTypeCode(purchasingCAMSItem.getCapitalAssetTransactionTypeCode()); 903 } 904 } 905 } 906 907 // add below the line items 908 purapService.addBelowLineItems(cmDocument); 909 910 cmDocument.fixItemReferences(); 911 } 912 913 /** 914 * Populate Credit Memo of type Vendor. 915 * 916 * @param cmDocument - Credit Memo Document to Populate 917 */ 918 protected void populateDocumentFromVendor(VendorCreditMemoDocument cmDocument) { 919 Integer vendorHeaderId = VendorUtils.getVendorHeaderId(cmDocument.getVendorNumber()); 920 Integer vendorDetailId = VendorUtils.getVendorDetailId(cmDocument.getVendorNumber()); 921 922 VendorDetail vendorDetail = vendorService.getVendorDetail(vendorHeaderId, vendorDetailId); 923 cmDocument.setVendorDetail(vendorDetail); 924 925 cmDocument.setVendorHeaderGeneratedIdentifier(vendorDetail.getVendorHeaderGeneratedIdentifier()); 926 cmDocument.setVendorDetailAssignedIdentifier(vendorDetail.getVendorDetailAssignedIdentifier()); 927 cmDocument.setVendorCustomerNumber(vendorDetail.getVendorNumber()); 928 cmDocument.setVendorName(vendorDetail.getVendorName()); 929 cmDocument.setPaymentMethodId(vendorDetail.getPaymentMethodId()); 930 931 // credit memo type vendor uses the default remit type address for the vendor if found 932 String userCampus = GlobalVariables.getUserSession().getPerson().getCampusCode(); 933 VendorAddress vendorAddress = vendorService.getVendorDefaultAddress(vendorHeaderId, vendorDetailId, VendorConstants.AddressTypes.REMIT, userCampus); 934 if (vendorAddress == null) { 935 // pick up the default vendor po address type 936 vendorAddress = vendorService.getVendorDefaultAddress(vendorHeaderId, vendorDetailId, VendorConstants.AddressTypes.PURCHASE_ORDER, userCampus); 937 } 938 939 cmDocument.setVendorAddressGeneratedIdentifier(vendorAddress.getVendorAddressGeneratedIdentifier()); 940 cmDocument.templateVendorAddress(vendorAddress); 941 942 // add below the line items 943 purapService.addBelowLineItems(cmDocument); 944 } 945 946 /** 947 * Defaults the document description based on the credit memo source type. 948 * 949 * @param cmDocument - Credit Memo Document to Populate 950 */ 951 protected void populateDocumentDescription(VendorCreditMemoDocument cmDocument) { 952 String description = ""; 953 if (cmDocument.isSourceVendor()) { 954 description = "Vendor: " + cmDocument.getVendorName(); 955 } else { 956 description = "PO: " + cmDocument.getPurchaseOrderDocument().getPurapDocumentIdentifier() + " Vendor: " + cmDocument.getVendorName(); 957 } 958 959 // trim description if longer than whats specified in the data dictionary 960 int noteTextMaxLength = dataDictionaryService.getAttributeMaxLength(DocumentHeader.class, KRADPropertyConstants.DOCUMENT_DESCRIPTION).intValue(); 961 if (noteTextMaxLength < description.length()) { 962 description = description.substring(0, noteTextMaxLength); 963 } 964 965 cmDocument.getDocumentHeader().setDocumentDescription(description); 966 } 967 968} 969