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.document;
018
019 import java.math.BigDecimal;
020 import java.sql.Date;
021 import java.sql.Timestamp;
022 import java.text.SimpleDateFormat;
023 import java.util.ArrayList;
024 import java.util.Arrays;
025 import java.util.HashMap;
026 import java.util.Iterator;
027 import java.util.List;
028
029 import org.apache.commons.lang.StringUtils;
030 import org.kuali.kfs.module.purap.PurapConstants;
031 import org.kuali.kfs.module.purap.PurapParameterConstants;
032 import org.kuali.kfs.module.purap.PurapPropertyConstants;
033 import org.kuali.kfs.module.purap.PurapWorkflowConstants;
034 import org.kuali.kfs.module.purap.PurapConstants.PaymentRequestStatuses;
035 import org.kuali.kfs.module.purap.PurapConstants.PurapDocTypeCodes;
036 import org.kuali.kfs.module.purap.PurapWorkflowConstants.NodeDetails;
037 import org.kuali.kfs.module.purap.PurapWorkflowConstants.PaymentRequestDocument.NodeDetailEnum;
038 import org.kuali.kfs.module.purap.businessobject.ItemType;
039 import org.kuali.kfs.module.purap.businessobject.PaymentRequestItem;
040 import org.kuali.kfs.module.purap.businessobject.PaymentRequestItemUseTax;
041 import org.kuali.kfs.module.purap.businessobject.PurApAccountingLine;
042 import org.kuali.kfs.module.purap.businessobject.PurApItem;
043 import org.kuali.kfs.module.purap.businessobject.PurApItemUseTax;
044 import org.kuali.kfs.module.purap.businessobject.PurchaseOrderItem;
045 import org.kuali.kfs.module.purap.businessobject.PurchaseOrderItemUseTax;
046 import org.kuali.kfs.module.purap.businessobject.PurchasingCapitalAssetItem;
047 import org.kuali.kfs.module.purap.businessobject.RecurringPaymentType;
048 import org.kuali.kfs.module.purap.document.service.AccountsPayableDocumentSpecificService;
049 import org.kuali.kfs.module.purap.document.service.AccountsPayableService;
050 import org.kuali.kfs.module.purap.document.service.PaymentRequestService;
051 import org.kuali.kfs.module.purap.document.service.PurapService;
052 import org.kuali.kfs.module.purap.document.validation.event.AttributedContinuePurapEvent;
053 import org.kuali.kfs.module.purap.service.PurapGeneralLedgerService;
054 import org.kuali.kfs.module.purap.util.ExpiredOrClosedAccountEntry;
055 import org.kuali.kfs.module.purap.util.UseTaxContainer;
056 import org.kuali.kfs.sys.KFSConstants;
057 import org.kuali.kfs.sys.businessobject.AccountingLine;
058 import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntry;
059 import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail;
060 import org.kuali.kfs.sys.context.SpringContext;
061 import org.kuali.kfs.sys.service.UniversityDateService;
062 import org.kuali.kfs.vnd.VendorConstants;
063 import org.kuali.kfs.vnd.VendorPropertyConstants;
064 import org.kuali.kfs.vnd.businessobject.PaymentTermType;
065 import org.kuali.kfs.vnd.businessobject.PurchaseOrderCostSource;
066 import org.kuali.kfs.vnd.businessobject.ShippingPaymentTerms;
067 import org.kuali.kfs.vnd.businessobject.VendorAddress;
068 import org.kuali.kfs.vnd.businessobject.VendorDetail;
069 import org.kuali.kfs.vnd.document.service.VendorService;
070 import org.kuali.rice.kew.dto.ActionTakenEventDTO;
071 import org.kuali.rice.kew.dto.DocumentRouteStatusChangeDTO;
072 import org.kuali.rice.kew.exception.WorkflowException;
073 import org.kuali.rice.kim.bo.Person;
074 import org.kuali.rice.kns.bo.Note;
075 import org.kuali.rice.kns.rule.event.KualiDocumentEvent;
076 import org.kuali.rice.kns.service.DataDictionaryService;
077 import org.kuali.rice.kns.service.DateTimeService;
078 import org.kuali.rice.kns.service.KualiConfigurationService;
079 import org.kuali.rice.kns.service.ParameterService;
080 import org.kuali.rice.kns.util.GlobalVariables;
081 import org.kuali.rice.kns.util.KualiDecimal;
082 import org.kuali.rice.kns.util.ObjectUtils;
083 import org.kuali.rice.kns.workflow.service.KualiWorkflowDocument;
084 import org.kuali.rice.kns.workflow.service.WorkflowDocumentService;
085
086 /**
087 * Payment Request Document Business Object. Contains the fields associated with the main document table.
088 */
089 public class PaymentRequestDocument extends AccountsPayableDocumentBase {
090 protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PaymentRequestDocument.class);
091
092 protected Date invoiceDate;
093 protected String invoiceNumber;
094 protected KualiDecimal vendorInvoiceAmount;
095 protected String vendorPaymentTermsCode;
096 protected String vendorShippingPaymentTermsCode;
097 protected Date paymentRequestPayDate;
098 protected String paymentRequestCostSourceCode;
099 protected boolean paymentRequestedCancelIndicator;
100 protected boolean paymentAttachmentIndicator;
101 protected boolean immediatePaymentIndicator;
102 protected String specialHandlingInstructionLine1Text;
103 protected String specialHandlingInstructionLine2Text;
104 protected String specialHandlingInstructionLine3Text;
105 protected Timestamp paymentPaidTimestamp;
106 protected boolean paymentRequestElectronicInvoiceIndicator;
107 protected String accountsPayableRequestCancelIdentifier;
108 protected Integer originalVendorHeaderGeneratedIdentifier;
109 protected Integer originalVendorDetailAssignedIdentifier;
110 protected Integer alternateVendorHeaderGeneratedIdentifier;
111 protected Integer alternateVendorDetailAssignedIdentifier;
112 protected String purchaseOrderNotes;
113 protected String recurringPaymentTypeCode;
114 protected boolean receivingDocumentRequiredIndicator;
115 protected boolean paymentRequestPositiveApprovalIndicator;
116
117 // TAX EDIT AREA FIELDS
118 protected String taxClassificationCode;
119 protected String taxCountryCode;
120 protected String taxNQIId;
121 protected BigDecimal taxFederalPercent; // number is in whole form so 5% is 5.00
122 protected BigDecimal taxStatePercent; // number is in whole form so 5% is 5.00
123 protected KualiDecimal taxSpecialW4Amount;
124 protected Boolean taxGrossUpIndicator;
125 protected Boolean taxExemptTreatyIndicator;
126 protected Boolean taxForeignSourceIndicator;
127 protected Boolean taxUSAIDPerDiemIndicator;
128 protected Boolean taxOtherExemptIndicator;
129
130 // NOT PERSISTED IN DB
131 protected String vendorShippingTitleCode;
132 protected Date purchaseOrderEndDate;
133 protected String primaryVendorName;
134
135 // BELOW USED BY ROUTING
136 protected Integer requisitionIdentifier;
137
138 // REFERENCE OBJECTS
139 protected PaymentTermType vendorPaymentTerms;
140 protected ShippingPaymentTerms vendorShippingPaymentTerms;
141 protected PurchaseOrderCostSource paymentRequestCostSource;
142 protected RecurringPaymentType recurringPaymentType;
143
144 /**
145 * Default constructor.
146 */
147 public PaymentRequestDocument() {
148 super();
149 }
150
151 /**
152 * @see org.kuali.rice.kns.bo.PersistableBusinessObjectBase#isBoNotesSupport()
153 */
154 @Override
155 public boolean isBoNotesSupport() {
156 return true;
157 }
158
159 public Integer getPostingYearPriorOrCurrent() {
160 if (SpringContext.getBean(PaymentRequestService.class).allowBackpost(this)) {
161 // allow prior; use it
162 return SpringContext.getBean(UniversityDateService.class).getCurrentFiscalYear() - 1;
163 }
164 // don't allow prior; use CURRENT
165 return SpringContext.getBean(UniversityDateService.class).getCurrentFiscalYear();
166 }
167
168
169 /**
170 * Overrides the method in PurchasingAccountsPayableDocumentBase to add the criteria specific to Payment Request Document.
171 *
172 * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocumentBase#isInquiryRendered()
173 */
174 @Override
175 public boolean isInquiryRendered() {
176 if (isPostingYearPrior() && (getStatusCode().equals(PurapConstants.PaymentRequestStatuses.DEPARTMENT_APPROVED) || getStatusCode().equals(PurapConstants.PaymentRequestStatuses.AUTO_APPROVED) || getStatusCode().equals(PurapConstants.PaymentRequestStatuses.CANCELLED_POST_AP_APPROVE) || getStatusCode().equals(PurapConstants.PaymentRequestStatuses.CANCELLED_IN_PROCESS))) {
177 return false;
178 }
179 else {
180 return true;
181 }
182 }
183
184 public Integer getRequisitionIdentifier() {
185 return getPurchaseOrderDocument().getRequisitionIdentifier();
186 }
187
188 public void setRequisitionIdentifier(Integer requisitionIdentifier) {
189 this.requisitionIdentifier = requisitionIdentifier;
190 }
191
192 /**
193 * @see org.kuali.kfs.module.purap.document.AccountsPayableDocumentBase#populateDocumentForRouting()
194 */
195 @Override
196 public void populateDocumentForRouting() {
197 this.setRequisitionIdentifier(getPurchaseOrderDocument().getRequisitionIdentifier());
198 super.populateDocumentForRouting();
199 }
200
201 public Date getInvoiceDate() {
202 return invoiceDate;
203 }
204
205 public void setInvoiceDate(Date invoiceDate) {
206 this.invoiceDate = invoiceDate;
207 }
208
209 public String getInvoiceNumber() {
210 return invoiceNumber;
211 }
212
213 public void setInvoiceNumber(String invoiceNumber) {
214 if (!StringUtils.isEmpty(invoiceNumber))
215 this.invoiceNumber = invoiceNumber.toUpperCase();
216 else
217 this.invoiceNumber = invoiceNumber;
218 }
219
220 public KualiDecimal getVendorInvoiceAmount() {
221 return vendorInvoiceAmount;
222 }
223
224 public void setVendorInvoiceAmount(KualiDecimal vendorInvoiceAmount) {
225 this.vendorInvoiceAmount = vendorInvoiceAmount;
226 }
227
228 public String getVendorPaymentTermsCode() {
229 return vendorPaymentTermsCode;
230 }
231
232 public void setVendorPaymentTermsCode(String vendorPaymentTermsCode) {
233 this.vendorPaymentTermsCode = vendorPaymentTermsCode;
234 refreshReferenceObject("vendorPaymentTerms");
235 }
236
237 public PaymentTermType getVendorPaymentTerms() {
238 if (ObjectUtils.isNull(vendorPaymentTerms) || !StringUtils.equalsIgnoreCase(getVendorPaymentTermsCode(), vendorPaymentTerms.getVendorPaymentTermsCode())) {
239 refreshReferenceObject(VendorPropertyConstants.VENDOR_PAYMENT_TERMS);
240 }
241 return vendorPaymentTerms;
242 }
243
244 public void setVendorPaymentTerms(PaymentTermType vendorPaymentTerms) {
245 this.vendorPaymentTerms = vendorPaymentTerms;
246 }
247
248 public String getVendorShippingPaymentTermsCode() {
249 if (ObjectUtils.isNull(vendorPaymentTerms)) {
250 refreshReferenceObject(VendorPropertyConstants.VENDOR_SHIPPING_PAYMENT_TERMS);
251 }
252 return vendorShippingPaymentTermsCode;
253 }
254
255 public void setVendorShippingPaymentTermsCode(String vendorShippingPaymentTermsCode) {
256 this.vendorShippingPaymentTermsCode = vendorShippingPaymentTermsCode;
257 }
258
259 public Date getPaymentRequestPayDate() {
260 return paymentRequestPayDate;
261 }
262
263 public void setPaymentRequestPayDate(Date paymentRequestPayDate) {
264 this.paymentRequestPayDate = paymentRequestPayDate;
265 }
266
267 public String getPaymentRequestCostSourceCode() {
268 return paymentRequestCostSourceCode;
269 }
270
271 public void setPaymentRequestCostSourceCode(String paymentRequestCostSourceCode) {
272 this.paymentRequestCostSourceCode = paymentRequestCostSourceCode;
273 }
274
275 public boolean getPaymentRequestedCancelIndicator() {
276 return paymentRequestedCancelIndicator;
277 }
278
279 public boolean isPaymentRequestedCancelIndicator() {
280 return paymentRequestedCancelIndicator;
281 }
282
283 public void setPaymentRequestedCancelIndicator(boolean paymentRequestedCancelIndicator) {
284 this.paymentRequestedCancelIndicator = paymentRequestedCancelIndicator;
285 }
286
287 public boolean getPaymentAttachmentIndicator() {
288 return paymentAttachmentIndicator;
289 }
290
291 public void setPaymentAttachmentIndicator(boolean paymentAttachmentIndicator) {
292 this.paymentAttachmentIndicator = paymentAttachmentIndicator;
293 }
294
295 public boolean getImmediatePaymentIndicator() {
296 return immediatePaymentIndicator;
297 }
298
299 public void setImmediatePaymentIndicator(boolean immediatePaymentIndicator) {
300 this.immediatePaymentIndicator = immediatePaymentIndicator;
301 }
302
303 public String getSpecialHandlingInstructionLine1Text() {
304 return specialHandlingInstructionLine1Text;
305 }
306
307 public void setSpecialHandlingInstructionLine1Text(String specialHandlingInstructionLine1Text) {
308 this.specialHandlingInstructionLine1Text = specialHandlingInstructionLine1Text;
309 }
310
311 public String getSpecialHandlingInstructionLine2Text() {
312 return specialHandlingInstructionLine2Text;
313 }
314
315 public void setSpecialHandlingInstructionLine2Text(String specialHandlingInstructionLine2Text) {
316 this.specialHandlingInstructionLine2Text = specialHandlingInstructionLine2Text;
317 }
318
319 public String getSpecialHandlingInstructionLine3Text() {
320 return specialHandlingInstructionLine3Text;
321 }
322
323 public void setSpecialHandlingInstructionLine3Text(String specialHandlingInstructionLine3Text) {
324 this.specialHandlingInstructionLine3Text = specialHandlingInstructionLine3Text;
325 }
326
327 public Timestamp getPaymentPaidTimestamp() {
328 return paymentPaidTimestamp;
329 }
330
331 public void setPaymentPaidTimestamp(Timestamp paymentPaidTimestamp) {
332 this.paymentPaidTimestamp = paymentPaidTimestamp;
333 }
334
335 public boolean getPaymentRequestElectronicInvoiceIndicator() {
336 return paymentRequestElectronicInvoiceIndicator;
337 }
338
339 public void setPaymentRequestElectronicInvoiceIndicator(boolean paymentRequestElectronicInvoiceIndicator) {
340 this.paymentRequestElectronicInvoiceIndicator = paymentRequestElectronicInvoiceIndicator;
341 }
342
343 public String getAccountsPayableRequestCancelIdentifier() {
344 return accountsPayableRequestCancelIdentifier;
345 }
346
347 public void setAccountsPayableRequestCancelIdentifier(String accountsPayableRequestCancelIdentifier) {
348 this.accountsPayableRequestCancelIdentifier = accountsPayableRequestCancelIdentifier;
349 }
350
351 public Integer getOriginalVendorHeaderGeneratedIdentifier() {
352 return originalVendorHeaderGeneratedIdentifier;
353 }
354
355 public void setOriginalVendorHeaderGeneratedIdentifier(Integer originalVendorHeaderGeneratedIdentifier) {
356 this.originalVendorHeaderGeneratedIdentifier = originalVendorHeaderGeneratedIdentifier;
357 }
358
359 public Integer getOriginalVendorDetailAssignedIdentifier() {
360 return originalVendorDetailAssignedIdentifier;
361 }
362
363 public void setOriginalVendorDetailAssignedIdentifier(Integer originalVendorDetailAssignedIdentifier) {
364 this.originalVendorDetailAssignedIdentifier = originalVendorDetailAssignedIdentifier;
365 }
366
367 public Integer getAlternateVendorHeaderGeneratedIdentifier() {
368 return alternateVendorHeaderGeneratedIdentifier;
369 }
370
371 public void setAlternateVendorHeaderGeneratedIdentifier(Integer alternateVendorHeaderGeneratedIdentifier) {
372 this.alternateVendorHeaderGeneratedIdentifier = alternateVendorHeaderGeneratedIdentifier;
373 }
374
375 public Integer getAlternateVendorDetailAssignedIdentifier() {
376 return alternateVendorDetailAssignedIdentifier;
377 }
378
379 public void setAlternateVendorDetailAssignedIdentifier(Integer alternateVendorDetailAssignedIdentifier) {
380 this.alternateVendorDetailAssignedIdentifier = alternateVendorDetailAssignedIdentifier;
381 }
382
383 public ShippingPaymentTerms getVendorShippingPaymentTerms() {
384 return vendorShippingPaymentTerms;
385 }
386
387 public void setVendorShippingPaymentTerms(ShippingPaymentTerms vendorShippingPaymentTerms) {
388 this.vendorShippingPaymentTerms = vendorShippingPaymentTerms;
389 }
390
391 public String getVendorShippingTitleCode() {
392 if (ObjectUtils.isNotNull(this.getPurchaseOrderDocument())) {
393 return this.getPurchaseOrderDocument().getVendorShippingTitleCode();
394 }
395 return vendorShippingTitleCode;
396 }
397
398 public void setVendorShippingTitleCode(String vendorShippingTitleCode) {
399 this.vendorShippingTitleCode = vendorShippingTitleCode;
400 }
401
402 public Date getPurchaseOrderEndDate() {
403 return purchaseOrderEndDate;
404 }
405
406 public void setPurchaseOrderEndDate(Date purchaseOrderEndDate) {
407 this.purchaseOrderEndDate = purchaseOrderEndDate;
408 }
409
410 /**
411 * Gets the paymentRequestPositiveApprovalIndicator attribute.
412 *
413 * @return Returns the paymentRequestPositiveApprovalIndicator.
414 */
415 public boolean isPaymentRequestPositiveApprovalIndicator() {
416 return paymentRequestPositiveApprovalIndicator;
417 }
418
419 /**
420 * Sets the paymentRequestPositiveApprovalIndicator attribute value.
421 *
422 * @param paymentRequestPositiveApprovalIndicator The paymentRequestPositiveApprovalIndicator to set.
423 */
424 public void setPaymentRequestPositiveApprovalIndicator(boolean paymentRequestPositiveApprovalIndicator) {
425 this.paymentRequestPositiveApprovalIndicator = paymentRequestPositiveApprovalIndicator;
426 }
427
428 /**
429 * Gets the receivingDocumentRequiredIndicator attribute.
430 *
431 * @return Returns the receivingDocumentRequiredIndicator.
432 */
433 public boolean isReceivingDocumentRequiredIndicator() {
434 return receivingDocumentRequiredIndicator;
435 }
436
437 /**
438 * Sets the receivingDocumentRequiredIndicator attribute value.
439 *
440 * @param receivingDocumentRequiredIndicator The receivingDocumentRequiredIndicator to set.
441 */
442 public void setReceivingDocumentRequiredIndicator(boolean receivingDocumentRequiredIndicator) {
443 this.receivingDocumentRequiredIndicator = receivingDocumentRequiredIndicator;
444 }
445
446 /**
447 * Perform logic needed to initiate PREQ Document
448 */
449 public void initiateDocument() {
450 LOG.debug("initiateDocument() started");
451 Person currentUser = (Person) GlobalVariables.getUserSession().getPerson();
452 this.setStatusCode(PurapConstants.PaymentRequestStatuses.INITIATE);
453 this.setAccountsPayableProcessorIdentifier(currentUser.getPrincipalId());
454 this.setProcessingCampusCode(currentUser.getCampusCode());
455 this.refreshNonUpdateableReferences();
456 }
457
458 /**
459 * Perform logic needed to clear the initial fields on a PREQ Document
460 */
461 public void clearInitFields() {
462 LOG.debug("clearDocument() started");
463 // Clearing document overview fields
464 this.getDocumentHeader().setDocumentDescription(null);
465 this.getDocumentHeader().setExplanation(null);
466 this.getDocumentHeader().setFinancialDocumentTotalAmount(null);
467 this.getDocumentHeader().setOrganizationDocumentNumber(null);
468
469 // Clearing document Init fields
470 this.setPurchaseOrderIdentifier(null);
471 this.setInvoiceNumber(null);
472 this.setInvoiceDate(null);
473 this.setVendorInvoiceAmount(null);
474 this.setSpecialHandlingInstructionLine1Text(null);
475 this.setSpecialHandlingInstructionLine2Text(null);
476 this.setSpecialHandlingInstructionLine3Text(null);
477 }
478
479 /**
480 * Populates a preq from a PO - delegate method
481 *
482 * @param po -
483 */
484 public void populatePaymentRequestFromPurchaseOrder(PurchaseOrderDocument po) {
485 populatePaymentRequestFromPurchaseOrder(po, new HashMap<String, ExpiredOrClosedAccountEntry>());
486 }
487
488
489 /**
490 * Populates a preq from a PO
491 *
492 * @param po Purchase Order Document used for populating the PREQ
493 * @param expiredOrClosedAccountList a list of closed or expired accounts
494 */
495 public void populatePaymentRequestFromPurchaseOrder(PurchaseOrderDocument po, HashMap<String, ExpiredOrClosedAccountEntry> expiredOrClosedAccountList) {
496 this.setPurchaseOrderIdentifier(po.getPurapDocumentIdentifier());
497 this.getDocumentHeader().setOrganizationDocumentNumber(po.getDocumentHeader().getOrganizationDocumentNumber());
498 this.setPostingYear(po.getPostingYear());
499 this.setReceivingDocumentRequiredIndicator(po.isReceivingDocumentRequiredIndicator());
500 this.setUseTaxIndicator(po.isUseTaxIndicator());
501 this.setPaymentRequestPositiveApprovalIndicator(po.isPaymentRequestPositiveApprovalIndicator());
502 this.setVendorCustomerNumber(po.getVendorCustomerNumber());
503
504 if (po.getPurchaseOrderCostSource() != null) {
505 this.setPaymentRequestCostSource(po.getPurchaseOrderCostSource());
506 this.setPaymentRequestCostSourceCode(po.getPurchaseOrderCostSourceCode());
507 }
508
509 if (po.getVendorShippingPaymentTerms() != null) {
510 this.setVendorShippingPaymentTerms(po.getVendorShippingPaymentTerms());
511 this.setVendorShippingPaymentTermsCode(po.getVendorShippingPaymentTermsCode());
512 }
513
514 if (po.getVendorPaymentTerms() != null) {
515 this.setVendorPaymentTermsCode(po.getVendorPaymentTermsCode());
516 this.setVendorPaymentTerms(po.getVendorPaymentTerms());
517 }
518
519 if (po.getRecurringPaymentType() != null) {
520 this.setRecurringPaymentType(po.getRecurringPaymentType());
521 this.setRecurringPaymentTypeCode(po.getRecurringPaymentTypeCode());
522 }
523
524 this.setVendorHeaderGeneratedIdentifier(po.getVendorHeaderGeneratedIdentifier());
525 this.setVendorDetailAssignedIdentifier(po.getVendorDetailAssignedIdentifier());
526 this.setVendorCustomerNumber(po.getVendorCustomerNumber());
527 this.setVendorName(po.getVendorName());
528
529 // set original vendor
530 this.setOriginalVendorHeaderGeneratedIdentifier(po.getVendorHeaderGeneratedIdentifier());
531 this.setOriginalVendorDetailAssignedIdentifier(po.getVendorDetailAssignedIdentifier());
532
533 // set alternate vendor info as well
534 this.setAlternateVendorHeaderGeneratedIdentifier(po.getAlternateVendorHeaderGeneratedIdentifier());
535 this.setAlternateVendorDetailAssignedIdentifier(po.getAlternateVendorDetailAssignedIdentifier());
536
537 // populate preq vendor address with the default remit address type for the vendor if found
538 String userCampus = GlobalVariables.getUserSession().getPerson().getCampusCode();
539 VendorAddress vendorAddress = SpringContext.getBean(VendorService.class).getVendorDefaultAddress(po.getVendorHeaderGeneratedIdentifier(), po.getVendorDetailAssignedIdentifier(), VendorConstants.AddressTypes.REMIT, userCampus);
540 if (vendorAddress != null) {
541 this.templateVendorAddress(vendorAddress);
542 this.setVendorAddressGeneratedIdentifier(vendorAddress.getVendorAddressGeneratedIdentifier());
543 setVendorAttentionName(StringUtils.defaultString(vendorAddress.getVendorAttentionName()));
544 }
545 else {
546 // set address from PO
547 this.setVendorAddressGeneratedIdentifier(po.getVendorAddressGeneratedIdentifier());
548 this.setVendorLine1Address(po.getVendorLine1Address());
549 this.setVendorLine2Address(po.getVendorLine2Address());
550 this.setVendorCityName(po.getVendorCityName());
551 this.setVendorAddressInternationalProvinceName(po.getVendorAddressInternationalProvinceName());
552 this.setVendorStateCode(po.getVendorStateCode());
553 this.setVendorPostalCode(po.getVendorPostalCode());
554 this.setVendorCountryCode(po.getVendorCountryCode());
555
556 boolean blankAttentionLine = StringUtils.equalsIgnoreCase("Y", SpringContext.getBean(KualiConfigurationService.class).getParameterValue(PurapConstants.PURAP_NAMESPACE, "Document", PurapParameterConstants.BLANK_ATTENTION_LINE_FOR_PO_TYPE_ADDRESS));
557
558 if (blankAttentionLine) {
559 setVendorAttentionName(StringUtils.EMPTY);
560 }
561 else {
562 setVendorAttentionName(StringUtils.defaultString(po.getVendorAttentionName()));
563 }
564 }
565
566 this.setPaymentRequestPayDate(SpringContext.getBean(PaymentRequestService.class).calculatePayDate(this.getInvoiceDate(), this.getVendorPaymentTerms()));
567
568 AccountsPayableService accountsPayableService = SpringContext.getBean(AccountsPayableService.class);
569
570 if(SpringContext.getBean(PaymentRequestService.class).encumberedItemExistsForInvoicing(po))
571 {
572 for (PurchaseOrderItem poi : (List<PurchaseOrderItem>) po.getItems()) {
573 // check to make sure it's eligible for payment (i.e. active and has encumbrance available
574 if (getDocumentSpecificService().poItemEligibleForAp(this, poi)) {
575 PaymentRequestItem paymentRequestItem = new PaymentRequestItem(poi, this, expiredOrClosedAccountList);
576 this.getItems().add(paymentRequestItem);
577 PurchasingCapitalAssetItem purchasingCAMSItem = po.getPurchasingCapitalAssetItemByItemIdentifier(poi.getItemIdentifier());
578 if (purchasingCAMSItem != null) {
579 paymentRequestItem.setCapitalAssetTransactionTypeCode(purchasingCAMSItem.getCapitalAssetTransactionTypeCode());
580 }
581
582 /*
583 // copy usetaxitems over
584 paymentRequestItem.getUseTaxItems().clear();
585 for (PurApItemUseTax useTax : poi.getUseTaxItems()) {
586 paymentRequestItem.getUseTaxItems().add(useTax);
587 }
588 */
589 }
590 }
591 }
592
593 // add missing below the line
594 SpringContext.getBean(PurapService.class).addBelowLineItems(this);
595 this.setAccountsPayablePurchasingDocumentLinkIdentifier(po.getAccountsPayablePurchasingDocumentLinkIdentifier());
596
597 //fix up below the line items
598 SpringContext.getBean(PaymentRequestService.class).removeIneligibleAdditionalCharges(this);
599
600 this.fixItemReferences();
601 this.refreshNonUpdateableReferences();
602 }
603
604 /**
605 * @see org.kuali.rice.kns.document.DocumentBase#getDocumentTitle()
606 */
607 @Override
608 public String getDocumentTitle() {
609 if (SpringContext.getBean(ParameterService.class).getIndicatorParameter(PaymentRequestDocument.class, PurapParameterConstants.PURAP_OVERRIDE_PREQ_DOC_TITLE)) {
610 return getCustomDocumentTitle();
611 }
612 return this.buildDocumentTitle(super.getDocumentTitle());
613 }
614
615 /**
616 * Returns a custom document title based on the workflow document title. Depending on what route level the document is currently
617 * in, the PO, vendor, amount, account number, dept, campus may be added to the documents title.
618 *
619 * @return - Customized document title text dependent upon route level.
620 */
621 protected String getCustomDocumentTitle() {
622
623 try {
624 // set the workflow document title
625 String poNumber = getPurchaseOrderIdentifier().toString();
626 String vendorName = StringUtils.trimToEmpty(getVendorName());
627 String preqAmount = getGrandTotal().toString();
628
629 String documentTitle = "";
630 String[] nodeNames = getDocumentHeader().getWorkflowDocument().getNodeNames();
631
632 // if this doc is final or will be final
633 if (nodeNames.length == 0 || getDocumentHeader().getWorkflowDocument().stateIsFinal()) {
634 documentTitle = (new StringBuffer("PO: ")).append(poNumber).append(" Vendor: ").append(vendorName).append(" Amount: ").append(preqAmount).toString();
635 }
636 else {
637 PurApAccountingLine theAccount = getFirstAccount();
638 String accountNumber = (theAccount != null ? StringUtils.trimToEmpty(theAccount.getAccountNumber()) : "n/a");
639 String accountChart = (theAccount != null ? theAccount.getChartOfAccountsCode() : "");
640 String payDate = (new SimpleDateFormat("MM/dd/yyyy")).format(getPaymentRequestPayDate());
641 String indicator = getTitleIndicator();
642
643 //set title to: PO# - VendorName - Chart/Account - total amt - Pay Date - Indicator (ie Hold, Request Cancel)
644 documentTitle = (new StringBuffer("PO: ")).append(poNumber).append(" Vendor: ").append(vendorName).append(" Account: ").append(accountChart).append(" ").append(accountNumber).append(" Amount: ").append(preqAmount).append(" Pay Date: ").append(payDate).append(" ").append(indicator).toString();
645 }
646 return documentTitle;
647 }
648 catch (WorkflowException e) {
649 LOG.error("Error updating Payment Request document: " + e.getMessage());
650 throw new RuntimeException("Error updating Payment Request document: " + e.getMessage());
651 }
652 }
653
654 /**
655 * Returns the first payment item's first account (assuming the item list is sequentially ordered).
656 *
657 * @return - Accounting Line object for first account of first payment item.
658 */
659 public PurApAccountingLine getFirstAccount() {
660 // loop through items, and pick the first item
661 if ((getItems() != null) && (!getItems().isEmpty())) {
662 PaymentRequestItem itemToUse = null;
663 for (Iterator iter = getItems().iterator(); iter.hasNext();) {
664 PaymentRequestItem item = (PaymentRequestItem) iter.next();
665 if ((item.isConsideredEntered()) && ((item.getSourceAccountingLines() != null) && (!item.getSourceAccountingLines().isEmpty()))) {
666 // accounting lines are not empty so pick the first account
667 PurApAccountingLine accountLine = item.getSourceAccountingLine(0);
668 accountLine.refreshNonUpdateableReferences();
669 return accountLine;
670 }
671 /*
672 if (((item.getExtendedPrice() != null) && item.getExtendedPrice().compareTo(BigDecimal.ZERO) > 0) && ((item.getAccounts() != null) && (!item.getAccounts().isEmpty()))) {
673 // accounting lines are not empty so pick the first account
674 List accts = (List)item.getAccounts();
675 PaymentRequestAccount accountLine = (PaymentRequestAccount)accts.get(0);
676 return accountLine.getFinancialChartOfAccountsCode() + "-" + accountLine.getAccountNumber();
677 }
678 */
679 }
680 }
681 return null;
682 }
683
684 /**
685 * Determines the indicator text that will appear in the workflow document title
686 *
687 * @return - Text of hold or request cancel
688 */
689 protected String getTitleIndicator() {
690 if (isHoldIndicator()) {
691 return PurapConstants.PaymentRequestIndicatorText.HOLD;
692 }
693 else if (isPaymentRequestedCancelIndicator()) {
694 return PurapConstants.PaymentRequestIndicatorText.REQUEST_CANCEL;
695 }
696 return "";
697 }
698
699
700 /**
701 * @see org.kuali.rice.kns.document.DocumentBase#doRouteStatusChange()
702 */
703 @Override
704 public void doRouteStatusChange(DocumentRouteStatusChangeDTO statusChangeEvent) {
705 LOG.debug("doRouteStatusChange() started");
706
707 super.doRouteStatusChange(statusChangeEvent);
708 try {
709 // DOCUMENT PROCESSED
710 if (this.getDocumentHeader().getWorkflowDocument().stateIsProcessed()) {
711 if (!PaymentRequestStatuses.AUTO_APPROVED.equals(getStatusCode())) {
712 SpringContext.getBean(PurapService.class).updateStatus(this, PurapConstants.PaymentRequestStatuses.DEPARTMENT_APPROVED);
713 populateDocumentForRouting();
714 SpringContext.getBean(PurapService.class).saveDocumentNoValidation(this);
715 return;
716 }
717 }
718 // DOCUMENT DISAPPROVED
719 else if (this.getDocumentHeader().getWorkflowDocument().stateIsDisapproved()) {
720 String nodeName = SpringContext.getBean(WorkflowDocumentService.class).getCurrentRouteLevelName(getDocumentHeader().getWorkflowDocument());
721 NodeDetails currentNode = NodeDetailEnum.getNodeDetailEnumByName(nodeName);
722 if (ObjectUtils.isNotNull(currentNode)) {
723 String newStatusCode = currentNode.getDisapprovedStatusCode();
724 if ((StringUtils.isBlank(newStatusCode)) && ((StringUtils.isBlank(currentNode.getDisapprovedStatusCode())) && ((PaymentRequestStatuses.INITIATE.equals(getStatusCode())) || (PaymentRequestStatuses.IN_PROCESS.equals(getStatusCode()))))) {
725 newStatusCode = PaymentRequestStatuses.CANCELLED_IN_PROCESS;
726 }
727 if (StringUtils.isNotBlank(newStatusCode)) {
728 SpringContext.getBean(AccountsPayableService.class).cancelAccountsPayableDocument(this, nodeName);
729 return;
730 }
731 }
732 logAndThrowRuntimeException("No status found to set for document being disapproved in node '" + nodeName + "'");
733 }
734 // DOCUMENT CANCELED
735 else if (this.getDocumentHeader().getWorkflowDocument().stateIsCanceled()) {
736 String currentNodeName = SpringContext.getBean(WorkflowDocumentService.class).getCurrentRouteLevelName(this.getDocumentHeader().getWorkflowDocument());
737 NodeDetails currentNode = NodeDetailEnum.getNodeDetailEnumByName(currentNodeName);
738 if (ObjectUtils.isNotNull(currentNode)) {
739 String cancelledStatusCode = currentNode.getDisapprovedStatusCode();
740 if (StringUtils.isNotBlank(cancelledStatusCode)) {
741 SpringContext.getBean(PurapService.class).updateStatus(this, cancelledStatusCode);
742 SpringContext.getBean(PurapService.class).saveDocumentNoValidation(this);
743 return;
744 }
745 }
746 logAndThrowRuntimeException("No status found to set for document being canceled in node '" + currentNode + "'");
747 }
748 }
749 catch (WorkflowException e) {
750 logAndThrowRuntimeException("Error saving routing data while saving document with id " + getDocumentNumber(), e);
751 }
752 }
753
754 /**
755 * Generates correcting entries to the GL if accounts are modified.
756 *
757 * @see org.kuali.rice.kns.document.Document#doActionTaken(org.kuali.rice.kew.clientapp.vo.ActionTakenEventDTO)
758 */
759 @Override
760 public void doActionTaken(ActionTakenEventDTO event) {
761 super.doActionTaken(event);
762 KualiWorkflowDocument workflowDocument = getDocumentHeader().getWorkflowDocument();
763 try {
764 String currentNode = null;
765 if (workflowDocument.getNodeNames().length > 0) {
766 currentNode = workflowDocument.getNodeNames()[0];
767 }
768
769 // everything in the below list requires correcting entries to be written to the GL
770 if (NodeDetailEnum.getNodesRequiringCorrectingGeneralLedgerEntries().contains(currentNode)) {
771 if (NodeDetailEnum.ACCOUNT_REVIEW.getName().equals(currentNode) || NodeDetailEnum.VENDOR_TAX_REVIEW.getName().equals(currentNode)) {
772 SpringContext.getBean(PurapGeneralLedgerService.class).generateEntriesModifyPaymentRequest(this);
773 }
774 }
775 }
776 catch (WorkflowException e) {
777 logAndThrowRuntimeException("Error saving routing data while saving document with id " + getDocumentNumber(), e);
778 }
779 }
780
781 /**
782 * @see org.kuali.kfs.module.purap.document.AccountsPayableDocumentBase#preProcessNodeChange(java.lang.String, java.lang.String)
783 */
784 public boolean processNodeChange(String newNodeName, String oldNodeName) {
785 if (PaymentRequestStatuses.AUTO_APPROVED.equals(getStatusCode())) {
786 // do nothing for an auto approval
787 return false;
788 }
789 if (NodeDetailEnum.ADHOC_REVIEW.getName().equals(oldNodeName)) {
790 SpringContext.getBean(AccountsPayableService.class).performLogicForFullEntryCompleted(this);
791 }
792 return true;
793 }
794
795 /**
796 * @see org.kuali.kfs.module.purap.document.AccountsPayableDocumentBase#getNodeDetailEnum(java.lang.String)
797 */
798 public NodeDetails getNodeDetailEnum(String nodeName) {
799 return NodeDetailEnum.getNodeDetailEnumByName(nodeName);
800 }
801
802 /**
803 * @see org.kuali.kfs.module.purap.document.AccountsPayableDocumentBase#saveDocumentFromPostProcessing()
804 */
805 public void saveDocumentFromPostProcessing() {
806 SpringContext.getBean(PurapService.class).saveDocumentNoValidation(this);
807
808 // if we've hit full entry completed then close/reopen po
809 if (SpringContext.getBean(PurapService.class).isFullDocumentEntryCompleted(this) && this.isClosePurchaseOrderIndicator()) {
810 SpringContext.getBean(PurapService.class).performLogicForCloseReopenPO(this);
811 }
812 }
813
814 /**
815 * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocumentBase#getItemClass()
816 */
817 @Override
818 public Class getItemClass() {
819 return PaymentRequestItem.class;
820 }
821
822 @Override
823 public Class getItemUseTaxClass() {
824 return PaymentRequestItemUseTax.class;
825 }
826
827 /**
828 * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocumentBase#getPurApSourceDocumentIfPossible()
829 */
830 @Override
831 public PurchaseOrderDocument getPurApSourceDocumentIfPossible() {
832 return getPurchaseOrderDocument();
833 }
834
835 /**
836 * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocumentBase#getPurApSourceDocumentLabelIfPossible()
837 */
838 @Override
839 public String getPurApSourceDocumentLabelIfPossible() {
840 return SpringContext.getBean(DataDictionaryService.class).getDocumentLabelByTypeName(KFSConstants.FinancialDocumentTypeCodes.PURCHASE_ORDER);
841 }
842
843 public String getPurchaseOrderNotes() {
844
845 ArrayList poNotes = (ArrayList) this.getPurchaseOrderDocument().getBoNotes();
846
847 if (poNotes.size() > 0) {
848 return "Yes";
849 }
850 return "No";
851 }
852
853 public void setPurchaseOrderNotes(String purchaseOrderNotes) {
854 this.purchaseOrderNotes = purchaseOrderNotes;
855 }
856
857 public String getRecurringPaymentTypeCode() {
858 return recurringPaymentTypeCode;
859 }
860
861 public void setRecurringPaymentTypeCode(String recurringPaymentTypeCode) {
862 this.recurringPaymentTypeCode = recurringPaymentTypeCode;
863 }
864
865 /**
866 * Returns the total encumbered amount from the purchase order excluding below the line.
867 *
868 * @return Total cost excluding below the line
869 */
870 public KualiDecimal getItemTotalPoEncumbranceAmount() {
871 // get total from po excluding below the line and inactive
872 return this.getPurchaseOrderDocument().getTotalDollarAmount(false, false);
873 }
874
875 public KualiDecimal getItemTotalPoEncumbranceAmountRelieved() {
876 return getItemTotalPoEncumbranceAmountRelieved(false);
877 }
878
879 public KualiDecimal getItemTotalPoEncumbranceAmountRelieved(boolean includeBelowTheLine) {
880
881 KualiDecimal total = KualiDecimal.ZERO;
882
883 for (PurchaseOrderItem item : (List<PurchaseOrderItem>) getPurchaseOrderDocument().getItems()) {
884 ItemType it = item.getItemType();
885 if (includeBelowTheLine || it.isLineItemIndicator()) {
886 total = total.add(item.getItemEncumbranceRelievedAmount());
887 }
888 }
889 return total;
890 }
891
892 public KualiDecimal getLineItemTotal() {
893 return this.getTotalDollarAmountAboveLineItems();
894 }
895
896 public KualiDecimal getLineItemPreTaxTotal() {
897 return this.getTotalPreTaxDollarAmountAboveLineItems();
898 }
899
900 public KualiDecimal getLineItemTaxAmount() {
901 return this.getTotalTaxAmountAboveLineItems();
902 }
903
904 public KualiDecimal getGrandTotal() {
905 return this.getTotalDollarAmount();
906 }
907
908 public KualiDecimal getGrandTotalExcludingDiscount() {
909 String[] discountCode = new String[] { PurapConstants.ItemTypeCodes.ITEM_TYPE_PMT_TERMS_DISCOUNT_CODE };
910 return this.getTotalDollarAmountWithExclusions(discountCode, true);
911 }
912
913 /**
914 * This method is here due to a setter requirement by the htmlControlAttribute
915 *
916 * @param amount - Grand total for document, excluding discount
917 */
918 public void setGrandTotalExcludingDiscount(KualiDecimal amount) {
919 // do nothing
920 }
921
922 public KualiDecimal getGrandPreTaxTotal() {
923 return this.getTotalPreTaxDollarAmount();
924 }
925
926 public KualiDecimal getGrandPreTaxTotalExcludingDiscount() {
927 String[] discountCode = new String[] { PurapConstants.ItemTypeCodes.ITEM_TYPE_PMT_TERMS_DISCOUNT_CODE };
928 return this.getTotalPreTaxDollarAmountWithExclusions(discountCode, true);
929 }
930
931 public KualiDecimal getGrandTaxAmount() {
932 return this.getTotalTaxAmount();
933 }
934
935 public KualiDecimal getGrandTaxAmountExcludingDiscount() {
936 String[] discountCode = new String[] { PurapConstants.ItemTypeCodes.ITEM_TYPE_PMT_TERMS_DISCOUNT_CODE };
937 return this.getTotalTaxAmountWithExclusions(discountCode, true);
938 }
939
940 public boolean isDiscount() {
941 return SpringContext.getBean(PaymentRequestService.class).hasDiscountItem(this);
942 }
943
944 /**
945 * The total that was paid on the po excluding below the line
946 *
947 * @return total paid
948 */
949 public KualiDecimal getItemTotalPoPaidAmount() {
950 KualiDecimal total = KualiDecimal.ZERO;
951 for (PurchaseOrderItem item : (List<PurchaseOrderItem>) getPurchaseOrderDocument().getItems()) {
952 ItemType iT = item.getItemType();
953 if (iT.isLineItemIndicator()) {
954 KualiDecimal itemPaid = item.getItemPaidAmount();
955 total = total.add(itemPaid);
956 }
957 }
958 return total;
959 }
960
961 /**
962 * Returns the name of who requested cancel.
963 *
964 * @return - name of who requested cancel.
965 */
966 public String getAccountsPayableRequestCancelPersonName() {
967 String personName = null;
968 Person user = SpringContext.getBean(org.kuali.rice.kim.service.PersonService.class).getPerson(getAccountsPayableRequestCancelIdentifier());
969 if (user != null) {
970 personName = user.getName();
971 }
972 else {
973 personName = "";
974 }
975
976 return personName;
977 }
978
979 /**
980 * Exists due to a setter requirement by the htmlControlAttribute
981 *
982 * @param amount - total po amount paid
983 */
984 public void setItemTotalPoPaidAmount(KualiDecimal amount) {
985 // do nothing
986 }
987
988 /**
989 * Exists due to a setter requirement by the htmlControlAttribute
990 *
991 * @param amount - total po encumbrance
992 */
993 public void setItemTotalPoEncumbranceAmount(KualiDecimal amount) {
994 // do nothing
995 }
996
997 /**
998 * Exists due to a setter requirement by the htmlControlAttribute
999 *
1000 * @param amount - total po encumbrance amount relieved
1001 */
1002 public void setItemTotalPoEncumbranceAmountRelieved(KualiDecimal amount) {
1003 // do nothing
1004 }
1005
1006 /**
1007 * Determinines the route levels for a given document.
1008 *
1009 * @param workflowDocument - work flow document
1010 * @return List - list of route levels
1011 */
1012 protected List getCurrentRouteLevels(KualiWorkflowDocument workflowDocument) {
1013 try {
1014 return Arrays.asList(workflowDocument.getNodeNames());
1015 }
1016 catch (WorkflowException e) {
1017 throw new RuntimeException(e);
1018 }
1019 }
1020
1021 /**
1022 * USED FOR ROUTING ONLY
1023 *
1024 * @deprecated
1025 */
1026 public String getStatusDescription() {
1027 return "";
1028 }
1029
1030 /**
1031 * USED FOR ROUTING ONLY
1032 *
1033 * @deprecated
1034 */
1035 public void setStatusDescription(String statusDescription) {
1036 }
1037
1038 public RecurringPaymentType getRecurringPaymentType() {
1039 if (ObjectUtils.isNull(recurringPaymentType)) {
1040 refreshReferenceObject(PurapPropertyConstants.RECURRING_PAYMENT_TYPE);
1041 }
1042 return recurringPaymentType;
1043 }
1044
1045 public void setRecurringPaymentType(RecurringPaymentType recurringPaymentType) {
1046 this.recurringPaymentType = recurringPaymentType;
1047 }
1048
1049 public PurchaseOrderCostSource getPaymentRequestCostSource() {
1050 return paymentRequestCostSource;
1051 }
1052
1053 public void setPaymentRequestCostSource(PurchaseOrderCostSource paymentRequestCostSource) {
1054 this.paymentRequestCostSource = paymentRequestCostSource;
1055 }
1056
1057 /**
1058 * @see org.kuali.kfs.module.purap.document.AccountsPayableDocumentBase#getPoDocumentTypeForAccountsPayableDocumentApprove()
1059 */
1060 public String getPoDocumentTypeForAccountsPayableDocumentCancel() {
1061 return PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_REOPEN_DOCUMENT;
1062 }
1063
1064 /**
1065 * @see org.kuali.kfs.module.purap.document.AccountsPayableDocumentBase#getInitialAmount()
1066 */
1067 public KualiDecimal getInitialAmount() {
1068 return this.getVendorInvoiceAmount();
1069 }
1070
1071 /**
1072 * Populates the payment request document, then continues with preparing for save.
1073 *
1074 * @see org.kuali.rice.kns.document.Document#prepareForSave(org.kuali.rice.kns.rule.event.KualiDocumentEvent)
1075 */
1076 @Override
1077 public void prepareForSave(KualiDocumentEvent event) {
1078 KualiWorkflowDocument workflowDocument = this.getDocumentHeader().getWorkflowDocument();
1079 String workflowDocumentTitle = this.buildDocumentTitle(workflowDocument.getTitle());
1080
1081 try {
1082 this.getDocumentHeader().getWorkflowDocument().setTitle(workflowDocumentTitle);
1083 }
1084 catch (WorkflowException e) {
1085 LOG.error("fail to access Workflow." + e);
1086 }
1087
1088 // first populate, then call super
1089 if (event instanceof AttributedContinuePurapEvent) {
1090 SpringContext.getBean(PaymentRequestService.class).populatePaymentRequest(this);
1091 }
1092 super.prepareForSave(event);
1093
1094 }
1095
1096 /**
1097 * @see org.kuali.kfs.module.purap.document.AccountsPayableDocumentBase#isAttachmentRequired()
1098 */
1099 @Override
1100 protected boolean isAttachmentRequired() {
1101 if (getPaymentRequestElectronicInvoiceIndicator())
1102 return false;
1103 return StringUtils.equalsIgnoreCase("Y", SpringContext.getBean(ParameterService.class).getParameterValue(PaymentRequestDocument.class, PurapParameterConstants.PURAP_PREQ_REQUIRE_ATTACHMENT));
1104 }
1105
1106 /**
1107 * @see org.kuali.kfs.module.purap.document.AccountsPayableDocument#getDocumentSpecificService()
1108 */
1109 @Override
1110 public AccountsPayableDocumentSpecificService getDocumentSpecificService() {
1111 return (AccountsPayableDocumentSpecificService) SpringContext.getBean(PaymentRequestService.class);
1112 }
1113
1114 /**
1115 * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocumentBase#getItem(int)
1116 */
1117 @Override
1118 public PurApItem getItem(int pos) {
1119 PaymentRequestItem item = (PaymentRequestItem) super.getItem(pos);
1120 if (item.getPaymentRequest() == null) {
1121 item.setPaymentRequest(this);
1122 }
1123 return item;
1124 }
1125
1126 public String getPrimaryVendorName() {
1127
1128 if (primaryVendorName == null) {
1129 VendorDetail vd = SpringContext.getBean(VendorService.class).getVendorDetail(this.getOriginalVendorHeaderGeneratedIdentifier(), this.getOriginalVendorDetailAssignedIdentifier());
1130
1131 if (vd != null) {
1132 primaryVendorName = vd.getVendorName();
1133 }
1134 }
1135
1136 return primaryVendorName;
1137 }
1138
1139 /**
1140 * @deprecated
1141 */
1142 public void setPrimaryVendorName(String primaryVendorName) {
1143 }
1144
1145 /**
1146 * Forces general ledger entries to be approved, does not wait for payment request document final approval.
1147 *
1148 * @see org.kuali.module.purap.rules.PurapAccountingDocumentRuleBase#customizeExplicitGeneralLedgerPendingEntry(org.kuali.kfs.sys.document.AccountingDocument,
1149 * org.kuali.kfs.sys.businessobject.AccountingLine, org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntry)
1150 */
1151 @Override
1152 public void customizeExplicitGeneralLedgerPendingEntry(GeneralLedgerPendingEntrySourceDetail postable, GeneralLedgerPendingEntry explicitEntry) {
1153 super.customizeExplicitGeneralLedgerPendingEntry(postable, explicitEntry);
1154
1155 SpringContext.getBean(PurapGeneralLedgerService.class).customizeGeneralLedgerPendingEntry(this, (AccountingLine) postable, explicitEntry, getPurchaseOrderIdentifier(), getDebitCreditCodeForGLEntries(), PurapDocTypeCodes.PAYMENT_REQUEST_DOCUMENT, isGenerateEncumbranceEntries());
1156
1157 // PREQs do not wait for document final approval to post GL entries; here we are forcing them to be APPROVED
1158 explicitEntry.setFinancialDocumentApprovedCode(KFSConstants.PENDING_ENTRY_APPROVED_STATUS_CODE.APPROVED);
1159 }
1160
1161 /**
1162 * Provides answers to the following splits: PurchaseWasReceived VendorIsEmployeeOrNonResidentAlien
1163 *
1164 * @see org.kuali.kfs.sys.document.FinancialSystemTransactionalDocumentBase#answerSplitNodeQuestion(java.lang.String)
1165 */
1166 @Override
1167 public boolean answerSplitNodeQuestion(String nodeName) throws UnsupportedOperationException {
1168 if (nodeName.equals(PurapWorkflowConstants.REQUIRES_IMAGE_ATTACHMENT))
1169 return requiresAccountsPayableReviewRouting();
1170 if (nodeName.equals(PurapWorkflowConstants.PURCHASE_WAS_RECEIVED))
1171 return shouldWaitForReceiving();
1172 if (nodeName.equals(PurapWorkflowConstants.VENDOR_IS_EMPLOYEE_OR_NON_RESIDENT_ALIEN))
1173 return isVendorEmployeeOrNonResidentAlien();
1174 throw new UnsupportedOperationException("Cannot answer split question for this node you call \"" + nodeName + "\"");
1175 }
1176
1177 protected boolean isVendorEmployeeOrNonResidentAlien() {
1178 String vendorHeaderGeneratedId = this.getVendorHeaderGeneratedIdentifier().toString();
1179 if (StringUtils.isBlank(vendorHeaderGeneratedId)) {
1180 // no vendor header id so can't check for proper tax routing
1181 return false;
1182 }
1183 VendorService vendorService = SpringContext.getBean(VendorService.class);
1184 boolean routeDocumentAsEmployeeVendor = vendorService.isVendorInstitutionEmployee(Integer.valueOf(vendorHeaderGeneratedId));
1185 boolean routeDocumentAsForeignVendor = vendorService.isVendorForeign(Integer.valueOf(vendorHeaderGeneratedId));
1186 if ((!routeDocumentAsEmployeeVendor) && (!routeDocumentAsForeignVendor)) {
1187 // no need to route
1188 return false;
1189 }
1190
1191 return true;
1192 }
1193
1194 /**
1195 * Payment Request needs to wait for receiving if the receiving requirements have NOT been met.
1196 *
1197 * @return
1198 */
1199 protected boolean shouldWaitForReceiving() {
1200 // only require if PO was marked to require receiving
1201 if (isReceivingDocumentRequiredIndicator()) {
1202 return !isReceivingRequirementMet();
1203 }
1204
1205 //receiving is not required or has already been fulfilled, no need to stop for routing
1206 return false;
1207 }
1208
1209 /**
1210 * Determine if the receiving requirement has been met for all items on the payment request. If any item does not have receiving
1211 * requirements met, return false. Receiving requirement has NOT been met if the quantity invoiced on the Payment Request is
1212 * greater than the quantity of "unpaid and received" items determined by (poQtyReceived - (poQtyInvoiced - preqQtyInvoiced)).
1213 * We have to subtract preqQtyInvoiced from the poQtyInvoiced because this payment request has already updated the totals on the
1214 * po.
1215 *
1216 * @return boolean return true if the receiving requirement has been met for all items on the payment request; false if
1217 * requirement has not been met
1218 */
1219 public boolean isReceivingRequirementMet() {
1220
1221 for (Iterator iter = getItems().iterator(); iter.hasNext();) {
1222 PaymentRequestItem preqItem = (PaymentRequestItem) iter.next();
1223
1224 if (preqItem.getItemType().isQuantityBasedGeneralLedgerIndicator()) {
1225 PurchaseOrderItem poItem = preqItem.getPurchaseOrderItem();
1226 KualiDecimal preqQuantityInvoiced = preqItem.getItemQuantity() == null ? KualiDecimal.ZERO : preqItem.getItemQuantity();
1227 KualiDecimal poQuantityReceived = poItem.getItemReceivedTotalQuantity() == null ? KualiDecimal.ZERO : poItem.getItemReceivedTotalQuantity();
1228 KualiDecimal poQuantityInvoiced = poItem.getItemInvoicedTotalQuantity() == null ? KualiDecimal.ZERO : poItem.getItemInvoicedTotalQuantity();
1229
1230 // receiving has NOT been met if preqQtyInvoiced is greater than (poQtyReceived & (poQtyInvoiced & preqQtyInvoiced))
1231 if (preqQuantityInvoiced.compareTo(poQuantityReceived.subtract(poQuantityInvoiced.subtract(preqQuantityInvoiced))) > 0) {
1232 return false;
1233 }
1234 }
1235 }
1236
1237 return true;
1238 }
1239
1240 public Date getTransactionTaxDate() {
1241 return getInvoiceDate();
1242 }
1243
1244 public String getTaxClassificationCode() {
1245 return taxClassificationCode;
1246 }
1247
1248 public void setTaxClassificationCode(String taxClassificationCode) {
1249 this.taxClassificationCode = taxClassificationCode;
1250 }
1251
1252 public KualiDecimal getTaxFederalPercentShort() {
1253 return new KualiDecimal(taxFederalPercent);
1254 }
1255
1256 public BigDecimal getTaxFederalPercent() {
1257 return taxFederalPercent;
1258 }
1259
1260 public void setTaxFederalPercent(BigDecimal taxFederalPercent) {
1261 this.taxFederalPercent = taxFederalPercent;
1262 }
1263
1264 public KualiDecimal getTaxStatePercentShort() {
1265 return new KualiDecimal(taxStatePercent);
1266 }
1267
1268 public BigDecimal getTaxStatePercent() {
1269 return taxStatePercent;
1270 }
1271
1272 public void setTaxStatePercent(BigDecimal taxStatePercent) {
1273 this.taxStatePercent = taxStatePercent;
1274 }
1275
1276 public String getTaxCountryCode() {
1277 return taxCountryCode;
1278 }
1279
1280 public void setTaxCountryCode(String taxCountryCode) {
1281 this.taxCountryCode = taxCountryCode;
1282 }
1283
1284 public Boolean getTaxGrossUpIndicator() {
1285 return taxGrossUpIndicator;
1286 }
1287
1288 public void setTaxGrossUpIndicator(Boolean taxGrossUpIndicator) {
1289 this.taxGrossUpIndicator = taxGrossUpIndicator;
1290 }
1291
1292 public Boolean getTaxExemptTreatyIndicator() {
1293 return taxExemptTreatyIndicator;
1294 }
1295
1296 public void setTaxExemptTreatyIndicator(Boolean taxExemptTreatyIndicator) {
1297 this.taxExemptTreatyIndicator = taxExemptTreatyIndicator;
1298 }
1299
1300 public Boolean getTaxForeignSourceIndicator() {
1301 return taxForeignSourceIndicator;
1302 }
1303
1304 public void setTaxForeignSourceIndicator(Boolean taxForeignSourceIndicator) {
1305 this.taxForeignSourceIndicator = taxForeignSourceIndicator;
1306 }
1307
1308 public KualiDecimal getTaxSpecialW4Amount() {
1309 return taxSpecialW4Amount;
1310 }
1311
1312 public void setTaxSpecialW4Amount(KualiDecimal taxSpecialW4Amount) {
1313 this.taxSpecialW4Amount = taxSpecialW4Amount;
1314 }
1315
1316 public Boolean getTaxUSAIDPerDiemIndicator() {
1317 return taxUSAIDPerDiemIndicator;
1318 }
1319
1320 public void setTaxUSAIDPerDiemIndicator(Boolean taxUSAIDPerDiemIndicator) {
1321 this.taxUSAIDPerDiemIndicator = taxUSAIDPerDiemIndicator;
1322 }
1323
1324 public Boolean getTaxOtherExemptIndicator() {
1325 return taxOtherExemptIndicator;
1326 }
1327
1328 public void setTaxOtherExemptIndicator(Boolean taxOtherExemptIndicator) {
1329 this.taxOtherExemptIndicator = taxOtherExemptIndicator;
1330 }
1331
1332 public String getTaxNQIId() {
1333 return taxNQIId;
1334 }
1335
1336 public void setTaxNQIId(String taxNQIId) {
1337 this.taxNQIId = taxNQIId;
1338 }
1339
1340 public boolean isPaymentRequestedCancelIndicatorForSearching() {
1341 return paymentRequestedCancelIndicator;
1342 }
1343
1344 /**
1345 * @return the payment request positive approval indicator
1346 */
1347 public boolean getPaymentRequestPositiveApprovalIndicatorForSearching() {
1348 return paymentRequestPositiveApprovalIndicator;
1349 }
1350
1351 /**
1352 * @return the receiving document required indicator
1353 */
1354 public boolean getReceivingDocumentRequiredIndicatorForSearching() {
1355 return receivingDocumentRequiredIndicator;
1356 }
1357
1358
1359 public String getRequestCancelIndicatorForResult() {
1360 return isPaymentRequestedCancelIndicator() ? "Yes" : "No";
1361 }
1362
1363 public String getPaidIndicatorForResult() {
1364 return getPaymentPaidTimestamp() != null ? "Yes" : "No";
1365 }
1366
1367 public Date getAccountsPayableApprovalDateForSearching() {
1368 if (this.getAccountsPayableApprovalTimestamp() == null)
1369 return null;
1370 try {
1371 Date date = SpringContext.getBean(DateTimeService.class).convertToSqlDate(this.getAccountsPayableApprovalTimestamp());
1372 LOG.debug("getAccountsPayableApprovalDateForSearching() returns " + date);
1373 return date;
1374 }
1375 catch (Exception e) {
1376 return new Date(this.getAccountsPayableApprovalTimestamp().getTime());
1377 }
1378 }
1379
1380 /**
1381 * Checks all documents notes for attachments.
1382 *
1383 * @return - true if document does not have an image attached, false otherwise
1384 */
1385 public boolean documentHasNoImagesAttached() {
1386 List boNotes = this.getDocumentBusinessObject().getBoNotes();
1387 if (ObjectUtils.isNotNull(boNotes)) {
1388 for (Object obj : boNotes) {
1389 Note note = (Note) obj;
1390
1391 note.refreshReferenceObject("attachment");
1392 if (ObjectUtils.isNotNull(note.getAttachment()) && PurapConstants.AttachmentTypeCodes.ATTACHMENT_TYPE_INVOICE_IMAGE.equals(note.getAttachment().getAttachmentTypeCode())) {
1393 return false;
1394 }
1395 }
1396 }
1397 return true;
1398 }
1399 }