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.document;
18  
19  import org.apache.commons.lang.StringUtils;
20  import org.kuali.ole.module.purap.PurapConstants;
21  import org.kuali.ole.module.purap.PurapConstants.CREDIT_MEMO_TYPE_LABELS;
22  import org.kuali.ole.module.purap.PurapConstants.CreditMemoStatuses;
23  import org.kuali.ole.module.purap.PurapConstants.PurapDocTypeCodes;
24  import org.kuali.ole.module.purap.PurapParameterConstants;
25  import org.kuali.ole.module.purap.PurapPropertyConstants;
26  import org.kuali.ole.module.purap.PurapWorkflowConstants;
27  import org.kuali.ole.module.purap.businessobject.CreditMemoItem;
28  import org.kuali.ole.module.purap.businessobject.CreditMemoItemUseTax;
29  import org.kuali.ole.module.purap.document.service.*;
30  import org.kuali.ole.module.purap.document.validation.event.AttributedContinuePurapEvent;
31  import org.kuali.ole.module.purap.service.PurapGeneralLedgerService;
32  import org.kuali.ole.select.businessobject.OleInvoiceSubType;
33  import org.kuali.ole.select.businessobject.OleInvoiceType;
34  import org.kuali.ole.select.businessobject.OlePaymentMethod;
35  import org.kuali.ole.sys.OLEConstants;
36  import org.kuali.ole.sys.businessobject.AccountingLine;
37  import org.kuali.ole.sys.businessobject.GeneralLedgerPendingEntry;
38  import org.kuali.ole.sys.businessobject.GeneralLedgerPendingEntrySourceDetail;
39  import org.kuali.ole.sys.context.SpringContext;
40  import org.kuali.rice.core.api.util.type.KualiDecimal;
41  import org.kuali.rice.coreservice.framework.parameter.ParameterService;
42  import org.kuali.rice.kew.api.exception.WorkflowException;
43  import org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange;
44  import org.kuali.rice.kim.api.identity.Person;
45  import org.kuali.rice.kns.service.DataDictionaryService;
46  import org.kuali.rice.krad.bo.Note;
47  import org.kuali.rice.krad.rules.rule.event.KualiDocumentEvent;
48  import org.kuali.rice.krad.util.GlobalVariables;
49  import org.kuali.rice.krad.util.ObjectUtils;
50  import org.kuali.rice.krad.workflow.service.WorkflowDocumentService;
51  
52  import java.sql.Date;
53  import java.sql.Timestamp;
54  import java.util.List;
55  
56  /**
57   * Credit Memo Document Business Object. Contains the fields associated with the main document table.
58   */
59  public class VendorCreditMemoDocument extends AccountsPayableDocumentBase {
60      protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(VendorCreditMemoDocument.class);
61  
62      protected Integer paymentRequestIdentifier;
63      protected String creditMemoNumber;
64      protected Date creditMemoDate;
65      protected KualiDecimal creditMemoAmount;
66      protected Timestamp creditMemoPaidTimestamp;
67      protected String itemMiscellaneousCreditDescription;
68      protected Date purchaseOrderEndDate;
69      protected String vendorAttentionName;
70  
71      protected PaymentRequestDocument paymentRequestDocument;
72      private Integer invoiceTypeId;
73      private Integer invoiceSubTypeId;
74      private Integer paymentMethodId;
75  
76      // NOT PERSISTED IN DB
77      private String invoiceType;
78      private String invoiceSubType;
79      private String paymentMethod;
80  
81      // REFERENCE OBJECTS
82      private OleInvoiceSubType creditMemoInvoiceSubType;
83      private OleInvoiceType creditMemoInvoiceType;
84      private OlePaymentMethod olePaymentMethod;
85  
86      /**
87       * Default constructor.
88       */
89      public VendorCreditMemoDocument() {
90          super();
91      }
92  
93      public boolean isSourceDocumentPaymentRequest() {
94          return getPaymentRequestIdentifier() != null;
95      }
96  
97      public boolean isSourceDocumentPurchaseOrder() {
98          return (!isSourceDocumentPaymentRequest()) && (getPurchaseOrderIdentifier() != null);
99      }
100 
101     public boolean isSourceVendor() {
102         return (!isSourceDocumentPaymentRequest()) && (!isSourceDocumentPurchaseOrder());
103     }
104 
105     public Integer getInvoiceTypeId() {
106         return invoiceTypeId;
107     }
108 
109     public void setInvoiceTypeId(Integer invoiceTypeId) {
110         this.invoiceTypeId = invoiceTypeId;
111     }
112 
113     public Integer getInvoiceSubTypeId() {
114         return invoiceSubTypeId;
115     }
116 
117     public void setInvoiceSubTypeId(Integer invoiceSubTypeId) {
118         this.invoiceSubTypeId = invoiceSubTypeId;
119     }
120 
121     public Integer getPaymentMethodId() {
122         return paymentMethodId;
123     }
124 
125     public void setPaymentMethodId(Integer paymentMethodId) {
126         this.paymentMethodId = paymentMethodId;
127     }
128 
129     public String getInvoiceType() {
130         return invoiceType;
131     }
132 
133     public void setInvoiceType(String invoiceType) {
134         this.invoiceType = invoiceType;
135     }
136 
137     public String getInvoiceSubType() {
138         return invoiceSubType;
139     }
140 
141     public void setInvoiceSubType(String invoiceSubType) {
142         this.invoiceSubType = invoiceSubType;
143     }
144 
145     public String getPaymentMethod() {
146         return paymentMethod;
147     }
148 
149     public void setPaymentMethod(String paymentMethod) {
150         this.paymentMethod = paymentMethod;
151     }
152 
153     public OleInvoiceSubType getCreditMemoInvoiceSubType() {
154         return creditMemoInvoiceSubType;
155     }
156 
157     public void setCreditMemoInvoiceSubType(OleInvoiceSubType creditMemoInvoiceSubType) {
158         this.creditMemoInvoiceSubType = creditMemoInvoiceSubType;
159     }
160 
161     public OleInvoiceType getCreditMemoInvoiceType() {
162         return creditMemoInvoiceType;
163     }
164 
165     public void setCreditMemoInvoiceType(OleInvoiceType creditMemoInvoiceType) {
166         this.creditMemoInvoiceType = creditMemoInvoiceType;
167     }
168 
169     public OlePaymentMethod getOlePaymentMethod() {
170         return olePaymentMethod;
171     }
172 
173     public void setOlePaymentMethod(OlePaymentMethod olePaymentMethod) {
174         this.olePaymentMethod = olePaymentMethod;
175     }
176 
177     /**
178      * Overrides the method in PurchasingAccountsPayableDocumentBase to add the criteria
179      * specific to Credit Memo Document.
180      *
181      * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocumentBase#isInquiryRendered()
182      */
183     @Override
184     public boolean isInquiryRendered() {
185         if (isPostingYearPrior() &&
186                 (getApplicationDocumentStatus().equals(PurapConstants.CreditMemoStatuses.APPDOC_COMPLETE) ||
187                         getApplicationDocumentStatus().equals(PurapConstants.PaymentRequestStatuses.APPDOC_CANCELLED_POST_AP_APPROVE) ||
188                         getApplicationDocumentStatus().equals(PurapConstants.PaymentRequestStatuses.APPDOC_CANCELLED_IN_PROCESS))) {
189             return false;
190         } else {
191             return true;
192         }
193     }
194 
195     /**
196      * Initializes the values for a new document.
197      */
198     public void initiateDocument() {
199         LOG.debug("initiateDocument() started");
200         try {
201             updateAndSaveAppDocStatus(PurapConstants.CreditMemoStatuses.APPDOC_INITIATE);
202         } catch (WorkflowException e) {
203             logAndThrowRuntimeException("Error saving routing data while saving document with id " + getDocumentNumber(), e);
204         }
205 
206         Person currentUser = (Person) GlobalVariables.getUserSession().getPerson();
207         setAccountsPayableProcessorIdentifier(currentUser.getPrincipalId());
208         setProcessingCampusCode(currentUser.getCampusCode());
209     }
210 
211     /**
212      * Clear out the initially populated fields.
213      */
214     public void clearInitFields() {
215         LOG.debug("clearDocument() started");
216 
217         // Clearing document overview fields
218         getDocumentHeader().setDocumentDescription(null);
219         getDocumentHeader().setExplanation(null);
220         getFinancialSystemDocumentHeader().setFinancialDocumentTotalAmount(null);
221         getDocumentHeader().setOrganizationDocumentNumber(null);
222 
223         // Clearing document Init fields
224         setPurchaseOrderIdentifier(null);
225         setCreditMemoNumber(null);
226         setCreditMemoDate(null);
227         setCreditMemoAmount(null);
228         setVendorNumber(null);
229         setPaymentRequestIdentifier(null);
230     }
231 
232     /**
233      * Returns the type of the Credit Memo that was selected on the init screen. It is based on them entering the Vendor, PO or PREQ #.
234      *
235      * @return Vendor, PO or PREQ
236      */
237     public String getCreditMemoType() {
238         String type = CREDIT_MEMO_TYPE_LABELS.TYPE_VENDOR;
239         if (isSourceDocumentPaymentRequest()) {
240             type = CREDIT_MEMO_TYPE_LABELS.TYPE_PREQ;
241         } else if (isSourceDocumentPurchaseOrder()) {
242             type = CREDIT_MEMO_TYPE_LABELS.TYPE_PO;
243         }
244         return type;
245     }
246 
247     public boolean isBoNotesSupport() {
248         return true;
249     }
250 
251     /**
252      * Determines if the purchase order has notes, using the note service.
253      *
254      * @return - true if po has notes, false if po does not have notes
255      */
256     public boolean getPurchaseOrderNotes() {
257         boolean hasNotes = false;
258 
259         if (this.getNotes().size() > 0) {
260             hasNotes = true;
261         }
262 
263         return hasNotes;
264     }
265 
266     /**
267      * Determines the indicator text that will appear in the workflow document title
268      *
269      * @return - Text of hold
270      */
271     protected String getTitleIndicator() {
272         if (isHoldIndicator()) {
273             return PurapConstants.PaymentRequestIndicatorText.HOLD;
274         } else return "";
275     }
276 
277     /**
278      * @see org.kuali.rice.krad.document.DocumentBase#doRouteStatusChange()
279      */
280     @Override
281     public void doRouteStatusChange(DocumentRouteStatusChange statusChangeEvent) {
282         LOG.debug("doRouteStatusChange() started");
283         super.doRouteStatusChange(statusChangeEvent);
284 
285         try {
286             // DOCUMENT PROCESSED
287             if (this.getFinancialSystemDocumentHeader().getWorkflowDocument().isProcessed()) {
288                 updateAndSaveAppDocStatus(PurapConstants.CreditMemoStatuses.APPDOC_COMPLETE);
289 
290                 return;
291             }
292             // DOCUMENT DISAPPROVED
293             else if (this.getFinancialSystemDocumentHeader().getWorkflowDocument().isDisapproved()) {
294                 String nodeName = SpringContext.getBean(WorkflowDocumentService.class).getCurrentRouteLevelName(this.getFinancialSystemDocumentHeader().getWorkflowDocument());
295 
296                 String disapprovalStatus = CreditMemoStatuses.getCreditMemoAppDocDisapproveStatuses().get(nodeName);
297 
298                 if (((StringUtils.isBlank(disapprovalStatus)) && ((CreditMemoStatuses.APPDOC_INITIATE.equals(getApplicationDocumentStatus())) || (CreditMemoStatuses.APPDOC_IN_PROCESS.equals(getApplicationDocumentStatus()))))) {
299                     disapprovalStatus = CreditMemoStatuses.APPDOC_CANCELLED_IN_PROCESS;
300                     updateAndSaveAppDocStatus(disapprovalStatus);
301                 }
302                 if (StringUtils.isNotBlank(disapprovalStatus)) {
303                     SpringContext.getBean(AccountsPayableService.class).cancelAccountsPayableDocument(this, nodeName);
304                 } else {
305                     logAndThrowRuntimeException("No status found to set for document being disapproved in node '" + nodeName + "'");
306                 }
307             }
308             // DOCUMENT CANCELED
309             else if (this.getFinancialSystemDocumentHeader().getWorkflowDocument().isCanceled()) {
310                 String currentNodeName = this.getFinancialSystemDocumentHeader().getWorkflowDocument().getCurrentNodeNames().iterator().next();
311                 SpringContext.getBean(AccountsPayableService.class).cancelAccountsPayableDocument(this, currentNodeName);
312             }
313         } catch (Exception e) {
314             logAndThrowRuntimeException("Error saving routing data while saving document with id " + getDocumentNumber(), e);
315         }
316     }
317 
318     /**
319      * Hook point for performing actions that occur after a route level change, in this case; Performs logic necessary after full
320      * entry has been completed when past Adhoc Review, or sets the AP approval date when past AP review.
321      *
322      * @see org.kuali.ole.module.purap.document.AccountsPayableDocumentBase#preProcessNodeChange(java.lang.String, java.lang.String)
323      */
324     public boolean processNodeChange(String newNodeName, String oldNodeName) {
325         if (CreditMemoStatuses.NODE_ADHOC_REVIEW.equals(oldNodeName)) {
326             SpringContext.getBean(AccountsPayableService.class).performLogicForFullEntryCompleted(this);
327         }
328 
329         // if we've hit Account node then reopen po
330         else if (CreditMemoStatuses.NODE_ACCOUNT_REVIEW.equals(newNodeName) && this.isReopenPurchaseOrderIndicator()) {
331             SpringContext.getBean(PurapService.class).performLogicForCloseReopenPO(this);
332         }
333         return true;
334     }
335 
336     /**
337      * @see org.kuali.rice.krad.document.DocumentBase#getDocumentTitle()
338      */
339     @Override
340     public String getDocumentTitle() {
341         if (SpringContext.getBean(ParameterService.class).getParameterValueAsBoolean(VendorCreditMemoDocument.class, PurapParameterConstants.PURAP_OVERRIDE_CM_DOC_TITLE)) {
342             return getCustomDocumentTitle();
343         }
344         return super.getDocumentTitle();
345     }
346 
347     /**
348      * Returns a custom document title based on the workflow document title.
349      * Depending on the document status, the PO, vendor, amount, etc may be added to the documents title.
350      *
351      * @return - Customized document title text dependent upon route level.
352      */
353     protected String getCustomDocumentTitle() {
354         String popreq = "";
355         if (this.isSourceDocumentPurchaseOrder() || this.isSourceDocumentPaymentRequest()) {
356             String poNumber = getPurchaseOrderIdentifier().toString();
357             popreq = new StringBuffer("PO: ").append(poNumber).toString();
358         }
359 
360         String vendorName = StringUtils.trimToEmpty(getVendorName());
361         String cmAmount = getGrandTotal().toString();
362         String indicator = getTitleIndicator();
363         String documentTitle = new StringBuffer(popreq).append(" Vendor: ").append(vendorName).append(" Amount: ").append(cmAmount).append(" ").append(indicator).toString();
364         return documentTitle;
365     }
366 
367     /**
368      * @see org.kuali.ole.module.purap.document.AccountsPayableDocumentBase#saveDocumentFromPostProcessing()
369      */
370     public void saveDocumentFromPostProcessing() {
371         SpringContext.getBean(PurapService.class).saveDocumentNoValidation(this);
372     }
373 
374     /**
375      * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocumentBase#getItemClass()
376      */
377     @Override
378     public Class<CreditMemoItem> getItemClass() {
379         return CreditMemoItem.class;
380     }
381 
382     @Override
383     public Class getItemUseTaxClass() {
384         return CreditMemoItemUseTax.class;
385     }
386 
387     /**
388      * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocumentBase#getPurApSourceDocumentIfPossible()
389      */
390     @Override
391     public PurchasingAccountsPayableDocument getPurApSourceDocumentIfPossible() {
392         PurchasingAccountsPayableDocument sourceDocument = null;
393         if (isSourceDocumentPaymentRequest()) {
394             sourceDocument = getPaymentRequestDocument();
395         } else if (isSourceDocumentPurchaseOrder()) {
396             sourceDocument = getPurchaseOrderDocument();
397         }
398         return sourceDocument;
399     }
400 
401     /**
402      * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocumentBase#getPurApSourceDocumentLabelIfPossible()
403      */
404     @Override
405     public String getPurApSourceDocumentLabelIfPossible() {
406         PurchasingAccountsPayableDocument document = getPurApSourceDocumentIfPossible();
407         if (ObjectUtils.isNotNull(document)) {
408             return SpringContext.getBean(DataDictionaryService.class).getDocumentLabelByClass(document.getClass());
409         }
410         return null;
411     }
412 
413     /**
414      * Calculates the pretax total of the above the line items
415      *
416      * @return KualiDecimal - above the line item pretax total
417      */
418     public KualiDecimal getLineItemPreTaxTotal() {
419         KualiDecimal lineItemPreTaxTotal = KualiDecimal.ZERO;
420 
421         for (CreditMemoItem item : (List<CreditMemoItem>) getItems()) {
422             item.refreshReferenceObject(PurapPropertyConstants.ITEM_TYPE);
423             if (item.getItemType().isLineItemIndicator() && item.getExtendedPrice() != null) {
424                 lineItemPreTaxTotal = lineItemPreTaxTotal.add(item.getExtendedPrice());
425             }
426         }
427 
428         return lineItemPreTaxTotal;
429     }
430 
431     /**
432      * Calculates the total of the above the line items
433      *
434      * @return KualiDecimal - above the line item total
435      */
436     public KualiDecimal getLineItemTotal() {
437         KualiDecimal lineItemTotal = KualiDecimal.ZERO;
438 
439         for (CreditMemoItem item : (List<CreditMemoItem>) getItems()) {
440             item.refreshReferenceObject(PurapPropertyConstants.ITEM_TYPE);
441             if (item.getItemType().isLineItemIndicator() && item.getTotalAmount() != null) {
442                 lineItemTotal = lineItemTotal.add(item.getTotalAmount());
443             }
444         }
445 
446         return lineItemTotal;
447     }
448 
449     /**
450      * Calculates the credit memo total: Sum of above the line - restocking fees + misc amount
451      *
452      * @return KualiDecimal - credit memo document total
453      */
454     public KualiDecimal getGrandTotal() {
455         KualiDecimal grandTotal = KualiDecimal.ZERO;
456 
457         for (CreditMemoItem item : (List<CreditMemoItem>) getItems()) {
458             item.refreshReferenceObject(PurapPropertyConstants.ITEM_TYPE);
459 
460             if (item.getTotalAmount() != null) {
461                 // make sure restocking fee is negative
462                 if (StringUtils.equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_RESTCK_FEE_CODE, item.getItemTypeCode())) {
463                     if (ObjectUtils.isNotNull(item.getExtendedPrice())) {
464                         item.setExtendedPrice(item.getExtendedPrice().abs().negated());
465                     } else {
466                         item.setExtendedPrice(KualiDecimal.ZERO);
467                     }
468                 }
469                 grandTotal = grandTotal.add(item.getTotalAmount());
470             }
471         }
472 
473         return grandTotal;
474     }
475 
476     /**
477      * Calculates the credit memo pretax total: Sum of above the line - restocking fees + misc amount
478      *
479      * @return KualiDecimal - credit memo document total
480      */
481     public KualiDecimal getGrandPreTaxTotal() {
482         KualiDecimal grandTotal = KualiDecimal.ZERO;
483 
484         for (CreditMemoItem item : (List<CreditMemoItem>) getItems()) {
485             item.refreshReferenceObject(PurapPropertyConstants.ITEM_TYPE);
486 
487             if (item.getExtendedPrice() != null) {
488                 // make sure restocking fee is negative
489                 if (StringUtils.equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_RESTCK_FEE_CODE, item.getItemTypeCode())) {
490                     item.setExtendedPrice(item.getExtendedPrice().abs().negated());
491                 }
492                 grandTotal = grandTotal.add(item.getExtendedPrice());
493             }
494         }
495 
496         return grandTotal;
497     }
498 
499     /**
500      * Calculates the credit memo tax amount: Sum of above the line -
501      *
502      * @return KualiDecimal - credit memo document total
503      */
504     public KualiDecimal getGrandTaxAmount() {
505         KualiDecimal grandTotal = KualiDecimal.ZERO;
506 
507         for (CreditMemoItem item : (List<CreditMemoItem>) getItems()) {
508             item.refreshReferenceObject(PurapPropertyConstants.ITEM_TYPE);
509 
510             if (item.getItemTaxAmount() != null) {
511                 // make sure restocking fee is negative
512                 if (StringUtils.equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_RESTCK_FEE_CODE, item.getItemTypeCode())) {
513                     item.setExtendedPrice(item.getItemTaxAmount().abs().negated());
514                 }
515                 grandTotal = grandTotal.add(item.getItemTaxAmount());
516             }
517         }
518 
519         return grandTotal;
520     }
521 
522     public KualiDecimal getGrandPreTaxTotalExcludingRestockingFee() {
523         String[] restockingFeeCode = new String[]{PurapConstants.ItemTypeCodes.ITEM_TYPE_RESTCK_FEE_CODE};
524         return this.getTotalPreTaxDollarAmountWithExclusions(restockingFeeCode, true);
525     }
526 
527     public KualiDecimal getGrandTotalExcludingRestockingFee() {
528         String[] restockingFeeCode = new String[]{PurapConstants.ItemTypeCodes.ITEM_TYPE_RESTCK_FEE_CODE};
529         return this.getTotalDollarAmountWithExclusions(restockingFeeCode, true);
530     }
531 
532     public Integer getPaymentRequestIdentifier() {
533         return paymentRequestIdentifier;
534     }
535 
536     public void setPaymentRequestIdentifier(Integer paymentRequestIdentifier) {
537         this.paymentRequestIdentifier = paymentRequestIdentifier;
538     }
539 
540     public String getCreditMemoNumber() {
541         return creditMemoNumber;
542     }
543 
544     public void setCreditMemoNumber(String creditMemoNumber) {
545         if (creditMemoNumber != null) {
546             creditMemoNumber = creditMemoNumber.toUpperCase();
547         }
548 
549         this.creditMemoNumber = creditMemoNumber;
550     }
551 
552     public Date getCreditMemoDate() {
553         return creditMemoDate;
554     }
555 
556     public void setCreditMemoDate(Date creditMemoDate) {
557         this.creditMemoDate = creditMemoDate;
558     }
559 
560     public KualiDecimal getCreditMemoAmount() {
561         return creditMemoAmount;
562     }
563 
564     public void setCreditMemoAmount(KualiDecimal creditMemoAmount) {
565         this.creditMemoAmount = creditMemoAmount;
566     }
567 
568     public String getItemMiscellaneousCreditDescription() {
569         return itemMiscellaneousCreditDescription;
570     }
571 
572     public void setItemMiscellaneousCreditDescription(String itemMiscellaneousCreditDescription) {
573         this.itemMiscellaneousCreditDescription = itemMiscellaneousCreditDescription;
574     }
575 
576     public Timestamp getCreditMemoPaidTimestamp() {
577         return creditMemoPaidTimestamp;
578     }
579 
580     public void setCreditMemoPaidTimestamp(Timestamp creditMemoPaidTimestamp) {
581         this.creditMemoPaidTimestamp = creditMemoPaidTimestamp;
582     }
583 
584     public PaymentRequestDocument getPaymentRequestDocument() {
585         if ((ObjectUtils.isNull(paymentRequestDocument)) && (ObjectUtils.isNotNull(getPaymentRequestIdentifier()))) {
586             setPaymentRequestDocument(SpringContext.getBean(PaymentRequestService.class).getPaymentRequestById(getPaymentRequestIdentifier()));
587         }
588         return this.paymentRequestDocument;
589     }
590 
591     public void setPaymentRequestDocument(PaymentRequestDocument paymentRequestDocument) {
592         if (ObjectUtils.isNull(paymentRequestDocument)) {
593             // do not blank out input, instead throw an error
594             // setPaymentRequestIdentifier(null);
595             this.paymentRequestDocument = null;
596         } else {
597             setPaymentRequestIdentifier(paymentRequestDocument.getPurapDocumentIdentifier());
598             this.paymentRequestDocument = paymentRequestDocument;
599         }
600     }
601 
602     /**
603      * AS A REPLACEMENT USE getPaymentRequestDocument()
604      *
605      * @deprecated
606      */
607     public PaymentRequestDocument getPaymentRequest() {
608         return getPaymentRequestDocument();
609     }
610 
611     /**
612      * AS A REPLACEMENT USE setPaymentRequestDocument(PaymentRequestDocument)
613      *
614      * @deprecated
615      */
616     public void setPaymentRequest(PaymentRequestDocument paymentRequest) {
617         setPaymentRequestDocument(paymentRequest);
618     }
619 
620     /**
621      * AS A REPLACEMENT USE getPurchaseOrderDocument()
622      *
623      * @deprecated
624      */
625     public PurchaseOrderDocument getPurchaseOrder() {
626         return getPurchaseOrderDocument();
627     }
628 
629     /**
630      * AS A REPLACEMENT USE setPurchaseOrderDocument(PurchaseOrderDocument)
631      *
632      * @deprecated
633      */
634     public void setPurchaseOrder(PurchaseOrderDocument purchaseOrder) {
635         setPurchaseOrderDocument(purchaseOrder);
636     }
637 
638     public Date getPurchaseOrderEndDate() {
639         return purchaseOrderEndDate;
640     }
641 
642     public void setPurchaseOrderEndDate(Date purchaseOrderEndDate) {
643         this.purchaseOrderEndDate = purchaseOrderEndDate;
644     }
645 
646     /**
647      * @see org.kuali.ole.module.purap.document.AccountsPayableDocumentBase#getPoDocumentTypeForAccountsPayableDocumentApprove()
648      */
649     public String getPoDocumentTypeForAccountsPayableDocumentCancel() {
650         return PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_CLOSE_DOCUMENT;
651     }
652 
653     /**
654      * @see org.kuali.ole.module.purap.document.AccountsPayableDocumentBase#getInitialAmount()
655      */
656     public KualiDecimal getInitialAmount() {
657         return this.getCreditMemoAmount();
658     }
659 
660     /**
661      * Credit Memo document is first populated on Continue AP Event, and then prepareForSave continues.
662      *
663      * @see org.kuali.rice.krad.document.Document#prepareForSave(org.kuali.rice.krad.rule.event.KualiDocumentEvent)
664      */
665     @Override
666     public void prepareForSave(KualiDocumentEvent event) {
667 
668         // first populate, then call super
669         if (event instanceof AttributedContinuePurapEvent) {
670             SpringContext.getBean(CreditMemoService.class).populateDocumentAfterInit(this);
671         }
672 
673         super.prepareForSave(event);
674     }
675 
676     /**
677      * @see org.kuali.ole.module.purap.document.AccountsPayableDocumentBase#isAttachmentRequired()
678      */
679     @Override
680     protected boolean isAttachmentRequired() {
681         return StringUtils.equalsIgnoreCase("Y", SpringContext.getBean(ParameterService.class).getParameterValueAsString(VendorCreditMemoDocument.class, PurapParameterConstants.PURAP_CM_REQUIRE_ATTACHMENT));
682     }
683 
684     /**
685      * @see org.kuali.ole.module.purap.document.AccountsPayableDocument#getDocumentSpecificService()
686      */
687     @Override
688     public AccountsPayableDocumentSpecificService getDocumentSpecificService() {
689         return SpringContext.getBean(CreditMemoService.class);
690     }
691 
692     /**
693      * Forces GL entries to be approved before document final approval.
694      *
695      * @see org.kuali.module.purap.rules.PurapAccountingDocumentRuleBase#customizeExplicitGeneralLedgerPendingEntry(org.kuali.ole.sys.document.AccountingDocument, org.kuali.ole.sys.businessobject.AccountingLine, org.kuali.ole.sys.businessobject.GeneralLedgerPendingEntry)
696      */
697     @Override
698     public void customizeExplicitGeneralLedgerPendingEntry(GeneralLedgerPendingEntrySourceDetail postable, GeneralLedgerPendingEntry explicitEntry) {
699         super.customizeExplicitGeneralLedgerPendingEntry(postable, explicitEntry);
700 
701         SpringContext.getBean(PurapGeneralLedgerService.class).customizeGeneralLedgerPendingEntry(this, (AccountingLine) postable, explicitEntry, getPurchaseOrderIdentifier(), getDebitCreditCodeForGLEntries(), PurapDocTypeCodes.CREDIT_MEMO_DOCUMENT, isGenerateEncumbranceEntries());
702 
703         // CMs do not wait for document final approval to post GL entries; here we are forcing them to be APPROVED
704         explicitEntry.setFinancialDocumentApprovedCode(OLEConstants.PENDING_ENTRY_APPROVED_STATUS_CODE.APPROVED);
705     }
706 
707     public Date getTransactionTaxDate() {
708         return getCreditMemoDate();
709     }
710 
711     public String getVendorAttentionName() {
712         return vendorAttentionName;
713     }
714 
715     public void setVendorAttentionName(String vendorAttentionName) {
716         this.vendorAttentionName = vendorAttentionName;
717     }
718 
719     /**
720      * Provides answers to the following splits:
721      * RequiresInvoiceAttachment
722      *
723      * @see org.kuali.ole.sys.document.FinancialSystemTransactionalDocumentBase#answerSplitNodeQuestion(java.lang.String)
724      */
725     @Override
726     public boolean answerSplitNodeQuestion(String nodeName) throws UnsupportedOperationException {
727         if (nodeName.equals(PurapWorkflowConstants.REQUIRES_IMAGE_ATTACHMENT))
728             return requiresAccountsPayableReviewRouting();
729         throw new UnsupportedOperationException("Cannot answer split question for this node you call \"" + nodeName + "\"");
730     }
731 
732     public String getPaidIndicatorForResult() {
733         return getCreditMemoPaidTimestamp() != null ? "Yes" : "No";
734     }
735 
736     /**
737      * Checks all documents notes for attachments.
738      *
739      * @return - true if document does not have an image attached, false otherwise
740      */
741     public boolean documentHasNoImagesAttached() {
742         List boNotes = this.getNotes();
743         if (ObjectUtils.isNotNull(boNotes)) {
744             for (Object obj : boNotes) {
745                 Note note = (Note) obj;
746 
747                 note.refreshReferenceObject("attachment");
748                 if (ObjectUtils.isNotNull(note.getAttachment()) && PurapConstants.AttachmentTypeCodes.ATTACHMENT_TYPE_CM_IMAGE.equals(note.getAttachment().getAttachmentTypeCode())) {
749                     return false;
750                 }
751             }
752         }
753         return true;
754     }
755 
756 }
757