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 }