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.PurapPropertyConstants;
21  import org.kuali.ole.module.purap.document.PaymentRequestDocument;
22  import org.kuali.ole.module.purap.document.PurchaseOrderDocument;
23  import org.kuali.ole.module.purap.document.service.AccountsPayableService;
24  import org.kuali.ole.module.purap.document.service.PurapService;
25  import org.kuali.ole.module.purap.exception.PurError;
26  import org.kuali.ole.module.purap.util.ExpiredOrClosedAccountEntry;
27  import org.kuali.ole.module.purap.util.PurApItemUtils;
28  import org.kuali.ole.module.purap.util.PurApObjectUtils;
29  import org.kuali.ole.select.businessobject.OleInvoiceItem;
30  import org.kuali.ole.select.document.OlePaymentRequestDocument;
31  import org.kuali.ole.select.document.service.OlePaymentRequestService;
32  import org.kuali.ole.sys.businessobject.SourceAccountingLine;
33  import org.kuali.ole.sys.context.SpringContext;
34  import org.kuali.rice.core.api.util.type.KualiDecimal;
35  import org.kuali.rice.krad.util.ObjectUtils;
36  
37  import java.math.BigDecimal;
38  import java.util.ArrayList;
39  import java.util.HashMap;
40  import java.util.List;
41  
42  /**
43   * Payment Request Item Business Object.
44   */
45  public class PaymentRequestItem extends AccountsPayableItemBase {
46      private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PaymentRequestItem.class);
47  
48      protected BigDecimal purchaseOrderItemUnitPrice;
49      private KualiDecimal itemOutstandingInvoiceQuantity;
50      private KualiDecimal itemOutstandingInvoiceAmount;
51  
52      /**
53       * Default constructor.
54       */
55      public PaymentRequestItem() {
56  
57      }
58  
59      /**
60       * preq item constructor - Delegate
61       *
62       * @param poi  - purchase order item
63       * @param preq - payment request document
64       */
65      public PaymentRequestItem(PurchaseOrderItem poi, PaymentRequestDocument preq) {
66          this(poi, preq, new HashMap<String, ExpiredOrClosedAccountEntry>());
67      }
68  
69      /**
70       * Constructs a new payment request item, but also merges expired accounts.
71       *
72       * @param poi                        - purchase order item
73       * @param preq                       - payment request document
74       * @param expiredOrClosedAccountList - list of expired or closed accounts to merge
75       */
76      public PaymentRequestItem(PurchaseOrderItem poi, PaymentRequestDocument preq, HashMap<String, ExpiredOrClosedAccountEntry> expiredOrClosedAccountList) {
77  
78          // copy base attributes w/ extra array of fields not to be copied
79          PurApObjectUtils.populateFromBaseClass(PurApItemBase.class, poi, this, PurapConstants.PREQ_ITEM_UNCOPYABLE_FIELDS);
80  
81          setItemDescription(poi.getItemDescription());
82  
83          //New Source Line should be set for PaymentRequestItem
84          resetAccount();
85  
86          // set up accounts
87          List accounts = new ArrayList();
88          for (PurApAccountingLine account : poi.getSourceAccountingLines()) {
89              PurchaseOrderAccount poa = (PurchaseOrderAccount) account;
90  
91              // check if this account is expired/closed and replace as needed
92              SpringContext.getBean(AccountsPayableService.class).processExpiredOrClosedAccount(poa, expiredOrClosedAccountList);
93  
94              //KFSMI-4522 copy an accounting line with zero dollar amount if system parameter allows
95              if (poa.getAmount().isZero()) {
96                  if (SpringContext.getBean(AccountsPayableService.class).canCopyAccountingLinesWithZeroAmount()) {
97                      accounts.add(new PaymentRequestAccount(this, poa));
98                  }
99              } else {
100                 accounts.add(new PaymentRequestAccount(this, poa));
101             }
102         }
103 
104         this.setSourceAccountingLines(accounts);
105         this.getUseTaxItems().clear();
106         //List<PurApItemUseTax> newUseTaxItems = new ArrayList<PurApItemUseTax>();
107         /// this.setUseTaxItems(newUseTaxItems);
108         //copy use tax items over, and blank out keys (useTaxId and itemIdentifier)
109         /*
110         this.getUseTaxItems().clear();
111         for (PurApItemUseTax useTaxItem : poi.getUseTaxItems()) {
112             PaymentRequestItemUseTax newItemUseTax = new PaymentRequestItemUseTax(useTaxItem);
113             this.getUseTaxItems().add(newItemUseTax);
114 
115         }
116         */
117 
118         // clear amount and desc on below the line - we probably don't need that null
119         // itemType check but it's there just in case remove if it causes problems
120         // also do this if of type service
121         if ((ObjectUtils.isNotNull(this.getItemType()) && this.getItemType().isAmountBasedGeneralLedgerIndicator())) {
122             // setting unit price to be null to be more consistent with other below the line
123             this.setItemUnitPrice(null);
124         }
125 
126         // copy custom
127         this.purchaseOrderItemUnitPrice = poi.getItemUnitPrice();
128 //        this.purchaseOrderCommodityCode = poi.getPurchaseOrderCommodityCd();
129 
130         // set doc fields
131         this.setPurapDocumentIdentifier(preq.getPurapDocumentIdentifier());
132         this.setPurapDocument(preq);
133     }
134 
135     /**
136      * Retrieves a purchase order item by inspecting the item type to see if its above the line or below the line and returns the
137      * appropriate type.
138      *
139      * @return - purchase order item
140      */
141     @Override
142     public PurchaseOrderItem getPurchaseOrderItem() {
143         if (ObjectUtils.isNotNull(this.getPurapDocumentIdentifier())) {
144             if (ObjectUtils.isNull(this.getPaymentRequest())) {
145                 this.refreshReferenceObject(PurapPropertyConstants.PURAP_DOC);
146             }
147         }
148         // ideally we should do this a different way - maybe move it all into the service or save this info somehow (make sure and
149         // update though)
150         if (getPaymentRequest() != null) {
151             PurchaseOrderDocument po = getPaymentRequest().getPurchaseOrderDocument();
152             PurchaseOrderItem poi = null;
153             if (this.getItemType().isLineItemIndicator()) {
154                 List<PurchaseOrderItem> items = po.getItems();
155                 poi = items.get(this.getItemLineNumber().intValue() - 1);
156                 // throw error if line numbers don't match
157                 // MSU Contribution DTT-3014 OLEMI-8483 OLECNTRB-974
158                 /*
159                  * List items = po.getItems(); if (items != null) { for (Object object : items) { PurchaseOrderItem item =
160                  * (PurchaseOrderItem) object; if (item != null && item.getItemLineNumber().equals(this.getItemLineNumber())) { poi
161                  * = item; break; } } }
162                  */
163             } else {
164                 poi = (PurchaseOrderItem) SpringContext.getBean(PurapService.class).getBelowTheLineByType(po, this.getItemType());
165             }
166             if (poi != null) {
167                 return poi;
168             } else {
169                 if (LOG.isDebugEnabled()) {
170                     LOG.debug("getPurchaseOrderItem() Returning null because PurchaseOrderItem object for line number" + getItemLineNumber() + "or itemType " + getItemTypeCode() + " is null");
171                 }
172                 return null;
173             }
174         } else {
175 
176             LOG.error("getPurchaseOrderItem() Returning null because paymentRequest object is null");
177             throw new PurError("Payment Request Object in Purchase Order item line number " + getItemLineNumber() + "or itemType " + getItemTypeCode() + " is null");
178         }
179     }
180 
181     public KualiDecimal getPoOutstandingAmount() {
182         PurchaseOrderItem poi = getPurchaseOrderItem();
183         if (ObjectUtils.isNull(this.getPurchaseOrderItemUnitPrice()) || KualiDecimal.ZERO.equals(this.getPurchaseOrderItemUnitPrice())) {
184             return null;
185         } else {
186             return this.getPoOutstandingAmount(poi);
187         }
188     }
189 
190     private KualiDecimal getPoOutstandingAmount(PurchaseOrderItem poi) {
191         if (poi == null) {
192             return KualiDecimal.ZERO;
193         } else {
194             return poi.getItemOutstandingEncumberedAmount();
195         }
196     }
197 
198     public KualiDecimal getPoOriginalAmount() {
199         PurchaseOrderItem poi = getPurchaseOrderItem();
200         if (poi == null) {
201             return null;
202         } else {
203             return poi.getExtendedPrice();
204         }
205     }
206 
207     /**
208      * Exists due to a setter requirement by the htmlControlAttribute
209      *
210      * @param amount - po outstanding amount
211      * @deprecated
212      */
213     @Deprecated
214     public void setPoOutstandingAmount(KualiDecimal amount) {
215         // do nothing
216     }
217 
218 
219     public KualiDecimal getPoOutstandingQuantity() {
220         PurchaseOrderItem poi = getPurchaseOrderItem();
221         if (poi == null) {
222             return null;
223         } else {
224             if (PurapConstants.ItemTypeCodes.ITEM_TYPE_SERVICE_CODE.equals(this.getItemTypeCode())) {
225                 return null;
226             } else {
227                 return poi.getOutstandingQuantity();
228             }
229         }
230     }
231 
232     /**
233      * Exists due to a setter requirement by the htmlControlAttribute
234      *
235      * @param qty - po outstanding quantity
236      * @deprecated
237      */
238     @Deprecated
239     public void setPoOutstandingQuantity(KualiDecimal qty) {
240         // do nothing
241     }
242 
243     public BigDecimal getPurchaseOrderItemUnitPrice() {
244         return purchaseOrderItemUnitPrice;
245     }
246 
247     public BigDecimal getOriginalAmountfromPO() {
248         return purchaseOrderItemUnitPrice;
249     }
250 
251     public void setOriginalAmountfromPO(BigDecimal purchaseOrderItemUnitPrice) {
252         // Do nothing
253     }
254 
255     public void setPurchaseOrderItemUnitPrice(BigDecimal purchaseOrderItemUnitPrice) {
256         this.purchaseOrderItemUnitPrice = purchaseOrderItemUnitPrice;
257     }
258 
259     public KualiDecimal getItemOutstandingInvoiceAmount() {
260         return itemOutstandingInvoiceAmount;
261     }
262 
263     public void setItemOutstandingInvoiceAmount(KualiDecimal itemOutstandingInvoiceAmount) {
264         this.itemOutstandingInvoiceAmount = itemOutstandingInvoiceAmount;
265     }
266 
267     public KualiDecimal getItemOutstandingInvoiceQuantity() {
268         return itemOutstandingInvoiceQuantity;
269     }
270 
271     public void setItemOutstandingInvoiceQuantity(KualiDecimal itemOutstandingInvoiceQuantity) {
272         this.itemOutstandingInvoiceQuantity = itemOutstandingInvoiceQuantity;
273     }
274 
275     public PaymentRequestDocument getPaymentRequest() {
276         if (ObjectUtils.isNotNull(getPurapDocumentIdentifier())) {
277             if (ObjectUtils.isNull(getPurapDocument())) {
278                 this.refreshReferenceObject(PurapPropertyConstants.PURAP_DOC);
279             }
280         }
281         return super.getPurapDocument();
282     }
283 
284     public void setPaymentRequest(PaymentRequestDocument paymentRequest) {
285         this.setPurapDocument(paymentRequest);
286     }
287 
288     public void generateAccountListFromPoItemAccounts(List<PurApAccountingLine> accounts) {
289         for (PurApAccountingLine line : accounts) {
290             PurchaseOrderAccount poa = (PurchaseOrderAccount) line;
291             if (!line.isEmpty()) {
292                 getSourceAccountingLines().add(new PaymentRequestAccount(this, poa));
293             }
294         }
295     }
296 
297     /**
298      * @see org.kuali.ole.module.purap.businessobject.PurApItem#getAccountingLineClass()
299      */
300     @Override
301     public Class getAccountingLineClass() {
302         return PaymentRequestAccount.class;
303     }
304 
305     public boolean isDisplayOnPreq() {
306         PurchaseOrderItem poi = getPurchaseOrderItem();
307         if (ObjectUtils.isNull(poi)) {
308             LOG.debug("poi was null");
309             return false;
310         }
311 
312         // if the po item is not active... skip it
313         if (!poi.isItemActiveIndicator()) {
314             if (LOG.isDebugEnabled()) {
315                 LOG.debug("poi was not active: " + poi.toString());
316             }
317             return false;
318         }
319 
320         ItemType poiType = poi.getItemType();
321 
322         if (poiType.isQuantityBasedGeneralLedgerIndicator()) {
323             if (poi.getItemQuantity().isGreaterThan(poi.getItemInvoicedTotalQuantity())) {
324                 return true;
325             } else {
326                 if (ObjectUtils.isNotNull(this.getItemQuantity()) && this.getItemQuantity().isGreaterThan(KualiDecimal.ZERO)) {
327                     return true;
328                 }
329             }
330 
331             return false;
332         } else { // not quantity based
333             if (poi.getItemOutstandingEncumberedAmount().isGreaterThan(KualiDecimal.ZERO)) {
334                 return true;
335             } else {
336                 if (PurApItemUtils.isNonZeroExtended(this)) {
337                     return true;
338                 }
339                 return false;
340             }
341 
342         }
343     }
344 
345     /**
346      * sets account line percentage to zero.
347      *
348      * @see org.kuali.ole.module.purap.businessobject.PurApItem#resetAccount()
349      */
350     @Override
351     public void resetAccount() {
352         super.resetAccount();
353         this.getNewSourceLine().setAmount(null);
354         this.getNewSourceLine().setAccountLinePercent(new BigDecimal(0));
355     }
356 
357     /**
358      * Added for electronic invoice
359      */
360     public void addToUnitPrice(BigDecimal addThisValue) {
361         if (getItemUnitPrice() == null) {
362             setItemUnitPrice(BigDecimal.ZERO);
363         }
364         BigDecimal addedPrice = getItemUnitPrice().add(addThisValue);
365         setItemUnitPrice(addedPrice);
366     }
367 
368     public void addToExtendedPrice(KualiDecimal addThisValue) {
369         if (getExtendedPrice() == null) {
370             setExtendedPrice(KualiDecimal.ZERO);
371         }
372         KualiDecimal addedPrice = getExtendedPrice().add(addThisValue);
373         setExtendedPrice(addedPrice);
374     }
375 
376     @Override
377     public Class getUseTaxClass() {
378         return PaymentRequestItemUseTax.class;
379     }
380 
381     /**
382      * preq item constructor - Delegate
383      *
384      * @param poi  - purchase order item
385      * @param preq - payment request document
386      */
387     public PaymentRequestItem(OleInvoiceItem poi, OlePaymentRequestDocument preq) {
388         this(poi, preq, new HashMap<String, ExpiredOrClosedAccountEntry>());
389     }
390 
391 
392     /**
393      * Constructs a new payment request item, but also merges expired accounts.
394      *
395      * @param poi                        - purchase order item
396      * @param preq                       - payment request document
397      * @param expiredOrClosedAccountList - list of expired or closed accounts to merge
398      */
399     public PaymentRequestItem(OleInvoiceItem poi, OlePaymentRequestDocument preq, HashMap<String, ExpiredOrClosedAccountEntry> expiredOrClosedAccountList) {
400 
401         // copy base attributes w/ extra array of fields not to be copied
402         PurApObjectUtils.populateFromBaseClass(PurApItemBase.class, poi, this, PurapConstants.PREQ_ITEM_UNCOPYABLE_FIELDS);
403 
404         setItemDescription(poi.getItemDescription());
405 
406         //New Source Line should be set for PaymentRequestItem
407         resetAccount();
408 
409         // set up accounts
410         List accounts = new ArrayList();
411 
412         for (PurApAccountingLine account : poi.getSourceAccountingLines()) {
413             InvoiceAccount poa = (InvoiceAccount) account;
414 
415             // check if this account is expired/closed and replace as needed
416             SpringContext.getBean(AccountsPayableService.class).processExpiredOrClosedAccount(poa, expiredOrClosedAccountList);
417 
418             //KFSMI-4522 copy an accounting line with zero dollar amount if system parameter allows
419             if (poa.getAmount().isZero()) {
420                 if (SpringContext.getBean(AccountsPayableService.class).canCopyAccountingLinesWithZeroAmount()) {
421                     accounts.add(new PaymentRequestAccount(this, poa));
422                 }
423             } else {
424                 accounts.add(new PaymentRequestAccount(this, poa));
425             }
426         }
427 
428         this.setSourceAccountingLines(accounts);
429         this.getUseTaxItems().clear();
430         //List<PurApItemUseTax> newUseTaxItems = new ArrayList<PurApItemUseTax>();
431         /// this.setUseTaxItems(newUseTaxItems);
432         //copy use tax items over, and blank out keys (useTaxId and itemIdentifier)
433         /*
434         this.getUseTaxItems().clear();
435         for (PurApItemUseTax useTaxItem : poi.getUseTaxItems()) {
436             PaymentRequestItemUseTax newItemUseTax = new PaymentRequestItemUseTax(useTaxItem);
437             this.getUseTaxItems().add(newItemUseTax);
438 
439         }
440         */
441 
442         // clear amount and desc on below the line - we probably don't need that null
443         // itemType check but it's there just in case remove if it causes problems
444         // also do this if of type service
445         if ((ObjectUtils.isNotNull(this.getItemType()) && this.getItemType().isAmountBasedGeneralLedgerIndicator())) {
446             // setting unit price to be null to be more consistent with other below the line
447             // this.setItemUnitPrice(null);
448         }
449 
450         // copy custom
451         /*Modified for the jira -5458*/
452         this.purchaseOrderItemUnitPrice = poi.getPurchaseOrderItem()!=null ? poi.getPurchaseOrderItem().getItemUnitPrice() : null;
453 //        this.purchaseOrderCommodityCode = poi.getPurchaseOrderCommodityCd();
454 
455         // set doc fields
456         this.setPurapDocumentIdentifier(preq.getPurapDocumentIdentifier());
457         this.setPurapDocument(preq);
458     }
459 
460 }