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.util.ArrayList; 020 import java.util.Calendar; 021 import java.util.Date; 022 import java.util.Iterator; 023 import java.util.List; 024 import java.util.Map; 025 import java.util.Set; 026 027 import org.apache.commons.lang.StringUtils; 028 import org.kuali.kfs.module.purap.PurapConstants; 029 import org.kuali.kfs.module.purap.PurapKeyConstants; 030 import org.kuali.kfs.module.purap.PurapParameterConstants; 031 import org.kuali.kfs.module.purap.PurapWorkflowConstants; 032 import org.kuali.kfs.module.purap.PurapConstants.RequisitionStatuses; 033 import org.kuali.kfs.module.purap.PurapWorkflowConstants.NodeDetails; 034 import org.kuali.kfs.module.purap.PurapWorkflowConstants.RequisitionDocument.NodeDetailEnum; 035 import org.kuali.kfs.module.purap.businessobject.BillingAddress; 036 import org.kuali.kfs.module.purap.businessobject.DefaultPrincipalAddress; 037 import org.kuali.kfs.module.purap.businessobject.PurApAccountingLine; 038 import org.kuali.kfs.module.purap.businessobject.PurchaseRequisitionItemUseTax; 039 import org.kuali.kfs.module.purap.businessobject.RequisitionAccount; 040 import org.kuali.kfs.module.purap.businessobject.RequisitionCapitalAssetItem; 041 import org.kuali.kfs.module.purap.businessobject.RequisitionCapitalAssetSystem; 042 import org.kuali.kfs.module.purap.businessobject.RequisitionItem; 043 import org.kuali.kfs.module.purap.document.service.PurapService; 044 import org.kuali.kfs.module.purap.document.service.PurchaseOrderService; 045 import org.kuali.kfs.module.purap.document.service.PurchasingDocumentSpecificService; 046 import org.kuali.kfs.module.purap.document.service.PurchasingService; 047 import org.kuali.kfs.module.purap.document.service.RequisitionService; 048 import org.kuali.kfs.sys.KFSConstants; 049 import org.kuali.kfs.sys.businessobject.Building; 050 import org.kuali.kfs.sys.businessobject.ChartOrgHolder; 051 import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper; 052 import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail; 053 import org.kuali.kfs.sys.context.SpringContext; 054 import org.kuali.kfs.sys.service.FinancialSystemUserService; 055 import org.kuali.kfs.sys.service.UniversityDateService; 056 import org.kuali.kfs.vnd.businessobject.VendorContract; 057 import org.kuali.kfs.vnd.businessobject.VendorDetail; 058 import org.kuali.kfs.vnd.document.service.VendorService; 059 import org.kuali.kfs.vnd.service.PhoneNumberService; 060 import org.kuali.rice.kew.dto.DocumentRouteLevelChangeDTO; 061 import org.kuali.rice.kew.dto.DocumentRouteStatusChangeDTO; 062 import org.kuali.rice.kew.dto.ReportCriteriaDTO; 063 import org.kuali.rice.kew.exception.WorkflowException; 064 import org.kuali.rice.kew.util.KEWConstants; 065 import org.kuali.rice.kim.bo.Person; 066 import org.kuali.rice.kim.service.KIMServiceLocator; 067 import org.kuali.rice.kns.document.Copyable; 068 import org.kuali.rice.kns.exception.ValidationException; 069 import org.kuali.rice.kns.service.BusinessObjectService; 070 import org.kuali.rice.kns.service.DateTimeService; 071 import org.kuali.rice.kns.service.KualiConfigurationService; 072 import org.kuali.rice.kns.service.ParameterService; 073 import org.kuali.rice.kns.service.PersistenceService; 074 import org.kuali.rice.kns.util.GlobalVariables; 075 import org.kuali.rice.kns.util.KualiDecimal; 076 import org.kuali.rice.kns.util.ObjectUtils; 077 import org.kuali.rice.kns.workflow.service.KualiWorkflowInfo; 078 import org.kuali.rice.kns.workflow.service.WorkflowDocumentService; 079 080 /** 081 * Document class for the Requisition. 082 */ 083 public class RequisitionDocument extends PurchasingDocumentBase implements Copyable { 084 protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(RequisitionDocument.class); 085 086 protected String requisitionOrganizationReference1Text; 087 protected String requisitionOrganizationReference2Text; 088 protected String requisitionOrganizationReference3Text; 089 protected String alternate1VendorName; 090 protected String alternate2VendorName; 091 protected String alternate3VendorName; 092 protected String alternate4VendorName; 093 protected String alternate5VendorName; 094 protected KualiDecimal organizationAutomaticPurchaseOrderLimit; 095 096 // non-persistent property used for controlling validation for accounting lines when doc is request for blanket approve. 097 protected boolean isBlanketApproveRequest = false; 098 099 /** 100 * Default constructor. 101 */ 102 public RequisitionDocument() { 103 super(); 104 } 105 106 @Override 107 public PurchasingDocumentSpecificService getDocumentSpecificService() { 108 return SpringContext.getBean(RequisitionService.class); 109 } 110 /** 111 * @see org.kuali.rice.kns.bo.PersistableBusinessObjectBase#isBoNotesSupport() 112 */ 113 @Override 114 public boolean isBoNotesSupport() { 115 return true; 116 } 117 118 /** 119 * Provides answers to the following splits: 120 * AmountRequiresSeparationOfDutiesReview 121 * 122 * @see org.kuali.kfs.sys.document.FinancialSystemTransactionalDocumentBase#answerSplitNodeQuestion(java.lang.String) 123 */ 124 @Override 125 public boolean answerSplitNodeQuestion(String nodeName) throws UnsupportedOperationException { 126 if (nodeName.equals(PurapWorkflowConstants.HAS_ACCOUNTING_LINES)) return !isMissingAccountingLines(); 127 if (nodeName.equals(PurapWorkflowConstants.AMOUNT_REQUIRES_SEPARATION_OF_DUTIES_REVIEW_SPLIT)) return isSeparationOfDutiesReviewRequired(); 128 throw new UnsupportedOperationException("Cannot answer split question for this node you call \""+nodeName+"\""); 129 } 130 131 protected boolean isMissingAccountingLines() { 132 for (Iterator iterator = getItems().iterator(); iterator.hasNext();) { 133 RequisitionItem item = (RequisitionItem) iterator.next(); 134 if (item.isConsideredEntered() && item.isAccountListEmpty()) { 135 return true; 136 } 137 } 138 139 return false; 140 } 141 142 protected boolean isSeparationOfDutiesReviewRequired() { 143 try { 144 Set<Person> priorApprovers = getDocumentHeader().getWorkflowDocument().getAllPriorApprovers(); 145 146 // The initiator cannot be the approver 147 String initiatorPrincipalId = getDocumentHeader().getWorkflowDocument().getInitiatorPrincipalId(); 148 Person initiator = KIMServiceLocator.getPersonService().getPerson(initiatorPrincipalId); 149 // If there is only one approver, and that approver is also the initiator, then Separation of Duties is required. 150 boolean priorApproverIsInitiator = priorApprovers.contains(initiator); 151 boolean onlyOneApprover = (priorApprovers.size() == 1); 152 if ( priorApproverIsInitiator && onlyOneApprover) { 153 return true; 154 } 155 156 // if there are more than 0 prior approvers which means there had been at least another approver than the current approver 157 // then no need for separation of duties 158 if (priorApprovers.size() > 0) { 159 return false; 160 } 161 }catch (WorkflowException we) { 162 LOG.error("Exception while attempting to retrieve all prior approvers from workflow: " + we); 163 } 164 ParameterService parameterService = SpringContext.getBean(ParameterService.class); 165 KualiDecimal maxAllowedAmount = new KualiDecimal(parameterService.getParameterValue(RequisitionDocument.class, PurapParameterConstants.SEPARATION_OF_DUTIES_DOLLAR_AMOUNT)); 166 // if app param amount is greater than or equal to documentTotalAmount... no need for separation of duties 167 KualiDecimal totalAmount = documentHeader.getFinancialDocumentTotalAmount(); 168 if (ObjectUtils.isNotNull(maxAllowedAmount) && ObjectUtils.isNotNull(totalAmount) && (maxAllowedAmount.compareTo(totalAmount) >= 0)) { 169 return false; 170 } 171 else { 172 return true; 173 } 174 } 175 176 177 /** 178 * Overrides the method in PurchasingAccountsPayableDocumentBase to add the criteria 179 * specific to Requisition Document. 180 * 181 * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocumentBase#isInquiryRendered() 182 */ 183 @Override 184 public boolean isInquiryRendered() { 185 if ( isPostingYearPrior() && 186 ( getStatusCode().equals(PurapConstants.RequisitionStatuses.CLOSED) || 187 getStatusCode().equals(PurapConstants.RequisitionStatuses.CANCELLED) ) ) { 188 return false; 189 } 190 else { 191 return true; 192 } 193 } 194 195 /** 196 * Performs logic needed to initiate Requisition Document. 197 */ 198 public void initiateDocument() { 199 this.setRequisitionSourceCode(PurapConstants.RequisitionSources.STANDARD_ORDER); 200 this.setStatusCode(PurapConstants.RequisitionStatuses.IN_PROCESS); 201 this.setPurchaseOrderCostSourceCode(PurapConstants.POCostSources.ESTIMATE); 202 this.setPurchaseOrderTransmissionMethodCode(determinePurchaseOrderTransmissionMethod()); 203 this.setDocumentFundingSourceCode(SpringContext.getBean(ParameterService.class).getParameterValue(RequisitionDocument.class, PurapParameterConstants.DEFAULT_FUNDING_SOURCE)); 204 this.setUseTaxIndicator(SpringContext.getBean(PurchasingService.class).getDefaultUseTaxIndicatorValue(this)); 205 206 Person currentUser = GlobalVariables.getUserSession().getPerson(); 207 ChartOrgHolder purapChartOrg = SpringContext.getBean(FinancialSystemUserService.class).getPrimaryOrganization(currentUser, PurapConstants.PURAP_NAMESPACE); 208 if (ObjectUtils.isNotNull(purapChartOrg)) { 209 this.setChartOfAccountsCode(purapChartOrg.getChartOfAccountsCode()); 210 this.setOrganizationCode(purapChartOrg.getOrganizationCode()); 211 } 212 this.setDeliveryCampusCode(currentUser.getCampusCode()); 213 this.setDeliveryToName(currentUser.getName()); 214 this.setDeliveryToEmailAddress(currentUser.getEmailAddressUnmasked()); 215 this.setDeliveryToPhoneNumber(SpringContext.getBean(PhoneNumberService.class).formatNumberIfPossible(currentUser.getPhoneNumber())); 216 this.setRequestorPersonName(currentUser.getName()); 217 this.setRequestorPersonEmailAddress(currentUser.getEmailAddressUnmasked()); 218 this.setRequestorPersonPhoneNumber(SpringContext.getBean(PhoneNumberService.class).formatNumberIfPossible(currentUser.getPhoneNumber())); 219 220 DefaultPrincipalAddress defaultPrincipalAddress = new DefaultPrincipalAddress(currentUser.getPrincipalId()); 221 Map addressKeys = SpringContext.getBean(PersistenceService.class).getPrimaryKeyFieldValues(defaultPrincipalAddress); 222 defaultPrincipalAddress = (DefaultPrincipalAddress) SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(DefaultPrincipalAddress.class, addressKeys); 223 if (ObjectUtils.isNotNull(defaultPrincipalAddress) && ObjectUtils.isNotNull(defaultPrincipalAddress.getBuilding())) { 224 if (defaultPrincipalAddress.getBuilding().isActive()) { 225 this.setDeliveryCampusCode(defaultPrincipalAddress.getCampusCode()); 226 this.templateBuildingToDeliveryAddress(defaultPrincipalAddress.getBuilding()); 227 this.setDeliveryBuildingRoomNumber(defaultPrincipalAddress.getBuildingRoomNumber()); 228 } 229 else { 230 //since building is now inactive, delete default building record 231 SpringContext.getBean(BusinessObjectService.class).delete(defaultPrincipalAddress); 232 } 233 } 234 235 // set the APO limit 236 this.setOrganizationAutomaticPurchaseOrderLimit(SpringContext.getBean(PurapService.class).getApoLimit(this.getVendorContractGeneratedIdentifier(), this.getChartOfAccountsCode(), this.getOrganizationCode())); 237 238 // populate billing address 239 BillingAddress billingAddress = new BillingAddress(); 240 billingAddress.setBillingCampusCode(this.getDeliveryCampusCode()); 241 Map keys = SpringContext.getBean(PersistenceService.class).getPrimaryKeyFieldValues(billingAddress); 242 billingAddress = (BillingAddress) SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(BillingAddress.class, keys); 243 this.templateBillingAddress(billingAddress); 244 245 // populate receiving address with the default one for the chart/org 246 loadReceivingAddress(); 247 248 SpringContext.getBean(PurapService.class).addBelowLineItems(this); 249 this.refreshNonUpdateableReferences(); 250 } 251 252 public void templateBuildingToDeliveryAddress(Building building) { 253 if (ObjectUtils.isNotNull(building)) { 254 setDeliveryBuildingCode(building.getBuildingCode()); 255 setDeliveryBuildingName(building.getBuildingName()); 256 setDeliveryBuildingLine1Address(building.getBuildingStreetAddress()); 257 setDeliveryCityName(building.getBuildingAddressCityName()); 258 setDeliveryStateCode(building.getBuildingAddressStateCode()); 259 setDeliveryPostalCode(building.getBuildingAddressZipCode()); 260 setDeliveryCountryCode(building.getBuildingAddressCountryCode()); 261 } 262 } 263 264 /** 265 * Determines what PO transmission method to use. 266 * 267 * @return the PO PO transmission method to use. 268 */ 269 protected String determinePurchaseOrderTransmissionMethod() { 270 271 return SpringContext.getBean(ParameterService.class).getParameterValue(RequisitionDocument.class, PurapParameterConstants.PURAP_DEFAULT_PO_TRANSMISSION_CODE); 272 } 273 274 /** 275 * Checks whether copying of this document should be allowed. Copying is not allowed if this is a B2B requistion, and more than 276 * a set number of days have passed since the document's creation. 277 * 278 * @return True if copying of this requisition is allowed. 279 * @see org.kuali.rice.kns.document.Document#getAllowsCopy() 280 */ 281 @Override 282 public boolean getAllowsCopy() { 283 boolean allowsCopy = super.getAllowsCopy(); 284 if (PurapConstants.RequisitionSources.B2B.equals(getRequisitionSourceCode())) { 285 DateTimeService dateTimeService = SpringContext.getBean(DateTimeService.class); 286 Calendar c = Calendar.getInstance(); 287 288 // The allowed copy date is the document creation date plus a set number of days. 289 Date createDate = getDocumentHeader().getWorkflowDocument().getCreateDate(); 290 c.setTime(createDate); 291 String allowedCopyDays = SpringContext.getBean(ParameterService.class).getParameterValue(RequisitionDocument.class, PurapParameterConstants.B2B_ALLOW_COPY_DAYS); 292 c.add(Calendar.DATE, Integer.parseInt(allowedCopyDays)); 293 Date allowedCopyDate = c.getTime(); 294 Date currentDate = dateTimeService.getCurrentDate(); 295 296 // Return true if the current time is before the allowed copy date. 297 allowsCopy = (dateTimeService.dateDiff(currentDate, allowedCopyDate, false) > 0); 298 } 299 return allowsCopy; 300 } 301 302 /** 303 * Performs logic needed to copy Requisition Document. 304 * 305 * @see org.kuali.rice.kns.document.Document#toCopy() 306 */ 307 @Override 308 public void toCopy() throws WorkflowException, ValidationException { 309 super.toCopy(); 310 311 // Clear related views 312 this.setAccountsPayablePurchasingDocumentLinkIdentifier(null); 313 this.setRelatedViews(null); 314 315 Person currentUser = GlobalVariables.getUserSession().getPerson(); 316 ChartOrgHolder purapChartOrg = SpringContext.getBean(FinancialSystemUserService.class).getPrimaryOrganization(currentUser, PurapConstants.PURAP_NAMESPACE); 317 this.setPurapDocumentIdentifier(null); 318 319 // Set req status to INPR. 320 this.setStatusCode(PurapConstants.RequisitionStatuses.IN_PROCESS); 321 322 // Set fields from the user. 323 if (ObjectUtils.isNotNull(purapChartOrg)) { 324 this.setChartOfAccountsCode(purapChartOrg.getChartOfAccountsCode()); 325 this.setOrganizationCode(purapChartOrg.getOrganizationCode()); 326 } 327 this.setPostingYear(SpringContext.getBean(UniversityDateService.class).getCurrentFiscalYear()); 328 329 boolean activeVendor = true; 330 boolean activeContract = true; 331 Date today = SpringContext.getBean(DateTimeService.class).getCurrentDate(); 332 VendorContract vendorContract = new VendorContract(); 333 vendorContract.setVendorContractGeneratedIdentifier(this.getVendorContractGeneratedIdentifier()); 334 Map keys = SpringContext.getBean(PersistenceService.class).getPrimaryKeyFieldValues(vendorContract); 335 vendorContract = (VendorContract) SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(VendorContract.class, keys); 336 if (!(vendorContract != null && today.after(vendorContract.getVendorContractBeginningDate()) && today.before(vendorContract.getVendorContractEndDate()))) { 337 activeContract = false; 338 } 339 340 VendorDetail vendorDetail = SpringContext.getBean(VendorService.class).getVendorDetail(this.getVendorHeaderGeneratedIdentifier(), this.getVendorDetailAssignedIdentifier()); 341 if (!(vendorDetail != null && vendorDetail.isActiveIndicator())) { 342 activeVendor = false; 343 } 344 345 // B2B - only copy if contract and vendor are both active (throw separate errors to print to screen) 346 if (this.getRequisitionSourceCode().equals(PurapConstants.RequisitionSources.B2B)) { 347 if (!activeContract) { 348 throw new ValidationException(PurapKeyConstants.ERROR_REQ_COPY_EXPIRED_CONTRACT); 349 } 350 if (!activeVendor) { 351 throw new ValidationException(PurapKeyConstants.ERROR_REQ_COPY_INACTIVE_VENDOR); 352 } 353 } 354 355 if (!activeVendor) { 356 this.setVendorContractGeneratedIdentifier(null); 357 } 358 if (!activeContract) { 359 this.setVendorContractGeneratedIdentifier(null); 360 } 361 362 // These fields should not be set in this method; force to be null 363 this.setOrganizationAutomaticPurchaseOrderLimit(null); 364 this.setPurchaseOrderAutomaticIndicator(false); 365 366 // Fill the BO Notes with an empty List. 367 this.setBoNotes(new ArrayList()); 368 369 for (Iterator iter = this.getItems().iterator(); iter.hasNext();) { 370 RequisitionItem item = (RequisitionItem) iter.next(); 371 item.setPurapDocumentIdentifier(null); 372 item.setItemIdentifier(null); 373 for (Iterator acctIter = item.getSourceAccountingLines().iterator(); acctIter.hasNext();) { 374 RequisitionAccount account = (RequisitionAccount) acctIter.next(); 375 account.setAccountIdentifier(null); 376 account.setItemIdentifier(null); 377 } 378 } 379 380 if (!PurapConstants.RequisitionSources.B2B.equals(this.getRequisitionSourceCode())) { 381 SpringContext.getBean(PurapService.class).addBelowLineItems(this); 382 } 383 this.setOrganizationAutomaticPurchaseOrderLimit(SpringContext.getBean(PurapService.class).getApoLimit(this.getVendorContractGeneratedIdentifier(), this.getChartOfAccountsCode(), this.getOrganizationCode())); 384 clearCapitalAssetFields(); 385 SpringContext.getBean(PurapService.class).clearTax(this, this.isUseTaxIndicator()); 386 387 this.refreshNonUpdateableReferences(); 388 } 389 390 /** 391 * Updates status of this document and saves it. 392 * 393 * @param statusCode the status code of the current status. 394 */ 395 protected void updateStatusAndSave(String statusCode) { 396 SpringContext.getBean(PurapService.class).updateStatus(this, statusCode); 397 SpringContext.getBean(PurapService.class).saveDocumentNoValidation(this); 398 } 399 400 @Override 401 public List<Long> getWorkflowEngineDocumentIdsToLock() { 402 List<String> docIdStrings = new ArrayList<String>(); 403 docIdStrings.add(getDocumentNumber()); 404 405 // PROCESSED 406 if (getDocumentHeader().getWorkflowDocument().stateIsProcessed()) { 407 // creates a new PO but no way to know what the docID will be ahead of time 408 } 409 410 // convert our easy to use List<String> to a Long[] 411 List<Long> docIds = new ArrayList<Long>(); 412 for (int i = 0; i < docIdStrings.size(); i++) { 413 docIds.add(new Long(docIdStrings.get(i))); 414 } 415 return docIds; 416 } 417 418 /** 419 * @see org.kuali.rice.kns.document.DocumentBase#doRouteStatusChange() 420 */ 421 @Override 422 public void doRouteStatusChange(DocumentRouteStatusChangeDTO statusChangeEvent) { 423 LOG.debug("doRouteStatusChange() started"); 424 super.doRouteStatusChange(statusChangeEvent); 425 try { 426 // DOCUMENT PROCESSED 427 if (this.getDocumentHeader().getWorkflowDocument().stateIsProcessed()) { 428 String newRequisitionStatus = PurapConstants.RequisitionStatuses.AWAIT_CONTRACT_MANAGER_ASSGN; 429 if (SpringContext.getBean(RequisitionService.class).isAutomaticPurchaseOrderAllowed(this)) { 430 newRequisitionStatus = PurapConstants.RequisitionStatuses.CLOSED; 431 SpringContext.getBean(PurchaseOrderService.class).createAutomaticPurchaseOrderDocument(this); 432 } 433 updateStatusAndSave(newRequisitionStatus); 434 } 435 // DOCUMENT DISAPPROVED 436 else if (this.getDocumentHeader().getWorkflowDocument().stateIsDisapproved()) { 437 String nodeName = SpringContext.getBean(WorkflowDocumentService.class).getCurrentRouteLevelName(getDocumentHeader().getWorkflowDocument()); 438 NodeDetails currentNode = NodeDetailEnum.getNodeDetailEnumByName(nodeName); 439 if (ObjectUtils.isNotNull(currentNode)) { 440 if (StringUtils.isNotBlank(currentNode.getDisapprovedStatusCode())) { 441 updateStatusAndSave(currentNode.getDisapprovedStatusCode()); 442 return; 443 } 444 } 445 logAndThrowRuntimeException("No status found to set for document being disapproved in node '" + nodeName + "'"); 446 } 447 // DOCUMENT CANCELED 448 else if (this.getDocumentHeader().getWorkflowDocument().stateIsCanceled()) { 449 updateStatusAndSave(RequisitionStatuses.CANCELLED); 450 } 451 } 452 catch (WorkflowException e) { 453 logAndThrowRuntimeException("Error saving routing data while saving document with id " + getDocumentNumber(), e); 454 } 455 LOG.debug("doRouteStatusChange() ending"); 456 } 457 458 /** 459 * @see org.kuali.rice.kns.document.DocumentBase#handleRouteLevelChange(org.kuali.rice.kew.clientapp.vo.DocumentRouteLevelChangeDTO) 460 */ 461 @Override 462 public void doRouteLevelChange(DocumentRouteLevelChangeDTO change) { 463 LOG.debug("handleRouteLevelChange() started"); 464 super.doRouteLevelChange(change); 465 try { 466 String newNodeName = change.getNewNodeName(); 467 if (StringUtils.isNotBlank(newNodeName)) { 468 ReportCriteriaDTO reportCriteriaDTO = new ReportCriteriaDTO(Long.valueOf(getDocumentNumber())); 469 reportCriteriaDTO.setTargetNodeName(newNodeName); 470 if (SpringContext.getBean(KualiWorkflowInfo.class).documentWillHaveAtLeastOneActionRequest(reportCriteriaDTO, new String[] { KEWConstants.ACTION_REQUEST_APPROVE_REQ, KEWConstants.ACTION_REQUEST_COMPLETE_REQ }, false)) { 471 NodeDetails currentNode = NodeDetailEnum.getNodeDetailEnumByName(newNodeName); 472 if (ObjectUtils.isNotNull(currentNode)) { 473 if (StringUtils.isNotBlank(currentNode.getAwaitingStatusCode())) { 474 updateStatusAndSave(currentNode.getAwaitingStatusCode()); 475 } 476 } 477 } 478 else { 479 LOG.debug("Document with id " + getDocumentNumber() + " will not stop in route node '" + newNodeName + "'"); 480 } 481 } 482 } 483 catch (WorkflowException e) { 484 String errorMsg = "Workflow Error found checking actions requests on document with id " + getDocumentNumber() + ". *** WILL NOT UPDATE PURAP STATUS ***"; 485 LOG.warn(errorMsg, e); 486 } 487 } 488 489 /** 490 * @see org.kuali.kfs.sys.document.AccountingDocument#getSourceAccountingLineClass() 491 */ 492 @Override 493 public Class getSourceAccountingLineClass() { 494 //NOTE: do not do anything with this method as it is used by routing etc! 495 return super.getSourceAccountingLineClass(); 496 } 497 498 public String getRequisitionOrganizationReference1Text() { 499 return requisitionOrganizationReference1Text; 500 } 501 502 public void setRequisitionOrganizationReference1Text(String requisitionOrganizationReference1Text) { 503 this.requisitionOrganizationReference1Text = requisitionOrganizationReference1Text; 504 } 505 506 public String getRequisitionOrganizationReference2Text() { 507 return requisitionOrganizationReference2Text; 508 } 509 510 public void setRequisitionOrganizationReference2Text(String requisitionOrganizationReference2Text) { 511 this.requisitionOrganizationReference2Text = requisitionOrganizationReference2Text; 512 } 513 514 public String getRequisitionOrganizationReference3Text() { 515 return requisitionOrganizationReference3Text; 516 } 517 518 public void setRequisitionOrganizationReference3Text(String requisitionOrganizationReference3Text) { 519 this.requisitionOrganizationReference3Text = requisitionOrganizationReference3Text; 520 } 521 522 public String getAlternate1VendorName() { 523 return alternate1VendorName; 524 } 525 526 public void setAlternate1VendorName(String alternate1VendorName) { 527 this.alternate1VendorName = alternate1VendorName; 528 } 529 530 public String getAlternate2VendorName() { 531 return alternate2VendorName; 532 } 533 534 public void setAlternate2VendorName(String alternate2VendorName) { 535 this.alternate2VendorName = alternate2VendorName; 536 } 537 538 public String getAlternate3VendorName() { 539 return alternate3VendorName; 540 } 541 542 public void setAlternate3VendorName(String alternate3VendorName) { 543 this.alternate3VendorName = alternate3VendorName; 544 } 545 546 public String getAlternate4VendorName() { 547 return alternate4VendorName; 548 } 549 550 public void setAlternate4VendorName(String alternate4VendorName) { 551 this.alternate4VendorName = alternate4VendorName; 552 } 553 554 public String getAlternate5VendorName() { 555 return alternate5VendorName; 556 } 557 558 public void setAlternate5VendorName(String alternate5VendorName) { 559 this.alternate5VendorName = alternate5VendorName; 560 } 561 562 public KualiDecimal getOrganizationAutomaticPurchaseOrderLimit() { 563 return organizationAutomaticPurchaseOrderLimit; 564 } 565 566 public void setOrganizationAutomaticPurchaseOrderLimit(KualiDecimal organizationAutomaticPurchaseOrderLimit) { 567 this.organizationAutomaticPurchaseOrderLimit = organizationAutomaticPurchaseOrderLimit; 568 } 569 570 /** 571 * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocumentBase#getItemClass() 572 */ 573 @Override 574 public Class getItemClass() { 575 return RequisitionItem.class; 576 } 577 578 @Override 579 public Class getItemUseTaxClass() { 580 return PurchaseRequisitionItemUseTax.class; 581 } 582 583 /** 584 * Returns null as requistion has no source document. 585 * 586 * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocumentBase#getPurApSourceDocumentIfPossible() 587 */ 588 @Override 589 public PurchasingAccountsPayableDocument getPurApSourceDocumentIfPossible() { 590 return null; 591 } 592 593 /** 594 * Returns null as requistion has no source document. 595 * 596 * @see org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocumentBase#getPurApSourceDocumentLabelIfPossible() 597 */ 598 @Override 599 public String getPurApSourceDocumentLabelIfPossible() { 600 return null; 601 } 602 603 /** 604 * @see org.kuali.rice.kns.document.Document#getDocumentTitle() 605 */ 606 @Override 607 public String getDocumentTitle() { 608 String title = ""; 609 if (SpringContext.getBean(ParameterService.class).getIndicatorParameter(RequisitionDocument.class, PurapParameterConstants.PURAP_OVERRIDE_REQ_DOC_TITLE)) { 610 String docIdStr = ""; 611 if ((this.getPurapDocumentIdentifier() != null) && (StringUtils.isNotBlank(this.getPurapDocumentIdentifier().toString()))) { 612 docIdStr = "Requisition: " + this.getPurapDocumentIdentifier().toString(); 613 } 614 String chartAcct = this.getFirstChartAccount(); 615 String chartAcctStr = (chartAcct == null ? "" : " - Account Number: " + chartAcct); 616 title = docIdStr + chartAcctStr; 617 } 618 else { 619 title = super.getDocumentTitle(); 620 } 621 return title; 622 } 623 624 /** 625 * Gets this requisition's Chart/Account of the first accounting line from the first item. 626 * 627 * @return The first Chart and Account, or an empty string if there is none. 628 */ 629 protected String getFirstChartAccount() { 630 String chartAcct = null; 631 RequisitionItem item = (RequisitionItem) this.getItem(0); 632 if (ObjectUtils.isNotNull(item)) { 633 if (item.getSourceAccountingLines().size() > 0) { 634 PurApAccountingLine accountLine = item.getSourceAccountingLine(0); 635 if (ObjectUtils.isNotNull(accountLine) && ObjectUtils.isNotNull(accountLine.getChartOfAccountsCode()) && ObjectUtils.isNotNull(accountLine.getAccountNumber())) { 636 chartAcct = accountLine.getChartOfAccountsCode() + "-" + accountLine.getAccountNumber(); 637 } 638 } 639 } 640 return chartAcct; 641 } 642 643 public Date getCreateDate() { 644 return this.getDocumentHeader().getWorkflowDocument().getCreateDate(); 645 } 646 647 public String getUrl() { 648 return SpringContext.getBean(KualiConfigurationService.class).getPropertyString(KFSConstants.WORKFLOW_URL_KEY) + "/DocHandler.do?docId=" + getDocumentNumber() + "&command=displayDocSearchView"; 649 } 650 651 /** 652 * Used for routing only. 653 * 654 * @deprecated 655 */ 656 public String getStatusDescription() { 657 return ""; 658 } 659 660 /** 661 * Used for routing only. 662 * 663 * @deprecated 664 */ 665 public void setStatusDescription(String statusDescription) { 666 } 667 668 /** 669 * This is a "do nothing" version of the method - it just won't create GLPEs 670 * @see org.kuali.kfs.sys.document.AccountingDocumentBase#generateGeneralLedgerPendingEntries(org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail, org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper) 671 */ 672 @Override 673 public boolean generateGeneralLedgerPendingEntries(GeneralLedgerPendingEntrySourceDetail glpeSourceDetail, GeneralLedgerPendingEntrySequenceHelper sequenceHelper) { 674 return true; 675 } 676 677 @Override 678 public Class getPurchasingCapitalAssetItemClass() { 679 return RequisitionCapitalAssetItem.class; 680 } 681 682 @Override 683 public Class getPurchasingCapitalAssetSystemClass() { 684 return RequisitionCapitalAssetSystem.class; 685 } 686 687 @Override 688 public boolean shouldGiveErrorForEmptyAccountsProration() { 689 if (isDocumentStoppedInRouteNode(NodeDetailEnum.CONTENT_REVIEW) || 690 getStatusCode().equals(PurapConstants.RequisitionStatuses.IN_PROCESS)) { 691 return false; 692 } 693 return true; 694 } 695 696 public Date getCreateDateForResult() { 697 return this.getDocumentHeader().getWorkflowDocument().getCreateDate(); 698 } 699 700 /** 701 * Gets the isBlanketApproveRequest attribute. 702 * @return Returns the isBlanketApproveRequest. 703 */ 704 public boolean isBlanketApproveRequest() { 705 return isBlanketApproveRequest; 706 } 707 708 /** 709 * Sets the isBlanketApproveRequest attribute value. 710 * @param isBlanketApproveRequest The isBlanketApproveRequest to set. 711 */ 712 public void setBlanketApproveRequest(boolean isBlanketApproveRequest) { 713 this.isBlanketApproveRequest = isBlanketApproveRequest; 714 } 715 716 717 } 718