View Javadoc
1   /*
2    * Copyright 2007 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.apache.commons.lang.StringUtils;
20  import org.kuali.ole.module.purap.PurapConstants;
21  import org.kuali.ole.module.purap.PurapPropertyConstants;
22  import org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocument;
23  import org.kuali.ole.module.purap.util.PurApObjectUtils;
24  import org.kuali.rice.core.api.util.type.KualiDecimal;
25  import org.kuali.rice.krad.bo.PersistableBusinessObjectBase;
26  import org.kuali.rice.krad.util.ObjectUtils;
27  
28  import java.math.BigDecimal;
29  import java.util.ArrayList;
30  import java.util.HashMap;
31  import java.util.LinkedHashMap;
32  import java.util.List;
33  
34  /**
35   * Purap Item Base Business Object.
36   */
37  public abstract class PurApItemBase extends PersistableBusinessObjectBase implements PurApItem {
38  
39      private Integer itemIdentifier;
40      private Integer itemLineNumber;
41      private String itemUnitOfMeasureCode;
42      private String itemCatalogNumber;
43      private String itemDescription;
44      private BigDecimal itemUnitPrice;
45      private String itemTypeCode;
46      private String itemAuxiliaryPartIdentifier;
47      private String externalOrganizationB2bProductReferenceNumber;
48      private String externalOrganizationB2bProductTypeName;
49      private boolean itemAssignedToTradeInIndicator;
50      private KualiDecimal extendedPrice; // not currently in DB
51      private KualiDecimal itemSalesTaxAmount;
52  
53      private List<PurApItemUseTax> useTaxItems;
54      private List<PurApAccountingLine> sourceAccountingLines;
55      private List<PurApAccountingLine> baselineSourceAccountingLines;
56      private PurApAccountingLine newSourceLine;
57  
58      private ItemType itemType;
59      private Integer purapDocumentIdentifier;
60      private KualiDecimal itemQuantity;
61  
62      private PurchasingAccountsPayableDocument purapDocument;
63  
64      /**
65       * Default constructor.
66       */
67      public PurApItemBase() {
68          itemTypeCode = PurapConstants.ItemTypeCodes.ITEM_TYPE_ITEM_CODE;
69          sourceAccountingLines = new ArrayList();
70          baselineSourceAccountingLines = new ArrayList();
71          useTaxItems = new ArrayList();
72          resetAccount();
73      }
74  
75      /**
76       * @see org.kuali.ole.module.purap.businessobject.PurApItem#getItemIdentifierString()
77       */
78      @Override
79      public String getItemIdentifierString() {
80          String itemLineNumberString = (getItemLineNumber() != null ? getItemLineNumber().toString() : "");
81          String identifierString = (getItemType().isLineItemIndicator() ? "Item " + itemLineNumberString : getItemType().getItemTypeDescription());
82          return identifierString;
83      }
84  
85      @Override
86      public Integer getItemIdentifier() {
87          return itemIdentifier;
88      }
89  
90      @Override
91      public void setItemIdentifier(Integer ItemIdentifier) {
92          this.itemIdentifier = ItemIdentifier;
93      }
94  
95      @Override
96      public Integer getItemLineNumber() {
97          return itemLineNumber;
98      }
99  
100     @Override
101     public void setItemLineNumber(Integer itemLineNumber) {
102         this.itemLineNumber = itemLineNumber;
103     }
104 
105     @Override
106     public String getItemUnitOfMeasureCode() {
107         return itemUnitOfMeasureCode;
108     }
109 
110     @Override
111     public void setItemUnitOfMeasureCode(String itemUnitOfMeasureCode) {
112         this.itemUnitOfMeasureCode = (StringUtils.isNotBlank(itemUnitOfMeasureCode) ? itemUnitOfMeasureCode.toUpperCase() : itemUnitOfMeasureCode);
113     }
114 
115     @Override
116     public String getItemCatalogNumber() {
117         return itemCatalogNumber;
118     }
119 
120     @Override
121     public void setItemCatalogNumber(String itemCatalogNumber) {
122         this.itemCatalogNumber = itemCatalogNumber;
123     }
124 
125     @Override
126     public String getItemDescription() {
127         return itemDescription;
128     }
129 
130     @Override
131     public void setItemDescription(String itemDescription) {
132         this.itemDescription = itemDescription;
133     }
134 
135     @Override
136     public BigDecimal getItemUnitPrice() {
137         // Setting scale on retrieval of unit price
138         if (itemUnitPrice != null) {
139             if (itemUnitPrice.scale() < PurapConstants.DOLLAR_AMOUNT_MIN_SCALE) {
140                 itemUnitPrice = itemUnitPrice.setScale(PurapConstants.DOLLAR_AMOUNT_MIN_SCALE, KualiDecimal.ROUND_BEHAVIOR);
141             } else if (itemUnitPrice.scale() > PurapConstants.UNIT_PRICE_MAX_SCALE) {
142                 itemUnitPrice = itemUnitPrice.setScale(PurapConstants.UNIT_PRICE_MAX_SCALE, KualiDecimal.ROUND_BEHAVIOR);
143             }
144         }
145 
146         return itemUnitPrice;
147     }
148 
149     @Override
150     public void setItemUnitPrice(BigDecimal itemUnitPrice) {
151         if (itemUnitPrice != null) {
152             if (itemUnitPrice.scale() < PurapConstants.DOLLAR_AMOUNT_MIN_SCALE) {
153                 itemUnitPrice = itemUnitPrice.setScale(PurapConstants.DOLLAR_AMOUNT_MIN_SCALE, KualiDecimal.ROUND_BEHAVIOR);
154             } else if (itemUnitPrice.scale() > PurapConstants.UNIT_PRICE_MAX_SCALE) {
155                 itemUnitPrice = itemUnitPrice.setScale(PurapConstants.UNIT_PRICE_MAX_SCALE, KualiDecimal.ROUND_BEHAVIOR);
156             }
157         }
158         this.itemUnitPrice = itemUnitPrice;
159     }
160 
161     @Override
162     public String getItemTypeCode() {
163         return itemTypeCode;
164     }
165 
166     @Override
167     public void setItemTypeCode(String itemTypeCode) {
168         this.itemTypeCode = itemTypeCode;
169     }
170 
171     @Override
172     public String getItemAuxiliaryPartIdentifier() {
173         return itemAuxiliaryPartIdentifier;
174     }
175 
176     @Override
177     public void setItemAuxiliaryPartIdentifier(String itemAuxiliaryPartIdentifier) {
178         this.itemAuxiliaryPartIdentifier = itemAuxiliaryPartIdentifier;
179     }
180 
181     @Override
182     public String getExternalOrganizationB2bProductReferenceNumber() {
183         return externalOrganizationB2bProductReferenceNumber;
184     }
185 
186     @Override
187     public void setExternalOrganizationB2bProductReferenceNumber(String externalOrganizationB2bProductReferenceNumber) {
188         this.externalOrganizationB2bProductReferenceNumber = externalOrganizationB2bProductReferenceNumber;
189     }
190 
191     @Override
192     public String getExternalOrganizationB2bProductTypeName() {
193         return externalOrganizationB2bProductTypeName;
194     }
195 
196     @Override
197     public void setExternalOrganizationB2bProductTypeName(String externalOrganizationB2bProductTypeName) {
198         this.externalOrganizationB2bProductTypeName = externalOrganizationB2bProductTypeName;
199     }
200 
201     @Override
202     public boolean getItemAssignedToTradeInIndicator() {
203         return itemAssignedToTradeInIndicator;
204     }
205 
206     @Override
207     public void setItemAssignedToTradeInIndicator(boolean itemAssignedToTradeInIndicator) {
208         this.itemAssignedToTradeInIndicator = itemAssignedToTradeInIndicator;
209     }
210 
211     @Override
212     public ItemType getItemType() {
213         // JHK : short circuit the item type reference if there is no item type
214         if (StringUtils.isBlank(itemTypeCode)) {
215             return null;
216         }
217         if (ObjectUtils.isNull(itemType) || !itemType.getItemTypeCode().equals(itemTypeCode)) {
218             refreshReferenceObject(PurapPropertyConstants.ITEM_TYPE);
219         }
220         return itemType;
221     }
222 
223     /**
224      * Sets the itemType attribute.
225      *
226      * @param itemType The itemType to set.
227      * @deprecated
228      */
229     @Deprecated
230     @Override
231     public void setItemType(ItemType itemType) {
232         this.itemType = itemType;
233     }
234 
235     @Override
236     public KualiDecimal getItemTaxAmount() {
237         KualiDecimal taxAmount = KualiDecimal.ZERO;
238 
239         if (ObjectUtils.isNull(purapDocument)) {
240             this.refreshReferenceObject("purapDocument");
241         }
242 
243         if (ObjectUtils.isNotNull(purapDocument) && purapDocument.isUseTaxIndicator() == false) {
244             taxAmount = this.itemSalesTaxAmount;
245         } else {
246             // sum use tax item tax amounts
247             for (PurApItemUseTax useTaxItem : this.getUseTaxItems()) {
248                 taxAmount = taxAmount.add(useTaxItem.getTaxAmount());
249             }
250         }
251 
252         return taxAmount;
253     }
254 
255     @Override
256     public void setItemTaxAmount(KualiDecimal itemTaxAmount) {
257 
258         if (purapDocument == null) {
259             this.refreshReferenceObject("purapDocument");
260         }
261 
262         if (purapDocument.isUseTaxIndicator() == false) {
263             this.itemSalesTaxAmount = itemTaxAmount;
264         }
265 
266     }
267 
268     public final KualiDecimal getItemSalesTaxAmount() {
269         return itemSalesTaxAmount;
270     }
271 
272     public final void setItemSalesTaxAmount(KualiDecimal itemSalesTaxAmount) {
273         this.itemSalesTaxAmount = itemSalesTaxAmount;
274     }
275 
276     @Override
277     public KualiDecimal getExtendedPrice() {
278         return calculateExtendedPrice();
279     }
280 
281     @Override
282     public KualiDecimal getTotalAmount() {
283         KualiDecimal totalAmount = getExtendedPrice();
284         if (ObjectUtils.isNull(totalAmount)) {
285             totalAmount = KualiDecimal.ZERO;
286         }
287 
288         KualiDecimal taxAmount = getItemTaxAmount();
289         if (ObjectUtils.isNull(taxAmount)) {
290             taxAmount = KualiDecimal.ZERO;
291         }
292 
293         totalAmount = totalAmount.add(taxAmount);
294 
295         return totalAmount;
296     }
297 
298     @Override
299     public void setTotalAmount(KualiDecimal totalAmount) {
300         // do nothing, setter required by interface
301     }
302 
303     @Override
304     public KualiDecimal calculateExtendedPrice() {
305         KualiDecimal extendedPrice = KualiDecimal.ZERO;
306         if (ObjectUtils.isNotNull(itemUnitPrice)) {
307             if (this.itemType.isAmountBasedGeneralLedgerIndicator()) {
308                 // SERVICE ITEM: return unit price as extended price
309                 extendedPrice = new KualiDecimal(this.itemUnitPrice.toString());
310             } else if (ObjectUtils.isNotNull(this.getItemQuantity())) {
311                 BigDecimal calcExtendedPrice = this.itemUnitPrice.multiply(this.itemQuantity.bigDecimalValue());
312                 // ITEM TYPE (qty driven): return (unitPrice x qty)
313                 extendedPrice = new KualiDecimal(calcExtendedPrice.setScale(KualiDecimal.SCALE, KualiDecimal.ROUND_BEHAVIOR));
314             }
315         }
316         return extendedPrice;
317     }
318 
319     @Override
320     public void setExtendedPrice(KualiDecimal extendedPrice) {
321         this.extendedPrice = extendedPrice;
322     }
323 
324     @Override
325     public List<PurApAccountingLine> getSourceAccountingLines() {
326         return sourceAccountingLines;
327     }
328 
329     @Override
330     public void setSourceAccountingLines(List<PurApAccountingLine> accountingLines) {
331         this.sourceAccountingLines = accountingLines;
332     }
333 
334     @Override
335     public List<PurApAccountingLine> getBaselineSourceAccountingLines() {
336         return baselineSourceAccountingLines;
337     }
338 
339     public void setBaselineSourceAccountingLines(List<PurApAccountingLine> baselineSourceLines) {
340         this.baselineSourceAccountingLines = baselineSourceLines;
341     }
342 
343     /**
344      * This implementation is coupled tightly with some underlying issues that the Struts PojoProcessor plugin has with how objects
345      * get instantiated within lists. The first three lines are required otherwise when the PojoProcessor tries to automatically
346      * inject values into the list, it will get an index out of bounds error if the instance at an index is being called and prior
347      * instances at indices before that one are not being instantiated. So changing the code below will cause adding lines to break
348      * if you add more than one item to the list.
349      *
350      * @see org.kuali.rice.krad.document.FinancialDocument#getTargetAccountingLine(int)
351      */
352     public PurApAccountingLine getSourceAccountingLine(int index) {
353         return getSourceAccountingLines().get(index);
354     }
355 
356     public PurApAccountingLine getBaselineSourceAccountingLine(int index) {
357         return getBaselineSourceAccountingLines().get(index);
358     }
359 
360     private PurApAccountingLine getNewAccount() throws RuntimeException {
361 
362         PurApAccountingLine newAccount = null;
363         try {
364             newAccount = (PurApAccountingLine) getAccountingLineClass().newInstance();
365         } catch (InstantiationException e) {
366             throw new RuntimeException("Unable to get class");
367         } catch (IllegalAccessException e) {
368             throw new RuntimeException("Unable to get class");
369         } catch (NullPointerException e) {
370             throw new RuntimeException("Can't instantiate Purchasing Account from base");
371         }
372         return newAccount;
373     }
374 
375     @Override
376     public abstract Class getAccountingLineClass();
377 
378     @Override
379     public abstract Class getUseTaxClass();
380 
381     @Override
382     public void resetAccount() {
383         // add a blank accounting line
384         PurApAccountingLine purApAccountingLine = getNewAccount();
385 
386         purApAccountingLine.setItemIdentifier(this.itemIdentifier);
387         purApAccountingLine.setPurapItem(this);
388         purApAccountingLine.setSequenceNumber(0);
389         setNewSourceLine(purApAccountingLine);
390     }
391 
392     public void resetAccount(BigDecimal initialPercent) {
393         PurApAccountingLine purApAccountingLine = getNewAccount();
394 
395         purApAccountingLine.setItemIdentifier(this.itemIdentifier);
396         purApAccountingLine.setPurapItem(this);
397         purApAccountingLine.setSequenceNumber(0);
398         purApAccountingLine.setAccountLinePercent(initialPercent);
399         setNewSourceLine(purApAccountingLine);
400     }
401 
402     /**
403      * @see org.kuali.rice.krad.document.DocumentBase#buildListOfDeletionAwareLists()
404      */
405 
406     @Override
407     public List buildListOfDeletionAwareLists() {
408         List managedLists = new ArrayList();
409 
410         managedLists.add(getSourceAccountingLines());
411 
412         return managedLists;
413     }
414 
415     /**
416      * @see org.kuali.rice.krad.bo.BusinessObjectBase#toStringMapper()
417      */
418     protected LinkedHashMap toStringMapper_RICE20_REFACTORME() {
419         LinkedHashMap m = new LinkedHashMap();
420         if (this.itemIdentifier != null) {
421             m.put("requisitionItemIdentifier", this.itemIdentifier.toString());
422         }
423         return m;
424     }
425 
426     @Override
427     public PurApAccountingLine getNewSourceLine() {
428         return newSourceLine;
429     }
430 
431     @Override
432     public void setNewSourceLine(PurApAccountingLine newAccountingLine) {
433         this.newSourceLine = newAccountingLine;
434     }
435 
436     @Override
437     public Integer getPurapDocumentIdentifier() {
438         return purapDocumentIdentifier;
439     }
440 
441     @Override
442     public void setPurapDocumentIdentifier(Integer purapDocumentIdentifier) {
443         this.purapDocumentIdentifier = purapDocumentIdentifier;
444     }
445 
446     @Override
447     public List<PurApItemUseTax> getUseTaxItems() {
448         return useTaxItems;
449     }
450 
451     @Override
452     public void setUseTaxItems(List<PurApItemUseTax> useTaxItems) {
453         this.useTaxItems = useTaxItems;
454     }
455 
456     @Override
457     public KualiDecimal getItemQuantity() {
458         return itemQuantity;
459     }
460 
461     @Override
462     public void setItemQuantity(KualiDecimal itemQuantity) {
463         this.itemQuantity = itemQuantity;
464     }
465 
466     public boolean isAccountListEmpty() {
467         List<PurApAccountingLine> accounts = getSourceAccountingLines();
468         if (ObjectUtils.isNotNull(accounts)) {
469             for (PurApAccountingLine element : accounts) {
470                 if (!element.isEmpty()) {
471                     return false;
472                 }
473             }
474         }
475         return true;
476     }
477 
478     @Override
479     public PurApSummaryItem getSummaryItem() {
480         PurApSummaryItem summaryItem = new PurApSummaryItem();
481         PurApObjectUtils.populateFromBaseClass(PurApItemBase.class, this, summaryItem, new HashMap());
482         summaryItem.getItemType().setItemTypeDescription(this.itemType.getItemTypeDescription());
483         return summaryItem;
484     }
485 
486     @Override
487     public final <T extends PurchasingAccountsPayableDocument> T getPurapDocument() {
488         return (T) purapDocument;
489     }
490 
491     @Override
492     public final void setPurapDocument(PurchasingAccountsPayableDocument purapDoc) {
493         this.purapDocument = purapDoc;
494     }
495 
496     /**
497      * fixes item references on accounts
498      *
499      * @see org.kuali.ole.module.purap.businessobject.PurApItem#fixAccountReferences()
500      */
501     @Override
502     public void fixAccountReferences() {
503         if (ObjectUtils.isNull(this.getItemIdentifier())) {
504             for (PurApAccountingLine account : this.getSourceAccountingLines()) {
505                 account.setSequenceNumber(0);
506                 account.setPurapItem(this);
507             }
508         }
509     }
510 
511     @Override
512     public void refreshNonUpdateableReferences() {
513         PurchasingAccountsPayableDocument document = null;
514         PurchasingAccountsPayableDocument tempDocument = getPurapDocument();
515         if (tempDocument != null) {
516             Integer tempDocumentIdentifier = tempDocument.getPurapDocumentIdentifier();
517             if (tempDocumentIdentifier != null) {
518                 document = this.getPurapDocument();
519             }
520         }
521         super.refreshNonUpdateableReferences();
522         if (ObjectUtils.isNotNull(document)) {
523             this.setPurapDocument(document);
524         }
525     }
526 
527     @Override
528     public KualiDecimal getTotalRemitAmount() {
529         if (!purapDocument.isUseTaxIndicator()) {
530             return this.getTotalAmount();
531         }
532         return this.getExtendedPrice();
533     }
534 
535     @Override
536     public String toString() {
537         return "Line " + (itemLineNumber == null ? "(null)" : itemLineNumber.toString()) + ": [" + itemTypeCode + "] " +
538                 "Unit:" + (itemUnitPrice == null ? "(null)" : itemUnitPrice.toString()) + " " +
539                 "Tax:" + (itemSalesTaxAmount == null ? "(null)" : itemSalesTaxAmount.toString()) + " " +
540                 "*" + itemDescription + "*";
541     }
542 
543 }