001 /* 002 * Copyright 2011 The Kuali Foundation. 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.kuali.kfs.module.ar.businessobject; 017 018 import java.math.BigDecimal; 019 import java.sql.Date; 020 import java.util.ArrayList; 021 import java.util.HashMap; 022 import java.util.LinkedHashMap; 023 import java.util.List; 024 import java.util.Map; 025 026 import org.apache.commons.lang.StringUtils; 027 import org.apache.log4j.Logger; 028 import org.kuali.kfs.coa.businessobject.ObjectCode; 029 import org.kuali.kfs.coa.businessobject.SubObjectCode; 030 import org.kuali.kfs.module.ar.document.CustomerInvoiceDocument; 031 import org.kuali.kfs.module.ar.document.service.CustomerInvoiceWriteoffDocumentService; 032 import org.kuali.kfs.sys.KFSConstants; 033 import org.kuali.kfs.sys.businessobject.SourceAccountingLine; 034 import org.kuali.kfs.sys.businessobject.UnitOfMeasure; 035 import org.kuali.kfs.sys.context.SpringContext; 036 import org.kuali.rice.kew.exception.WorkflowException; 037 import org.kuali.rice.kns.service.BusinessObjectService; 038 import org.kuali.rice.kns.service.DocumentService; 039 import org.kuali.rice.kns.util.KualiDecimal; 040 import org.kuali.rice.kns.util.ObjectUtils; 041 042 /** 043 * This class represents a customer invoice detail on the customer invoice document. This class extends SourceAccountingLine since 044 * each customer invoice detail has associated accounting line information. 045 * 046 * @author Kuali Nervous System Team (kualidev@oncourse.iu.edu) 047 */ 048 public class CustomerInvoiceDetail extends SourceAccountingLine implements AppliedPayment { 049 private static Logger LOG = Logger.getLogger(CustomerInvoiceDetail.class); 050 051 // private Integer invoiceItemNumber; using SourceAccountingLine.sequenceNumber 052 private BigDecimal invoiceItemQuantity; 053 private BigDecimal invoiceItemUnitPrice; 054 // private KualiDecimal invoiceItemTotalAmount; using SourceAccountingLine.amount for now 055 private Date invoiceItemServiceDate; 056 private String invoiceItemCode; 057 private String invoiceItemDescription; 058 private String accountsReceivableObjectCode; 059 private String accountsReceivableSubObjectCode; 060 private KualiDecimal invoiceItemTaxAmount; 061 private boolean taxableIndicator; 062 private boolean isDebit; 063 private Integer invoiceItemDiscountLineNumber; 064 065 private String invoiceItemUnitOfMeasureCode; 066 private UnitOfMeasure unitOfMeasure; 067 068 private SubObjectCode accountsReceivableSubObject; 069 private ObjectCode accountsReceivableObject; 070 071 private transient CustomerInvoiceDocument customerInvoiceDocument; 072 private transient CustomerInvoiceDetail parentDiscountCustomerInvoiceDetail; 073 private transient CustomerInvoiceDetail discountCustomerInvoiceDetail; 074 075 // fields used for CustomerInvoiceWriteoffDocument 076 private KualiDecimal writeoffAmount; 077 private String customerInvoiceWriteoffDocumentNumber; 078 079 /** 080 * Default constructor. 081 */ 082 public CustomerInvoiceDetail() { 083 super(); 084 invoiceItemTaxAmount = KualiDecimal.ZERO; 085 } 086 087 // ---- BEGIN OPEN AMOUNTS 088 089 public KualiDecimal getAmountOpen() { 090 091 // if the parent isnt saved, or if its saved but not approved, we 092 // need to include the discounts. If its both saved AND approved, 093 // we do not include the discounts. 094 boolean includeDiscounts = !(isParentSaved() && isParentApproved()); 095 096 KualiDecimal amount = getAmount(); 097 KualiDecimal applied = getAmountApplied(); 098 KualiDecimal a = amount.subtract(applied); 099 100 if (includeDiscounts) { 101 CustomerInvoiceDetail discount = getDiscountCustomerInvoiceDetail(); 102 if (ObjectUtils.isNotNull(discount)) { 103 a = a.add(discount.getAmount()); 104 } 105 } 106 return a; 107 } 108 109 private boolean isParentSaved() { 110 return getCustomerInvoiceDocument() != null; 111 } 112 113 private boolean isParentApproved() { 114 if (getCustomerInvoiceDocument() == null) { 115 return false; 116 } 117 return KFSConstants.DocumentStatusCodes.APPROVED.equalsIgnoreCase(getCustomerInvoiceDocument().getDocumentHeader().getFinancialDocumentStatusCode()); 118 } 119 120 //TODO Andrew 121 // @Deprecated 122 // private KualiDecimal getAmountOpenFromDatabaseNoDiscounts() { 123 // KualiDecimal amount = getAmount(); 124 // KualiDecimal applied = getAmountAppliedFromDatabase(); 125 // KualiDecimal a = amount.subtract(applied); 126 // return a; 127 // } 128 // 129 // @Deprecated 130 // private KualiDecimal getAmountOpenFromDatabaseDiscounted() { 131 // KualiDecimal amount = getAmount(); 132 // KualiDecimal applied = getAmountAppliedFromDatabase(); 133 // KualiDecimal a = amount.subtract(applied); 134 // CustomerInvoiceDetail discount = getDiscountCustomerInvoiceDetail(); 135 // if (ObjectUtils.isNotNull(discount)) { 136 // a = a.add(discount.getAmount()); 137 // } 138 // return a; 139 // } 140 141 //TODO Andrew 142 //public KualiDecimal getAmountOpenExcludingAnyAmountFromCurrentPaymentApplicationDocument() { 143 // return getAmountOpenExcludingAnyAmountFrom(getCurrentPaymentApplicationDocument()); 144 //} 145 146 /** 147 * 148 * Retrieves the discounted amount. This is the amount minues any 149 * discounts that might exist. If no discount exists, then it 150 * just returns the amount. 151 * 152 * NOTE this does not subtract PaidApplieds, only discounts. 153 * 154 * @return 155 */ 156 //PAYAPP 157 public KualiDecimal getAmountDiscounted() { 158 KualiDecimal a = getAmount(); 159 CustomerInvoiceDetail discount = getDiscountCustomerInvoiceDetail(); 160 if(ObjectUtils.isNotNull(discount)) { 161 KualiDecimal d = discount.getAmount(); 162 a = a.add(d); 163 } 164 return a; 165 } 166 167 //TODO Andrew 168 // public KualiDecimal getAmountOpenExcludingAnyAmountFrom(PaymentApplicationDocument paymentApplicationDocument) { 169 // return getAmountDiscounted().subtract(getAmountAppliedExcludingAnyAmountAppliedBy(paymentApplicationDocument)); 170 // } 171 // 172 // public KualiDecimal getAmountOpenPerCurrentPaymentApplicationDocument() { 173 // return getAmountDiscounted().subtract(getAmountAppliedByCurrentPaymentApplicationDocument()); 174 // } 175 176 /** 177 * This method returns the amount that remained unapplied on a given date. 178 * 179 * @param date 180 * @return 181 */ 182 public KualiDecimal getAmountOpenByDateFromDatabase(java.sql.Date date) { 183 return getAmountOpen(); 184 //TODO Andrew - need to fix this to actually respect the dates 185 //return getAmountOpenByDateFromDatabaseExcludingAnyAmountAppliedByPaymentApplicationDocument(date, null); 186 } 187 188 public KualiDecimal getAmountOpenByDateFromDatabase(java.util.Date date) { 189 return getAmountOpen(); 190 //TODO Andrew - need to fix this to actually respect the dates 191 //return getAmountOpenByDateFromDatabaseExcludingAnyAmountAppliedByPaymentApplicationDocument(new java.sql.Date(date.getTime()),null); 192 } 193 194 //TODO Andrew 195 // public KualiDecimal getAmountOpenByDateFromDatabaseExcludingAnyAmountAppliedByPaymentApplicationDocument(java.sql.Date date, PaymentApplicationDocument paymentApplicationDocument) { 196 // BusinessObjectService businessObjectService = SpringContext.getBean(BusinessObjectService.class); 197 // 198 // // Lookup all applied payments as of the given date 199 // Map<String,Object> criteria = new HashMap<String,Object>(); 200 // criteria.put("invoiceItemNumber", getSequenceNumber()); 201 // criteria.put("financialDocumentReferenceInvoiceNumber", getDocumentNumber()); 202 // criteria.put("documentHeader.financialDocumentStatusCode", KFSConstants.DocumentStatusCodes.APPROVED); 203 // Collection<InvoicePaidApplied> invoicePaidAppliedsAsOfDate = businessObjectService.findMatching(InvoicePaidApplied.class, criteria); 204 // 205 // KualiDecimal totalAppliedAmount = new KualiDecimal(0); 206 // KualiDecimal appliedAmount = new KualiDecimal(0); 207 // for (InvoicePaidApplied invoicePaidApplied : invoicePaidAppliedsAsOfDate) { 208 // appliedAmount = invoicePaidApplied.getInvoiceItemAppliedAmount(); 209 // Date invoicePaidDate = invoicePaidApplied.getDocumentHeader().getDocumentFinalDate(); 210 // // get the paid date and use that to limit the adds from below 211 // if (ObjectUtils.isNotNull(appliedAmount)&&!invoicePaidDate.after(date)) { 212 // if(null != paymentApplicationDocument) { 213 // if(!invoicePaidApplied.getDocumentNumber().equals(paymentApplicationDocument.getDocumentNumber())) { 214 // totalAppliedAmount = totalAppliedAmount.add(appliedAmount); 215 // } 216 // } else { 217 // totalAppliedAmount = totalAppliedAmount.add(appliedAmount); 218 // } 219 // } 220 // } 221 // 222 // return getAmount().subtract(totalAppliedAmount); 223 // } 224 // 225 // public KualiDecimal getAmountOpenByDateFromDatabaseExcludingAnyAmountAppliedByPaymentApplicationDocument(java.util.Date date, PaymentApplicationDocument paymentApplicationDocument) { 226 // return getAmountOpenByDateFromDatabaseExcludingAnyAmountAppliedByPaymentApplicationDocument(new java.sql.Date(date.getTime()),paymentApplicationDocument); 227 // } 228 229 // ---- END OPEN AMOUNTS 230 231 // ---- BEGIN APPLIED AMOUNTS 232 public KualiDecimal getAmountApplied() { 233 List<InvoicePaidApplied> invoicePaidApplieds = null; 234 invoicePaidApplieds = getMatchingInvoicePaidAppliedsMatchingAnyDocumentFromDatabase(); 235 KualiDecimal appliedAmount = new KualiDecimal(0); 236 for(InvoicePaidApplied invoicePaidApplied : invoicePaidApplieds) { 237 appliedAmount = appliedAmount.add(invoicePaidApplied.getInvoiceItemAppliedAmount()); 238 } 239 return appliedAmount; 240 } 241 242 //TODO Andrew 243 // /** 244 // * @return the applied amount by getting it from the matching invoice paid applied 245 // */ 246 // public KualiDecimal getAmountAppliedFromDatabase() { 247 // return getAmountAppliedBy(null); 248 // } 249 // 250 // /** 251 // * This method is a convenience method used from the Struts form on the payment application document screen. 252 // * @return 253 // */ 254 // public KualiDecimal getAmountAppliedByCurrentPaymentApplicationDocument() { 255 // return getAmountAppliedBy(getCurrentPaymentApplicationDocument()); 256 // } 257 // 258 /** 259 * @param paymentApplicationDocument 260 * @return 261 */ 262 public KualiDecimal getAmountAppliedBy(String documentNumber) { 263 List<InvoicePaidApplied> invoicePaidApplieds = null; 264 if (StringUtils.isBlank(documentNumber)) { 265 invoicePaidApplieds = getMatchingInvoicePaidAppliedsMatchingAnyDocumentFromDatabase(); 266 } else { 267 invoicePaidApplieds = getMatchingInvoicePaidAppliedsMatchingDocument(documentNumber); 268 } 269 KualiDecimal appliedAmount = new KualiDecimal(0); 270 for(InvoicePaidApplied invoicePaidApplied : invoicePaidApplieds) { 271 appliedAmount = appliedAmount.add(invoicePaidApplied.getInvoiceItemAppliedAmount()); 272 } 273 return appliedAmount; 274 } 275 276 /** 277 * @param paymentApplicationDocument 278 * @return the sum of applied amounts according to the database, excluding any amounts applied by paymentApplicationDocument 279 */ 280 public KualiDecimal getAmountAppliedExcludingAnyAmountAppliedBy(String documentNumber) { 281 List<InvoicePaidApplied> invoicePaidApplieds = getMatchingInvoicePaidAppliedsMatchingAnyDocumentFromDatabase(); 282 KualiDecimal appliedAmount = new KualiDecimal(0); 283 for (InvoicePaidApplied invoicePaidApplied : invoicePaidApplieds) { 284 // Exclude any amounts applied by paymentApplicationDocument 285 if (StringUtils.isNotBlank(documentNumber)) { 286 } 287 if (StringUtils.isBlank(documentNumber) || !documentNumber.equalsIgnoreCase(invoicePaidApplied.getDocumentNumber())) { 288 appliedAmount = appliedAmount.add(invoicePaidApplied.getInvoiceItemAppliedAmount()); 289 } 290 } 291 return appliedAmount; 292 } 293 294 // ---- END APPLIED AMOUNTS 295 296 /** 297 * This method returns the writeoff amount. If writeoff document hasn't been approved yet, display the open amount. Else display 298 * the amount applied from the specific approved writeoff document. 299 * 300 * @param customerInvoiceWriteoffDocumentNumber 301 * @return 302 */ 303 public KualiDecimal getWriteoffAmount() { 304 if (SpringContext.getBean(CustomerInvoiceWriteoffDocumentService.class).isCustomerInvoiceWriteoffDocumentApproved(customerInvoiceWriteoffDocumentNumber)) { 305 //TODO this probably isnt right ... in the case of discounts and/or credit 306 // memos, the getAmount() isnt the amount that the writeoff document will have 307 // written off 308 return super.getAmount(); // using the accounting line amount ... see comments at top of class 309 } 310 else { 311 return getAmountOpen(); 312 } 313 } 314 315 /** 316 * This method returns the invoice pre tax amount 317 * 318 * @return 319 */ 320 public KualiDecimal getInvoiceItemPreTaxAmount() { 321 if (ObjectUtils.isNotNull(invoiceItemUnitPrice) && ObjectUtils.isNotNull(invoiceItemQuantity)) { 322 BigDecimal bd = invoiceItemUnitPrice.multiply(invoiceItemQuantity); 323 bd = bd.setScale(KualiDecimal.SCALE, KualiDecimal.ROUND_BEHAVIOR); 324 return new KualiDecimal(bd); 325 } else { 326 return KualiDecimal.ZERO; 327 } 328 } 329 330 /** 331 * Gets the accountsReceivableObjectCode attribute. 332 * 333 * @return Returns the accountsReceivableObjectCode 334 */ 335 public String getAccountsReceivableObjectCode() { 336 return accountsReceivableObjectCode; 337 } 338 339 /** 340 * Sets the accountsReceivableObjectCode attribute. 341 * 342 * @param accountsReceivableObjectCode The accountsReceivableObjectCode to set. 343 */ 344 public void setAccountsReceivableObjectCode(String accountsReceivableObjectCode) { 345 this.accountsReceivableObjectCode = accountsReceivableObjectCode; 346 } 347 348 /** 349 * Gets the accountsReceivableSubObjectCode attribute. 350 * 351 * @return Returns the accountsReceivableSubObjectCode 352 */ 353 public String getAccountsReceivableSubObjectCode() { 354 return accountsReceivableSubObjectCode; 355 } 356 357 /** 358 * Sets the accountsReceivableSubObjectCode attribute. 359 * 360 * @param accountsReceivableSubObjectCode The accountsReceivableSubObjectCode to set. 361 */ 362 public void setAccountsReceivableSubObjectCode(String accountsReceivableSubObjectCode) { 363 this.accountsReceivableSubObjectCode = accountsReceivableSubObjectCode; 364 } 365 366 /** 367 * Gets the invoiceItemQuantity attribute. 368 * 369 * @return Returns the invoiceItemQuantity 370 */ 371 public BigDecimal getInvoiceItemQuantity() { 372 return invoiceItemQuantity; 373 } 374 375 /** 376 * Sets the invoiceItemQuantity attribute. 377 * 378 * @param invoiceItemQuantity The invoiceItemQuantity to set. 379 */ 380 public void setInvoiceItemQuantity(BigDecimal invoiceItemQuantity) { 381 this.invoiceItemQuantity = invoiceItemQuantity; 382 } 383 384 /** 385 * Gets the invoiceItemUnitOfMeasureCode attribute. 386 * 387 * @return Returns the invoiceItemUnitOfMeasureCode 388 */ 389 public String getInvoiceItemUnitOfMeasureCode() { 390 return invoiceItemUnitOfMeasureCode; 391 } 392 393 /** 394 * Sets the invoiceItemUnitOfMeasureCode attribute. 395 * 396 * @param invoiceItemUnitOfMeasureCode The invoiceItemUnitOfMeasureCode to set. 397 */ 398 public void setInvoiceItemUnitOfMeasureCode(String invoiceItemUnitOfMeasureCode) { 399 this.invoiceItemUnitOfMeasureCode = invoiceItemUnitOfMeasureCode; 400 } 401 402 /** 403 * Gets the invoiceItemUnitPrice attribute. 404 * 405 * @return Returns the invoiceItemUnitPrice 406 */ 407 public BigDecimal getInvoiceItemUnitPrice() { 408 return invoiceItemUnitPrice; 409 } 410 411 /** 412 * @param invoiceItemUnitPrice 413 */ 414 public void setInvoiceItemUnitPrice(KualiDecimal invoiceItemUnitPrice) { 415 if (ObjectUtils.isNotNull(invoiceItemUnitPrice)) { 416 this.invoiceItemUnitPrice = invoiceItemUnitPrice.bigDecimalValue(); 417 } 418 else { 419 this.invoiceItemUnitPrice = BigDecimal.ZERO; 420 } 421 } 422 423 /** 424 * Sets the invoiceItemUnitPrice attribute. 425 * 426 * @param invoiceItemUnitPrice The invoiceItemUnitPrice to set. 427 */ 428 public void setInvoiceItemUnitPrice(BigDecimal invoiceItemUnitPrice) { 429 this.invoiceItemUnitPrice = invoiceItemUnitPrice; 430 } 431 432 /** 433 * Gets the invoiceItemServiceDate attribute. 434 * 435 * @return Returns the invoiceItemServiceDate 436 */ 437 public Date getInvoiceItemServiceDate() { 438 return invoiceItemServiceDate; 439 } 440 441 /** 442 * Sets the invoiceItemServiceDate attribute. 443 * 444 * @param invoiceItemServiceDate The invoiceItemServiceDate to set. 445 */ 446 public void setInvoiceItemServiceDate(Date invoiceItemServiceDate) { 447 this.invoiceItemServiceDate = invoiceItemServiceDate; 448 } 449 450 /** 451 * Gets the invoiceItemCode attribute. 452 * 453 * @return Returns the invoiceItemCode 454 */ 455 public String getInvoiceItemCode() { 456 return invoiceItemCode; 457 } 458 459 /** 460 * Sets the invoiceItemCode attribute. 461 * 462 * @param invoiceItemCode The invoiceItemCode to set. 463 */ 464 public void setInvoiceItemCode(String invoiceItemCode) { 465 this.invoiceItemCode = invoiceItemCode; 466 } 467 468 /** 469 * Gets the invoiceItemDescription attribute. 470 * 471 * @return Returns the invoiceItemDescription 472 */ 473 public String getInvoiceItemDescription() { 474 return invoiceItemDescription; 475 } 476 477 /** 478 * Sets the invoiceItemDescription attribute. 479 * 480 * @param invoiceItemDescription The invoiceItemDescription to set. 481 */ 482 public void setInvoiceItemDescription(String invoiceItemDescription) { 483 this.invoiceItemDescription = invoiceItemDescription; 484 } 485 486 /** 487 * Gets the invoiceItemTaxAmount attribute. TODO Use tax service to get invoice item tax amount 488 * 489 * @return Returns the invoiceItemTaxAmount. 490 */ 491 public KualiDecimal getInvoiceItemTaxAmount() { 492 return invoiceItemTaxAmount; 493 } 494 495 /** 496 * Sets the invoiceItemTaxAmount attribute value. 497 * 498 * @param invoiceItemTaxAmount The invoiceItemTaxAmount to set. 499 */ 500 public void setInvoiceItemTaxAmount(KualiDecimal invoiceItemTaxAmount) { 501 this.invoiceItemTaxAmount = invoiceItemTaxAmount; 502 } 503 504 /** 505 * Gets the invoiceItemDiscountLineNumber attribute. 506 * 507 * @return Returns the invoiceItemDiscountLineNumber. 508 */ 509 public Integer getInvoiceItemDiscountLineNumber() { 510 return invoiceItemDiscountLineNumber; 511 } 512 513 /** 514 * Sets the invoiceItemDiscountLineNumber attribute value. 515 * 516 * @param invoiceItemDiscountLineNumber The invoiceItemDiscountLineNumber to set. 517 */ 518 public void setInvoiceItemDiscountLineNumber(Integer invoiceItemDiscountLineNumber) { 519 this.invoiceItemDiscountLineNumber = invoiceItemDiscountLineNumber; 520 } 521 522 /** 523 * Gets the accountsReceivableSubObject attribute. 524 * 525 * @return Returns the accountsReceivableSubObject 526 */ 527 public SubObjectCode getAccountsReceivableSubObject() { 528 return accountsReceivableSubObject; 529 } 530 531 /** 532 * Sets the accountsReceivableSubObject attribute. 533 * 534 * @param accountsReceivableSubObject The accountsReceivableSubObject to set. 535 * @deprecated 536 */ 537 public void setAccountsReceivableSubObject(SubObjectCode accountsReceivableSubObject) { 538 this.accountsReceivableSubObject = accountsReceivableSubObject; 539 } 540 541 /** 542 * Gets the accountsReceivableObject attribute. 543 * 544 * @return Returns the accountsReceivableObject 545 */ 546 public ObjectCode getAccountsReceivableObject() { 547 return accountsReceivableObject; 548 } 549 550 /** 551 * Sets the accountsReceivableObject attribute. 552 * 553 * @param accountsReceivableObject The accountsReceivableObject to set. 554 * @deprecated 555 */ 556 public void setAccountsReceivableObject(ObjectCode accountsReceivableObject) { 557 this.accountsReceivableObject = accountsReceivableObject; 558 } 559 560 /** 561 * @see org.kuali.rice.kns.bo.BusinessObjectBase#toStringMapper() 562 */ 563 @SuppressWarnings("unchecked") 564 protected LinkedHashMap toStringMapper() { 565 LinkedHashMap m = new LinkedHashMap(); 566 m.put("documentNumber", getDocumentNumber()); 567 if (this.getSequenceNumber() != null) { 568 m.put("invoiceItemNumber", this.getSequenceNumber().toString()); 569 } 570 return m; 571 } 572 573 /** 574 * Update line amount based on quantity and unit price 575 */ 576 public void updateAmountBasedOnQuantityAndUnitPrice() { 577 setAmount(getInvoiceItemPreTaxAmount()); 578 } 579 580 public boolean isTaxableIndicator() { 581 return taxableIndicator; 582 } 583 584 // yes this is redundant, its required for the JSP on the accounting 585 // line checkbox field 586 public boolean getTaxableIndicator() { 587 return taxableIndicator; 588 } 589 590 public void setTaxableIndicator(boolean taxableIndicator) { 591 this.taxableIndicator = taxableIndicator; 592 } 593 594 public boolean isDebit() { 595 return isDebit; 596 } 597 598 public void setDebit(boolean isDebit) { 599 this.isDebit = isDebit; 600 } 601 602 /** 603 * This method returns true if customer invoice detail has a corresponding discount line 604 * 605 * @return 606 */ 607 public boolean isDiscountLineParent() { 608 return ObjectUtils.isNotNull(getInvoiceItemDiscountLineNumber()); 609 } 610 611 /** 612 * This method should only be used to determine if detail is discount line in JSP. If you want to determine if invoice detail is 613 * a detail line use CustomerInvoiceDocument.isDiscountLineBasedOnSequenceNumber() instead. 614 * 615 * @return 616 */ 617 public boolean isDiscountLine() { 618 return ObjectUtils.isNotNull(parentDiscountCustomerInvoiceDetail); 619 } 620 621 /** 622 * This method sets the amount to negative if it isn't already negative 623 * 624 * @return 625 */ 626 public void setInvoiceItemUnitPriceToNegative() { 627 // if unit price is positive 628 if (invoiceItemUnitPrice.compareTo(BigDecimal.ZERO) == 1) { 629 invoiceItemUnitPrice = invoiceItemUnitPrice.negate(); 630 } 631 } 632 633 public CustomerInvoiceDetail getParentDiscountCustomerInvoiceDetail() { 634 return parentDiscountCustomerInvoiceDetail; 635 } 636 637 public void setParentDiscountCustomerInvoiceDetail(CustomerInvoiceDetail parentDiscountCustomerInvoiceDetail) { 638 this.parentDiscountCustomerInvoiceDetail = parentDiscountCustomerInvoiceDetail; 639 } 640 641 public CustomerInvoiceDetail getDiscountCustomerInvoiceDetail() { 642 return discountCustomerInvoiceDetail; 643 } 644 645 public void setDiscountCustomerInvoiceDetail(CustomerInvoiceDetail discountCustomerInvoiceDetail) { 646 this.discountCustomerInvoiceDetail = discountCustomerInvoiceDetail; 647 } 648 649 // ---- Methods to find matching InvoicePaidApplieds. 650 651 /** 652 * @return matching InvoicePaidApplieds from the database if they exist 653 */ 654 public List<InvoicePaidApplied> getMatchingInvoicePaidAppliedsMatchingAnyDocumentFromDatabase() { 655 //TODO Andrew 656 //return getMatchingInvoicePaidApplieds(null); 657 658 BusinessObjectService businessObjectService = SpringContext.getBean(BusinessObjectService.class); 659 660 // assuming here that you never have a PaidApplied against a Discount line 661 Map<String,Object> criteria = new HashMap<String,Object>(); 662 criteria.put("invoiceItemNumber", getInvoiceItemNumber()); 663 criteria.put("financialDocumentReferenceInvoiceNumber", getDocumentNumber()); 664 criteria.put("documentHeader.financialDocumentStatusCode", KFSConstants.DocumentStatusCodes.APPROVED); 665 666 List<InvoicePaidApplied> invoicePaidApplieds = (List<InvoicePaidApplied>) businessObjectService.findMatching(InvoicePaidApplied.class, criteria); 667 if(ObjectUtils.isNull(invoicePaidApplieds)) { 668 invoicePaidApplieds = new ArrayList<InvoicePaidApplied>(); 669 } 670 return invoicePaidApplieds; 671 } 672 673 /** 674 * @param paymentApplicationDocumentNumber 675 * @return the List of matching InvoicePaidApplieds. 676 * If paymentApplicationDocumentNumber is null invoicePaidApplieds matching any PaymentApplicationDocument will be returned. 677 * If paymentApplicationDocumentNumber is not null only the invoicePaidApplieds that match on that PaymentApplicationDocument will be returned. 678 */ 679 private List<InvoicePaidApplied> getMatchingInvoicePaidAppliedsMatchingDocument(String documentNumber) { 680 if (StringUtils.isBlank(documentNumber)) { 681 return getMatchingInvoicePaidAppliedsMatchingAnyDocumentFromDatabase(); 682 } 683 684 BusinessObjectService businessObjectService = SpringContext.getBean(BusinessObjectService.class); 685 Map<String,Object> criteria = new HashMap<String,Object>(); 686 criteria.put("documentNumber", documentNumber); 687 criteria.put("invoiceItemNumber", getSequenceNumber()); 688 criteria.put("financialDocumentReferenceInvoiceNumber", getDocumentNumber()); 689 690 List<InvoicePaidApplied> invoicePaidApplieds = (List<InvoicePaidApplied>) businessObjectService.findMatching(InvoicePaidApplied.class, criteria); 691 if(ObjectUtils.isNull(invoicePaidApplieds)) { 692 invoicePaidApplieds = new ArrayList<InvoicePaidApplied>(); 693 } 694 return invoicePaidApplieds; 695 } 696 697 //TODO Andrew 698 // /** 699 // * @param paymentApplicationDocumentNumber 700 // * @return matching InvoicePaidApplieds from the database matching the specific PaymentApplicationDocument if they exist 701 // */ 702 // public List<InvoicePaidApplied> getMatchingInvoicePaidAppliedsMatchingASpecificPaymentApplicationDocumentFromDatabase(String paymentApplicationDocumentNumber) { 703 // return getMatchingInvoicePaidApplieds(paymentApplicationDocumentNumber); 704 // } 705 // 706 // /** 707 // * @param paymentApplicationDocumentNumber 708 // * @return 709 // */ 710 // public InvoicePaidApplied getSingleMatchingInvoicePaidAppliedMatchingASpecificPaymentApplicationDocumentFromDatabase(String paymentApplicationDocumentNumber) { 711 // List<InvoicePaidApplied> matchingInvoicePaidApplieds = getMatchingInvoicePaidApplieds(paymentApplicationDocumentNumber); 712 // return matchingInvoicePaidApplieds.iterator().next(); 713 // } 714 // 715 // 716 // /** 717 // * Get InvoicePaidApplieds related to this CustomerInvoiceDetail if they 718 // * exist in a PaymentApplicationDocument and do it just by looking at the 719 // * PaymentApplicationDocument as it is in memory. Don't get anything from 720 // * the database. 721 // * 722 // * @param paymentApplicationDocument 723 // * @return 724 // */ 725 // public List<InvoicePaidApplied> getMatchingInvoicePaidAppliedsMatchingPaymentApplicationDocumentNoDatabase(PaymentApplicationDocument paymentApplicationDocument) { 726 // List<InvoicePaidApplied> invoicePaidApplieds = paymentApplicationDocument.getInvoicePaidApplieds(); 727 // List<InvoicePaidApplied> selectedInvoicePaidApplieds = new ArrayList<InvoicePaidApplied>(); 728 // // The paymentApplicationDocumentService isn't used to pull anything from the database. 729 // // It's just used to try to pair CustomerInvoiceDetails and InvoicePaidApplieds 730 // PaymentApplicationDocumentService paymentApplicationDocumentService = SpringContext.getBean(PaymentApplicationDocumentService.class); 731 // for(InvoicePaidApplied invoicePaidApplied : invoicePaidApplieds) { 732 // if(paymentApplicationDocumentService.customerInvoiceDetailPairsWithInvoicePaidApplied(this, invoicePaidApplied)) { 733 // selectedInvoicePaidApplieds.add(invoicePaidApplied); 734 // } 735 // } 736 // return selectedInvoicePaidApplieds; 737 // } 738 // 739 // /** 740 // * This method returns the results of @link getMatchingInvoicePaidAppliedsMatchingPaymentApplicationDocumentNoDatabase(PaymentApplicationDocument) 741 // * as a single InvoicePaidApplied. This is OK because there's only one 742 // * InvoicePaidApplied for a CustomerInvoiceDetail on a given PaymentApplicationDocument. 743 // * 744 // * @param paymentApplicationDocument 745 // * @return 746 // */ 747 // public InvoicePaidApplied getSingleMatchingInvoicepaidAppliedMatchingPaymentApplicationDocumentNoDatabase(PaymentApplicationDocument paymentApplicationDocument) { 748 // List<InvoicePaidApplied> matchingInvoicePaidApplieds = getMatchingInvoicePaidAppliedsMatchingPaymentApplicationDocumentNoDatabase(paymentApplicationDocument); 749 // return matchingInvoicePaidApplieds.iterator().next(); 750 // } 751 752 // ---- Simple getters/setters 753 754 public CustomerInvoiceDocument getCustomerInvoiceDocument() { 755 if (customerInvoiceDocument == null) { 756 DocumentService documentService = (DocumentService) SpringContext.getBean(DocumentService.class); 757 try { 758 customerInvoiceDocument = (CustomerInvoiceDocument) documentService.getByDocumentHeaderId(getDocumentNumber()); 759 } 760 catch (WorkflowException e) { 761 throw new RuntimeException("A WorkflowException was thrown when trying to open the details parent document. This should never happen.", e); 762 } 763 } 764 return customerInvoiceDocument; 765 } 766 767 public void setCustomerInvoiceDocument(CustomerInvoiceDocument customerInvoiceDocument) { 768 this.customerInvoiceDocument = customerInvoiceDocument; 769 } 770 771 public String getCustomerInvoiceWriteoffDocumentNumber() { 772 return customerInvoiceWriteoffDocumentNumber; 773 } 774 775 public void setCustomerInvoiceWriteoffDocumentNumber(String customerInvoiceWriteoffDocumentNumber) { 776 this.customerInvoiceWriteoffDocumentNumber = customerInvoiceWriteoffDocumentNumber; 777 } 778 779 public void setWriteoffAmount(KualiDecimal writeoffAmount) { 780 this.writeoffAmount = writeoffAmount; 781 } 782 783 public UnitOfMeasure getUnitOfMeasure() { 784 return unitOfMeasure; 785 } 786 787 public void setUnitOfMeasure(UnitOfMeasure unitOfMeasure) { 788 this.unitOfMeasure = unitOfMeasure; 789 } 790 791 //TODO Andrew 792 // public boolean isFullApply() { 793 // return fullApply; 794 // } 795 // 796 // public void setFullApply(boolean fullApply) { 797 // this.fullApply = fullApply; 798 // } 799 800 /** 801 * If the detail is a discount customer invoice detail, return the parent customer invoice detail's sequence number instead 802 * 803 * @see org.kuali.kfs.module.ar.businessobject.AppliedPayment#getInvoiceItemNumber() 804 */ 805 public Integer getInvoiceItemNumber() { 806 if (isDiscountLine()) { 807 return parentDiscountCustomerInvoiceDetail.getSequenceNumber(); 808 } else { 809 return this.getSequenceNumber(); 810 } 811 } 812 813 /** 814 * If detail is part of an invoice that is a reversal, return the invoice that is being corrected. Else return the customer 815 * details document number. 816 * 817 * @see org.kuali.kfs.module.ar.businessobject.AppliedPayment#getInvoiceReferenceNumber() 818 */ 819 public String getInvoiceReferenceNumber() { 820 return getDocumentNumber(); 821 } 822 823 /** 824 * 825 * @see org.kuali.rice.kns.bo.PersistableBusinessObjectBase#refresh() 826 */ 827 public void refresh() { 828 super.refresh(); 829 this.updateAmountBasedOnQuantityAndUnitPrice(); 830 } 831 832 }