View Javadoc
1   /*
2    * Copyright 2006 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.kuali.ole.module.purap.businessobject;
18  
19  import org.kuali.ole.module.purap.PurapConstants;
20  import org.kuali.ole.module.purap.PurapParameterConstants;
21  import org.kuali.ole.module.purap.PurapPropertyConstants;
22  import org.kuali.ole.module.purap.document.InvoiceDocument;
23  import org.kuali.ole.module.purap.document.PurchaseOrderDocument;
24  import org.kuali.ole.module.purap.document.service.AccountsPayableService;
25  import org.kuali.ole.module.purap.document.service.PurapService;
26  import org.kuali.ole.module.purap.document.service.PurchaseOrderService;
27  import org.kuali.ole.module.purap.exception.PurError;
28  import org.kuali.ole.module.purap.util.ExpiredOrClosedAccountEntry;
29  import org.kuali.ole.module.purap.util.PurApItemUtils;
30  import org.kuali.ole.module.purap.util.PurApObjectUtils;
31  import org.kuali.ole.select.document.OlePurchaseOrderDocument;
32  import org.kuali.ole.select.document.service.OleInvoiceService;
33  import org.kuali.ole.sys.OLEConstants;
34  import org.kuali.ole.sys.context.SpringContext;
35  import org.kuali.ole.sys.service.impl.OleParameterConstants;
36  import org.kuali.rice.core.api.util.type.KualiDecimal;
37  import org.kuali.rice.krad.service.KRADServiceLocator;
38  import org.kuali.rice.krad.util.ObjectUtils;
39  
40  import java.math.BigDecimal;
41  import java.util.ArrayList;
42  import java.util.HashMap;
43  import java.util.List;
44  import java.util.Map;
45  
46  /**
47   * Payment Request Item Business Object.
48   */
49  public class InvoiceItem extends AccountsPayableItemBase {
50      private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(InvoiceItem.class);
51  
52      private BigDecimal purchaseOrderItemUnitPrice;
53      private KualiDecimal itemOutstandingInvoiceQuantity;
54      private KualiDecimal itemOutstandingInvoiceAmount;
55      private Integer invoiceIdentifier;
56      private Integer purchaseOrderIdentifier;
57      protected Integer accountsPayablePurchasingDocumentLinkIdentifier;
58      protected Integer poLineNumber;
59      protected boolean closePurchaseOrderIndicator;
60      protected boolean reopenPurchaseOrderIndicator;
61      protected Integer postingYear;
62      protected String recurringPaymentTypeCode;
63      protected RecurringPaymentType recurringPaymentType;
64      protected boolean receivingDocumentRequiredIndicator;
65      protected PurchaseOrderDocument purchaseOrderDocument;
66      private PurchaseOrderItem poItem;
67  
68      /**
69       * Default constructor.
70       */
71      public InvoiceItem() {
72  
73      }
74  
75      /**
76       * inv item constructor - Delegate
77       *
78       * @param poi - purchase order item
79       * @param inv - payment request document
80       */
81      public InvoiceItem(PurchaseOrderItem poi, InvoiceDocument inv) {
82          this(poi, inv, new HashMap<String, ExpiredOrClosedAccountEntry>());
83      }
84  
85      /**
86       * Constructs a new payment request item, but also merges expired accounts.
87       *
88       * @param poi                        - purchase order item
89       * @param inv                        - payment request document
90       * @param expiredOrClosedAccountList - list of expired or closed accounts to merge
91       */
92      public InvoiceItem(PurchaseOrderItem poi, InvoiceDocument inv, HashMap<String, ExpiredOrClosedAccountEntry> expiredOrClosedAccountList) {
93  
94          // copy base attributes w/ extra array of fields not to be copied
95          PurApObjectUtils.populateFromBaseClass(PurApItemBase.class, poi, this, PurapConstants.PREQ_ITEM_UNCOPYABLE_FIELDS);
96  
97          setItemDescription(poi.getItemDescription());
98  
99          //New Source Line should be set for InvoiceItem
100         resetAccount();
101 
102         // set up accounts
103         List accounts = new ArrayList();
104         for (PurApAccountingLine account : poi.getSourceAccountingLines()) {
105             PurchaseOrderAccount poa = (PurchaseOrderAccount) account;
106 
107             // check if this account is expired/closed and replace as needed
108             SpringContext.getBean(AccountsPayableService.class).processExpiredOrClosedAccount(poa, expiredOrClosedAccountList);
109 
110             //KFSMI-4522 copy an accounting line with zero dollar amount if system parameter allows
111             if (poa.getAmount()!=null && poa.getAmount().isZero()) {
112                 if (SpringContext.getBean(AccountsPayableService.class).canCopyAccountingLinesWithZeroAmount()) {
113                     accounts.add(new InvoiceAccount(this, poa));
114                 }
115             } else {
116                 accounts.add(new InvoiceAccount(this, poa));
117             }
118         }
119 
120         this.setSourceAccountingLines(accounts);
121         this.getUseTaxItems().clear();
122         //List<PurApItemUseTax> newUseTaxItems = new ArrayList<PurApItemUseTax>();
123         /// this.setUseTaxItems(newUseTaxItems);
124         //copy use tax items over, and blank out keys (useTaxId and itemIdentifier)
125         /*
126         this.getUseTaxItems().clear();
127         for (PurApItemUseTax useTaxItem : poi.getUseTaxItems()) {
128             InvoiceItemUseTax newItemUseTax = new InvoiceItemUseTax(useTaxItem);
129             this.getUseTaxItems().add(newItemUseTax);
130 
131         }
132         */
133 
134         // clear amount and desc on below the line - we probably don't need that null
135         // itemType check but it's there just in case remove if it causes problems
136         // also do this if of type service
137         if ((ObjectUtils.isNotNull(this.getItemType()) && this.getItemType().isAmountBasedGeneralLedgerIndicator())) {
138             // setting unit price to be null to be more consistent with other below the line
139             this.setItemUnitPrice(null);
140         }
141 
142         // copy custom
143         this.purchaseOrderItemUnitPrice = poi.getItemUnitPrice();
144 //        this.purchaseOrderCommodityCode = poi.getPurchaseOrderCommodityCd();
145 
146         // set doc fields
147         this.setPurapDocumentIdentifier(inv.getPurapDocumentIdentifier());
148         this.setPurapDocument(inv);
149     }
150 
151     /**
152      * Retrieves a purchase order item by inspecting the item type to see if its above the line or below the line and returns the
153      * appropriate type.
154      *
155      * @return - purchase order item
156      */
157     @Override
158     public PurchaseOrderItem getPurchaseOrderItem() {
159         if (ObjectUtils.isNotNull(this.getPurapDocumentIdentifier())) {
160             if (ObjectUtils.isNull(this.getInvoice())) {
161                 this.refreshReferenceObject(PurapPropertyConstants.PURAP_DOC);
162             }
163         }
164         PurchaseOrderItem poi = null;
165         // ideally we should do this a different way - maybe move it all into the service or save this info somehow (make sure and
166         // update though)
167         if (getInvoice() != null) {
168             PurchaseOrderDocument po = this.getInvoice().getPurchaseOrderDocument(this.getPurchaseOrderIdentifier());
169             if (po != null) {
170                 this.setPostingYear(po.getPostingYear());
171                 if (po.getRecurringPaymentType() != null) {
172                     this.setRecurringPaymentType(po.getRecurringPaymentType());
173                     this.setRecurringPaymentTypeCode(po.getRecurringPaymentTypeCode());
174 
175                 }
176 
177                 if (this.getItemType().isLineItemIndicator() && this.getItemLineNumber() != null ) {
178                     List<PurchaseOrderItem> items = po.getItems();
179                     poi = items.get(this.getItemLineNumber().intValue() - 1);
180                     // throw error if line numbers don't match
181                     // MSU Contribution DTT-3014 OLEMI-8483 OLECNTRB-974
182                     /*
183                     * List items = po.getItems(); if (items != null) { for (Object object : items) { PurchaseOrderItem item =
184                     * (PurchaseOrderItem) object; if (item != null && item.getItemLineNumber().equals(this.getItemLineNumber())) { poi
185                     * = item; break; } } }
186                     */
187                 } else {
188                     poi = (PurchaseOrderItem) SpringContext.getBean(PurapService.class).getBelowTheLineByType(po, this.getItemType());
189                 }
190             }
191 
192             if (poi != null) {
193                 this.setPoItem(poi);
194                 return poi;
195             } else {
196                 if (LOG.isDebugEnabled()) {
197                     LOG.debug("getPurchaseOrderItem() Returning null because PurchaseOrderItem object for line number" + getItemLineNumber() + "or itemType " + getItemTypeCode() + " is null");
198                 }
199                 return null;
200             }
201         } else {
202 
203             LOG.error("getPurchaseOrderItem() Returning null because invoice object is null");
204             throw new PurError("Payment Request Object in Purchase Order item line number " + getItemLineNumber() + "or itemType " + getItemTypeCode() + " is null");
205         }
206     }
207 
208     public KualiDecimal getPoOutstandingAmount() {
209         PurchaseOrderItem poi = this.getPoItem()!=null ? this.getPoItem() : getPurchaseOrderItem();
210         if (ObjectUtils.isNull(this.getPurchaseOrderItemUnitPrice()) || KualiDecimal.ZERO.equals(this.getPurchaseOrderItemUnitPrice())) {
211             return null;
212         } else {
213             return this.getPoOutstandingAmount(poi);
214         }
215     }
216 
217     private KualiDecimal getPoOutstandingAmount(PurchaseOrderItem poi) {
218         if (poi == null) {
219             return KualiDecimal.ZERO;
220         } else {
221             return poi.getItemOutstandingEncumberedAmount();
222         }
223     }
224 
225     public KualiDecimal getPoOriginalAmount() {
226         PurchaseOrderItem poi = this.getPoItem()!=null ? this.getPoItem() : getPurchaseOrderItem();
227         if (poi == null) {
228             return null;
229         } else {
230             return poi.getExtendedPrice();
231         }
232     }
233 
234     /**
235      * Exists due to a setter requirement by the htmlControlAttribute
236      *
237      * @param amount - po outstanding amount
238      * @deprecated
239      */
240     @Deprecated
241     public void setPoOutstandingAmount(KualiDecimal amount) {
242         // do nothing
243     }
244 
245 
246     public KualiDecimal getPoOutstandingQuantity() {
247         PurchaseOrderItem poi = this.getPoItem()!=null ? this.getPoItem() : getPurchaseOrderItem();
248         if (poi == null) {
249             return KualiDecimal.ZERO;
250         } else {
251             if (PurapConstants.ItemTypeCodes.ITEM_TYPE_SERVICE_CODE.equals(this.getItemTypeCode())) {
252                 return KualiDecimal.ZERO;
253             } else {
254                 return poi.getOutstandingQuantity();
255             }
256         }
257     }
258 
259     /**
260      * Exists due to a setter requirement by the htmlControlAttribute
261      *
262      * @param qty - po outstanding quantity
263      * @deprecated
264      */
265     @Deprecated
266     public void setPoOutstandingQuantity(KualiDecimal qty) {
267         // do nothing
268     }
269 
270     public BigDecimal getPurchaseOrderItemUnitPrice() {
271         return purchaseOrderItemUnitPrice;
272     }
273 
274     public Integer getAccountsPayablePurchasingDocumentLinkIdentifier() {
275         return accountsPayablePurchasingDocumentLinkIdentifier;
276     }
277 
278     public void setAccountsPayablePurchasingDocumentLinkIdentifier(Integer accountsPayablePurchasingDocumentLinkIdentifier) {
279         this.accountsPayablePurchasingDocumentLinkIdentifier = accountsPayablePurchasingDocumentLinkIdentifier;
280     }
281 
282     public Integer getPoLineNumber() {
283         return poLineNumber;
284     }
285 
286     public void setPoLineNumber(Integer poLineNumber) {
287         this.poLineNumber = poLineNumber;
288     }
289 
290 
291     public Integer getPurchaseOrderIdentifier() {
292         return purchaseOrderIdentifier;
293     }
294 
295     public void setPurchaseOrderIdentifier(Integer purchaseOrderIdentifier) {
296         this.purchaseOrderIdentifier = purchaseOrderIdentifier;
297     }
298 
299     public Integer getInvoiceIdentifier() {
300         return invoiceIdentifier;
301     }
302 
303     public void setInvoiceIdentifier(Integer invoiceIdentifier) {
304         this.invoiceIdentifier = invoiceIdentifier;
305     }
306 
307     public BigDecimal getOriginalAmountfromPO() {
308         return purchaseOrderItemUnitPrice;
309     }
310 
311     public void setOriginalAmountfromPO(BigDecimal purchaseOrderItemUnitPrice) {
312         // Do nothing
313     }
314 
315     public Integer getPostingYear() {
316         return postingYear;
317     }
318 
319     /**
320      * @see org.kuali.ole.sys.document.LedgerPostingDocument#setPostingYear(Integer)
321      */
322     public void setPostingYear(Integer postingYear) {
323         this.postingYear = postingYear;
324     }
325 
326     public void setPurchaseOrderItemUnitPrice(BigDecimal purchaseOrderItemUnitPrice) {
327         this.purchaseOrderItemUnitPrice = purchaseOrderItemUnitPrice;
328     }
329 
330     public KualiDecimal getItemOutstandingInvoiceAmount() {
331         return itemOutstandingInvoiceAmount;
332     }
333 
334     public void setItemOutstandingInvoiceAmount(KualiDecimal itemOutstandingInvoiceAmount) {
335         this.itemOutstandingInvoiceAmount = itemOutstandingInvoiceAmount;
336     }
337 
338     public KualiDecimal getItemOutstandingInvoiceQuantity() {
339         return itemOutstandingInvoiceQuantity;
340     }
341 
342     public void setItemOutstandingInvoiceQuantity(KualiDecimal itemOutstandingInvoiceQuantity) {
343         this.itemOutstandingInvoiceQuantity = itemOutstandingInvoiceQuantity;
344     }
345 
346     public InvoiceDocument getInvoice() {
347         if (ObjectUtils.isNotNull(getPurapDocumentIdentifier())) {
348             if (ObjectUtils.isNull(getPurapDocument())) {
349                 this.refreshReferenceObject(PurapPropertyConstants.PURAP_DOC);
350             }
351         }
352         return super.getPurapDocument();
353     }
354 
355     public void setInvoice(InvoiceDocument invoice) {
356         this.setPurapDocument(invoice);
357     }
358 
359     public boolean isClosePurchaseOrderIndicator() {
360         return closePurchaseOrderIndicator;
361     }
362 
363     public void setClosePurchaseOrderIndicator(boolean closePurchaseOrderIndicator) {
364         this.closePurchaseOrderIndicator = closePurchaseOrderIndicator;
365     }
366 
367     public boolean isReopenPurchaseOrderIndicator() {
368         return reopenPurchaseOrderIndicator;
369     }
370 
371     public void setReopenPurchaseOrderIndicator(boolean reopenPurchaseOrderIndicator) {
372         this.reopenPurchaseOrderIndicator = reopenPurchaseOrderIndicator;
373     }
374 
375     public String getRecurringPaymentTypeCode() {
376         return recurringPaymentTypeCode;
377     }
378 
379     public void setRecurringPaymentTypeCode(String recurringPaymentTypeCode) {
380         this.recurringPaymentTypeCode = recurringPaymentTypeCode;
381     }
382 
383     public RecurringPaymentType getRecurringPaymentType() {
384         if (ObjectUtils.isNull(recurringPaymentType)) {
385             refreshReferenceObject(PurapPropertyConstants.RECURRING_PAYMENT_TYPE);
386         }
387         return recurringPaymentType;
388     }
389 
390     public void setRecurringPaymentType(RecurringPaymentType recurringPaymentType) {
391         this.recurringPaymentType = recurringPaymentType;
392     }
393 
394     public void generateAccountListFromPoItemAccounts(List<PurApAccountingLine> accounts) {
395         for (PurApAccountingLine line : accounts) {
396             PurchaseOrderAccount poa = (PurchaseOrderAccount) line;
397             if (!line.isEmpty()) {
398                 getSourceAccountingLines().add(new InvoiceAccount(this, poa));
399             }
400         }
401     }
402 
403     /**
404      * @see org.kuali.ole.module.purap.businessobject.PurApItem#getAccountingLineClass()
405      */
406     @Override
407     public Class getAccountingLineClass() {
408         return InvoiceAccount.class;
409     }
410 
411     public boolean isDisplayOnPreq() {
412         PurchaseOrderItem poi = this.getPoItem()!=null ? this.getPoItem() : getPurchaseOrderItem();
413         if (ObjectUtils.isNull(poi)) {
414             LOG.debug("poi was null");
415             return false;
416         }
417 
418         // if the po item is not active... skip it
419         if (!poi.isItemActiveIndicator()) {
420             if (LOG.isDebugEnabled()) {
421                 LOG.debug("poi was not active: " + poi.toString());
422             }
423             return false;
424         }
425 
426         ItemType poiType = poi.getItemType();
427 
428         if (poiType.isQuantityBasedGeneralLedgerIndicator()) {
429             if (poi.getItemQuantity().isGreaterThan(poi.getItemInvoicedTotalQuantity())) {
430                 return true;
431             } else {
432                 if (ObjectUtils.isNotNull(this.getItemQuantity()) && this.getItemQuantity().isGreaterThan(KualiDecimal.ZERO)) {
433                     return true;
434                 }
435             }
436 
437             return false;
438         } else { // not quantity based
439             if (poi.getItemOutstandingEncumberedAmount().isGreaterThan(KualiDecimal.ZERO)) {
440                 return true;
441             } else {
442                 if (PurApItemUtils.isNonZeroExtended(this)) {
443                     return true;
444                 }
445                 return false;
446             }
447 
448         }
449     }
450 
451     /**
452      * sets account line percentage to zero.
453      *
454      * @see org.kuali.ole.module.purap.businessobject.PurApItem#resetAccount()
455      */
456     @Override
457     public void resetAccount() {
458         super.resetAccount();
459         this.getNewSourceLine().setAmount(null);
460         this.getNewSourceLine().setAccountLinePercent(null);
461     }
462 
463     /**
464      * Added for electronic invoice
465      */
466     public void addToUnitPrice(BigDecimal addThisValue) {
467         if (getItemUnitPrice() == null) {
468             setItemUnitPrice(BigDecimal.ZERO);
469         }
470         BigDecimal addedPrice = getItemUnitPrice().add(addThisValue);
471         setItemUnitPrice(addedPrice);
472     }
473 
474     public void addToExtendedPrice(KualiDecimal addThisValue) {
475         if (getExtendedPrice() == null) {
476             setExtendedPrice(KualiDecimal.ZERO);
477         }
478         KualiDecimal addedPrice = getExtendedPrice().add(addThisValue);
479         setExtendedPrice(addedPrice);
480     }
481 
482     @Override
483     public Class getUseTaxClass() {
484         return InvoiceItemUseTax.class;
485     }
486 
487     /**
488      * Gets the receivingDocumentRequiredIndicator attribute.
489      *
490      * @return Returns the receivingDocumentRequiredIndicator.
491      */
492     public boolean isReceivingDocumentRequiredIndicator() {
493         return receivingDocumentRequiredIndicator;
494     }
495 
496     /**
497      * Sets the receivingDocumentRequiredIndicator attribute value.
498      *
499      * @param receivingDocumentRequiredIndicator
500      *         The receivingDocumentRequiredIndicator to set.
501      */
502     public void setReceivingDocumentRequiredIndicator(boolean receivingDocumentRequiredIndicator) {
503         // if receivingDocumentRequiredIndicator functionality is disabled, always set it to false, overriding the passed-in value
504         if (!isEnableReceivingDocumentRequiredIndicator()) {
505             this.receivingDocumentRequiredIndicator = false;
506         } else {
507             this.receivingDocumentRequiredIndicator = receivingDocumentRequiredIndicator;
508         }
509     }
510 
511     /**
512      * Decides whether receivingDocumentRequiredIndicator functionality shall be enabled according to the controlling parameter.
513      */
514     public boolean isEnableReceivingDocumentRequiredIndicator() {
515         return SpringContext.getBean(OleInvoiceService.class).getParameterBoolean(OLEConstants.OptionalModuleNamespaces.PURCHASING_ACCOUNTS_PAYABLE, OleParameterConstants.DOCUMENT_COMPONENT, PurapParameterConstants.RECEIVING_DOCUMENT_REQUIRED_IND);
516         // return SpringContext.getBean(ParameterService.class).getParameterValueAsBoolean(OleParameterConstants.PURCHASING_DOCUMENT.class, PurapParameterConstants.RECEIVING_DOCUMENT_REQUIRED_IND);
517     }
518 
519     /**
520      * @see org.kuali.ole.module.purap.document.AccountsPayableDocument#getPurchaseOrderDocument()
521      */
522     public PurchaseOrderDocument getPurchaseOrderDocument() {
523         if ((ObjectUtils.isNull(purchaseOrderDocument) || ObjectUtils.isNull(purchaseOrderDocument.getPurapDocumentIdentifier())) && (ObjectUtils.isNotNull(getPurchaseOrderIdentifier()))) {
524             Map map = new HashMap();
525             map.put("purapDocumentIdentifier",this.getPurchaseOrderIdentifier());
526             List<OlePurchaseOrderDocument> purchaseOrderDocumentList = (List<OlePurchaseOrderDocument>) KRADServiceLocator.getBusinessObjectService().findMatching(OlePurchaseOrderDocument.class,map);
527             if(purchaseOrderDocumentList!=null && purchaseOrderDocumentList.size()>0){
528                 for(OlePurchaseOrderDocument olePurchaseOrderDocument : purchaseOrderDocumentList){
529                     if(olePurchaseOrderDocument.isPurchaseOrderCurrentIndicator()){
530                         setPurchaseOrderDocument(olePurchaseOrderDocument);
531                     }
532                 }
533 
534             }
535         }
536         return purchaseOrderDocument;
537     }
538 
539     /**
540      * @see org.kuali.ole.module.purap.document.AccountsPayableDocument#setPurchaseOrderDocument(org.kuali.ole.module.purap.document.PurchaseOrderDocument)
541      */
542     public void setPurchaseOrderDocument(PurchaseOrderDocument purchaseOrderDocument) {
543         if (ObjectUtils.isNull(purchaseOrderDocument)) {
544             // KUALI-PURAP 1185 PO Id not being set to null, instead throwing error on main screen that value is invalid.
545             // setPurchaseOrderIdentifier(null);
546             this.purchaseOrderDocument = null;
547         } else {
548             if (ObjectUtils.isNotNull(purchaseOrderDocument.getPurapDocumentIdentifier())) {
549                 setPurchaseOrderIdentifier(purchaseOrderDocument.getPurapDocumentIdentifier());
550             }
551             this.purchaseOrderDocument = purchaseOrderDocument;
552         }
553     }
554 
555     public PurchaseOrderItem getPoItem() {
556         return poItem;
557     }
558 
559     public void setPoItem(PurchaseOrderItem poItem) {
560         this.poItem = poItem;
561     }
562 }