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 017 package org.kuali.kfs.module.purap.businessobject; 018 019 import java.math.BigDecimal; 020 import java.util.ArrayList; 021 import java.util.HashMap; 022 import java.util.LinkedHashMap; 023 import java.util.List; 024 025 import org.apache.commons.lang.StringUtils; 026 import org.kuali.kfs.module.purap.PurapConstants; 027 import org.kuali.kfs.module.purap.PurapPropertyConstants; 028 import org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument; 029 import org.kuali.kfs.module.purap.util.PurApObjectUtils; 030 import org.kuali.rice.kns.bo.PersistableBusinessObjectBase; 031 import org.kuali.rice.kns.util.KualiDecimal; 032 import org.kuali.rice.kns.util.ObjectUtils; 033 import org.kuali.rice.kns.util.TypedArrayList; 034 035 /** 036 * Purap Item Base Business Object. 037 */ 038 public abstract class PurApItemBase extends PersistableBusinessObjectBase implements PurApItem { 039 040 private Integer itemIdentifier; 041 private Integer itemLineNumber; 042 private String itemUnitOfMeasureCode; 043 private String itemCatalogNumber; 044 private String itemDescription; 045 private BigDecimal itemUnitPrice; 046 private String itemTypeCode; 047 private String itemAuxiliaryPartIdentifier; 048 private String externalOrganizationB2bProductReferenceNumber; 049 private String externalOrganizationB2bProductTypeName; 050 private boolean itemAssignedToTradeInIndicator; 051 private KualiDecimal extendedPrice; // not currently in DB 052 private KualiDecimal itemSalesTaxAmount; 053 054 private List<PurApItemUseTax> useTaxItems; 055 private List<PurApAccountingLine> sourceAccountingLines; 056 private List<PurApAccountingLine> baselineSourceAccountingLines; 057 private PurApAccountingLine newSourceLine; 058 059 private ItemType itemType; 060 private Integer purapDocumentIdentifier; 061 private KualiDecimal itemQuantity; 062 063 private PurchasingAccountsPayableDocument purapDocument; 064 065 /** 066 * Default constructor. 067 */ 068 public PurApItemBase() { 069 itemTypeCode = PurapConstants.ItemTypeCodes.ITEM_TYPE_ITEM_CODE; 070 sourceAccountingLines = new TypedArrayList(getAccountingLineClass()); 071 baselineSourceAccountingLines = new TypedArrayList(getAccountingLineClass()); 072 useTaxItems = new TypedArrayList(getUseTaxClass()); 073 resetAccount(); 074 } 075 076 /** 077 * @see org.kuali.kfs.module.purap.businessobject.PurApItem#getItemIdentifierString() 078 */ 079 public String getItemIdentifierString() { 080 String itemLineNumberString = (getItemLineNumber() != null ? getItemLineNumber().toString() : ""); 081 String identifierString = (getItemType().isLineItemIndicator() ? "Item " + itemLineNumberString : getItemType().getItemTypeDescription()); 082 return identifierString; 083 } 084 085 public Integer getItemIdentifier() { 086 return itemIdentifier; 087 } 088 089 public void setItemIdentifier(Integer ItemIdentifier) { 090 this.itemIdentifier = ItemIdentifier; 091 } 092 093 public Integer getItemLineNumber() { 094 return itemLineNumber; 095 } 096 097 public void setItemLineNumber(Integer itemLineNumber) { 098 this.itemLineNumber = itemLineNumber; 099 } 100 101 public String getItemUnitOfMeasureCode() { 102 return itemUnitOfMeasureCode; 103 } 104 105 public void setItemUnitOfMeasureCode(String itemUnitOfMeasureCode) { 106 this.itemUnitOfMeasureCode = (StringUtils.isNotBlank(itemUnitOfMeasureCode) ? itemUnitOfMeasureCode.toUpperCase() : itemUnitOfMeasureCode); 107 } 108 109 public String getItemCatalogNumber() { 110 return itemCatalogNumber; 111 } 112 113 public void setItemCatalogNumber(String itemCatalogNumber) { 114 this.itemCatalogNumber = itemCatalogNumber; 115 } 116 117 public String getItemDescription() { 118 return itemDescription; 119 } 120 121 public void setItemDescription(String itemDescription) { 122 this.itemDescription = itemDescription; 123 } 124 125 public BigDecimal getItemUnitPrice() { 126 // Setting scale on retrieval of unit price 127 if (itemUnitPrice != null) { 128 if (itemUnitPrice.scale() < PurapConstants.DOLLAR_AMOUNT_MIN_SCALE) { 129 itemUnitPrice = itemUnitPrice.setScale(PurapConstants.DOLLAR_AMOUNT_MIN_SCALE, KualiDecimal.ROUND_BEHAVIOR); 130 } 131 else if (itemUnitPrice.scale() > PurapConstants.UNIT_PRICE_MAX_SCALE) { 132 itemUnitPrice = itemUnitPrice.setScale(PurapConstants.UNIT_PRICE_MAX_SCALE, KualiDecimal.ROUND_BEHAVIOR); 133 } 134 } 135 136 return itemUnitPrice; 137 } 138 139 public void setItemUnitPrice(BigDecimal itemUnitPrice) { 140 if (itemUnitPrice != null) { 141 if (itemUnitPrice.scale() < PurapConstants.DOLLAR_AMOUNT_MIN_SCALE) { 142 itemUnitPrice = itemUnitPrice.setScale(PurapConstants.DOLLAR_AMOUNT_MIN_SCALE, KualiDecimal.ROUND_BEHAVIOR); 143 } 144 else if (itemUnitPrice.scale() > PurapConstants.UNIT_PRICE_MAX_SCALE) { 145 itemUnitPrice = itemUnitPrice.setScale(PurapConstants.UNIT_PRICE_MAX_SCALE, KualiDecimal.ROUND_BEHAVIOR); 146 } 147 } 148 this.itemUnitPrice = itemUnitPrice; 149 } 150 151 public String getItemTypeCode() { 152 return itemTypeCode; 153 } 154 155 public void setItemTypeCode(String itemTypeCode) { 156 this.itemTypeCode = itemTypeCode; 157 } 158 159 public String getItemAuxiliaryPartIdentifier() { 160 return itemAuxiliaryPartIdentifier; 161 } 162 163 public void setItemAuxiliaryPartIdentifier(String itemAuxiliaryPartIdentifier) { 164 this.itemAuxiliaryPartIdentifier = itemAuxiliaryPartIdentifier; 165 } 166 167 public String getExternalOrganizationB2bProductReferenceNumber() { 168 return externalOrganizationB2bProductReferenceNumber; 169 } 170 171 public void setExternalOrganizationB2bProductReferenceNumber(String externalOrganizationB2bProductReferenceNumber) { 172 this.externalOrganizationB2bProductReferenceNumber = externalOrganizationB2bProductReferenceNumber; 173 } 174 175 public String getExternalOrganizationB2bProductTypeName() { 176 return externalOrganizationB2bProductTypeName; 177 } 178 179 public void setExternalOrganizationB2bProductTypeName(String externalOrganizationB2bProductTypeName) { 180 this.externalOrganizationB2bProductTypeName = externalOrganizationB2bProductTypeName; 181 } 182 183 public boolean getItemAssignedToTradeInIndicator() { 184 return itemAssignedToTradeInIndicator; 185 } 186 187 public void setItemAssignedToTradeInIndicator(boolean itemAssignedToTradeInIndicator) { 188 this.itemAssignedToTradeInIndicator = itemAssignedToTradeInIndicator; 189 } 190 191 public ItemType getItemType() { 192 if (ObjectUtils.isNull(itemType) || !itemType.getItemTypeCode().equals(itemTypeCode)) { 193 refreshReferenceObject(PurapPropertyConstants.ITEM_TYPE); 194 } 195 return itemType; 196 } 197 198 /** 199 * Sets the itemType attribute. 200 * 201 * @param itemType The itemType to set. 202 * @deprecated 203 */ 204 public void setItemType(ItemType itemType) { 205 this.itemType = itemType; 206 } 207 208 public KualiDecimal getItemTaxAmount() { 209 KualiDecimal taxAmount = KualiDecimal.ZERO; 210 211 if (ObjectUtils.isNull(purapDocument)) { 212 this.refreshReferenceObject("purapDocument"); 213 } 214 215 if (purapDocument.isUseTaxIndicator() == false) { 216 taxAmount = this.itemSalesTaxAmount; 217 } 218 else { 219 // sum use tax item tax amounts 220 for (PurApItemUseTax useTaxItem : this.getUseTaxItems()) { 221 taxAmount = taxAmount.add(useTaxItem.getTaxAmount()); 222 } 223 } 224 225 return taxAmount; 226 } 227 228 public void setItemTaxAmount(KualiDecimal itemTaxAmount) { 229 230 if (purapDocument == null) { 231 this.refreshReferenceObject("purapDocument"); 232 } 233 234 if (purapDocument.isUseTaxIndicator() == false) { 235 this.itemSalesTaxAmount = itemTaxAmount; 236 } 237 238 } 239 240 public final KualiDecimal getItemSalesTaxAmount() { 241 return itemSalesTaxAmount; 242 } 243 244 public final void setItemSalesTaxAmount(KualiDecimal itemSalesTaxAmount) { 245 this.itemSalesTaxAmount = itemSalesTaxAmount; 246 } 247 248 public KualiDecimal getExtendedPrice() { 249 return calculateExtendedPrice(); 250 } 251 252 public KualiDecimal getTotalAmount() { 253 KualiDecimal totalAmount = getExtendedPrice(); 254 if (ObjectUtils.isNull(totalAmount)) { 255 totalAmount = KualiDecimal.ZERO; 256 } 257 258 KualiDecimal taxAmount = getItemTaxAmount(); 259 if (ObjectUtils.isNull(taxAmount)) { 260 taxAmount = KualiDecimal.ZERO; 261 } 262 263 totalAmount = totalAmount.add(taxAmount); 264 265 return totalAmount; 266 } 267 268 public void setTotalAmount(KualiDecimal totalAmount) { 269 // do nothing, setter required by interface 270 } 271 272 public KualiDecimal calculateExtendedPrice() { 273 KualiDecimal extendedPrice = KualiDecimal.ZERO; 274 if (ObjectUtils.isNotNull(itemUnitPrice)) { 275 if (this.itemType.isAmountBasedGeneralLedgerIndicator()) { 276 // SERVICE ITEM: return unit price as extended price 277 extendedPrice = new KualiDecimal(this.itemUnitPrice.toString()); 278 } 279 else if (ObjectUtils.isNotNull(this.getItemQuantity())) { 280 BigDecimal calcExtendedPrice = this.itemUnitPrice.multiply(this.itemQuantity.bigDecimalValue()); 281 // ITEM TYPE (qty driven): return (unitPrice x qty) 282 extendedPrice = new KualiDecimal(calcExtendedPrice.setScale(KualiDecimal.SCALE, KualiDecimal.ROUND_BEHAVIOR)); 283 } 284 } 285 return extendedPrice; 286 } 287 288 public void setExtendedPrice(KualiDecimal extendedPrice) { 289 this.extendedPrice = extendedPrice; 290 } 291 292 public List<PurApAccountingLine> getSourceAccountingLines() { 293 return sourceAccountingLines; 294 } 295 296 public void setSourceAccountingLines(List<PurApAccountingLine> accountingLines) { 297 this.sourceAccountingLines = accountingLines; 298 } 299 300 public List<PurApAccountingLine> getBaselineSourceAccountingLines() { 301 return baselineSourceAccountingLines; 302 } 303 304 public void setBaselineSourceAccountingLines(List<PurApAccountingLine> baselineSourceLines) { 305 this.baselineSourceAccountingLines = baselineSourceLines; 306 } 307 308 /** 309 * This implementation is coupled tightly with some underlying issues that the Struts PojoProcessor plugin has with how objects 310 * get instantiated within lists. The first three lines are required otherwise when the PojoProcessor tries to automatically 311 * 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 312 * instances at indices before that one are not being instantiated. So changing the code below will cause adding lines to break 313 * if you add more than one item to the list. 314 * 315 * @see org.kuali.rice.kns.document.FinancialDocument#getTargetAccountingLine(int) 316 */ 317 public PurApAccountingLine getSourceAccountingLine(int index) { 318 return (PurApAccountingLine) getSourceAccountingLines().get(index); 319 } 320 321 public PurApAccountingLine getBaselineSourceAccountingLine(int index) { 322 return (PurApAccountingLine) getBaselineSourceAccountingLines().get(index); 323 } 324 325 private PurApAccountingLine getNewAccount() throws RuntimeException { 326 327 PurApAccountingLine newAccount = null; 328 try { 329 newAccount = (PurApAccountingLine) getAccountingLineClass().newInstance(); 330 } 331 catch (InstantiationException e) { 332 throw new RuntimeException("Unable to get class"); 333 } 334 catch (IllegalAccessException e) { 335 throw new RuntimeException("Unable to get class"); 336 } 337 catch (NullPointerException e) { 338 throw new RuntimeException("Can't instantiate Purchasing Account from base"); 339 } 340 return newAccount; 341 } 342 343 public abstract Class getAccountingLineClass(); 344 345 public abstract Class getUseTaxClass(); 346 347 public void resetAccount() { 348 // add a blank accounting line 349 PurApAccountingLine purApAccountingLine = getNewAccount(); 350 351 purApAccountingLine.setItemIdentifier(this.itemIdentifier); 352 purApAccountingLine.setPurapItem(this); 353 354 setNewSourceLine(purApAccountingLine); 355 } 356 357 /** 358 * @see org.kuali.rice.kns.document.DocumentBase#buildListOfDeletionAwareLists() 359 */ 360 @Override 361 public List buildListOfDeletionAwareLists() { 362 List managedLists = new ArrayList(); 363 364 managedLists.add(getSourceAccountingLines()); 365 366 return managedLists; 367 } 368 369 /** 370 * @see org.kuali.rice.kns.bo.BusinessObjectBase#toStringMapper() 371 */ 372 protected LinkedHashMap toStringMapper() { 373 LinkedHashMap m = new LinkedHashMap(); 374 if (this.itemIdentifier != null) { 375 m.put("requisitionItemIdentifier", this.itemIdentifier.toString()); 376 } 377 return m; 378 } 379 380 public PurApAccountingLine getNewSourceLine() { 381 return newSourceLine; 382 } 383 384 public void setNewSourceLine(PurApAccountingLine newAccountingLine) { 385 this.newSourceLine = newAccountingLine; 386 } 387 388 public Integer getPurapDocumentIdentifier() { 389 return purapDocumentIdentifier; 390 } 391 392 public void setPurapDocumentIdentifier(Integer purapDocumentIdentifier) { 393 this.purapDocumentIdentifier = purapDocumentIdentifier; 394 } 395 396 public List<PurApItemUseTax> getUseTaxItems() { 397 return useTaxItems; 398 } 399 400 public void setUseTaxItems(List<PurApItemUseTax> useTaxItems) { 401 this.useTaxItems = useTaxItems; 402 } 403 404 public KualiDecimal getItemQuantity() { 405 return itemQuantity; 406 } 407 408 public void setItemQuantity(KualiDecimal itemQuantity) { 409 this.itemQuantity = itemQuantity; 410 } 411 412 public boolean isAccountListEmpty() { 413 List<PurApAccountingLine> accounts = getSourceAccountingLines(); 414 if (ObjectUtils.isNotNull(accounts)) { 415 for (PurApAccountingLine element : accounts) { 416 if (!element.isEmpty()) { 417 return false; 418 } 419 } 420 } 421 return true; 422 } 423 424 public PurApSummaryItem getSummaryItem() { 425 PurApSummaryItem summaryItem = new PurApSummaryItem(); 426 PurApObjectUtils.populateFromBaseClass(PurApItemBase.class, this, summaryItem, new HashMap()); 427 summaryItem.getItemType().setItemTypeDescription(this.itemType.getItemTypeDescription()); 428 return summaryItem; 429 } 430 431 public final <T extends PurchasingAccountsPayableDocument> T getPurapDocument() { 432 return (T) purapDocument; 433 } 434 435 public final void setPurapDocument(PurchasingAccountsPayableDocument purapDoc) { 436 this.purapDocument = purapDoc; 437 } 438 439 /** 440 * fixes item references on accounts 441 * 442 * @see org.kuali.kfs.module.purap.businessobject.PurApItem#fixAccountReferences() 443 */ 444 public void fixAccountReferences() { 445 if (ObjectUtils.isNull(this.getItemIdentifier())) { 446 for (PurApAccountingLine account : this.getSourceAccountingLines()) { 447 account.setPurapItem(this); 448 } 449 } 450 } 451 452 @Override 453 public void refreshNonUpdateableReferences() { 454 PurchasingAccountsPayableDocument document = null; 455 PurchasingAccountsPayableDocument tempDocument = getPurapDocument(); 456 if (tempDocument != null) { 457 Integer tempDocumentIdentifier = tempDocument.getPurapDocumentIdentifier(); 458 if (tempDocumentIdentifier != null) { 459 document = this.getPurapDocument(); 460 } 461 } 462 super.refreshNonUpdateableReferences(); 463 if (ObjectUtils.isNotNull(document)) { 464 this.setPurapDocument(document); 465 } 466 } 467 468 public KualiDecimal getTotalRemitAmount() { 469 if (!purapDocument.isUseTaxIndicator()) { 470 return this.getTotalAmount(); 471 } 472 return this.getExtendedPrice(); 473 } 474 475 @Override 476 public String toString() { 477 return "Line "+(itemLineNumber==null?"(null)":itemLineNumber.toString())+": ["+itemTypeCode+"] " + 478 "Unit:"+(itemUnitPrice==null?"(null)":itemUnitPrice.toString())+" " + 479 "Tax:"+(itemSalesTaxAmount==null?"(null)":itemSalesTaxAmount.toString())+" " + 480 "*"+itemDescription+"*"; 481 } 482 483 }