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 }