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 package org.kuali.kfs.module.ar.batch; 017 018 import java.math.BigDecimal; 019 import java.text.SimpleDateFormat; 020 import java.util.ArrayList; 021 import java.util.Arrays; 022 import java.util.Calendar; 023 import java.util.Collection; 024 import java.util.Date; 025 import java.util.HashMap; 026 import java.util.List; 027 import java.util.Map; 028 029 import org.apache.commons.lang.StringUtils; 030 import org.apache.commons.lang.time.DateUtils; 031 import org.kuali.kfs.module.ar.ArConstants; 032 import org.kuali.kfs.module.ar.batch.service.LockboxService; 033 import org.kuali.kfs.module.ar.businessobject.CustomerAddress; 034 import org.kuali.kfs.module.ar.businessobject.CustomerInvoiceDetail; 035 import org.kuali.kfs.module.ar.businessobject.Lockbox; 036 import org.kuali.kfs.module.ar.document.CustomerInvoiceDocument; 037 import org.kuali.kfs.module.ar.document.CustomerInvoiceWriteoffDocument; 038 import org.kuali.kfs.module.ar.document.service.CustomerAddressService; 039 import org.kuali.kfs.module.ar.document.service.CustomerInvoiceDocumentService; 040 import org.kuali.kfs.module.ar.document.service.CustomerInvoiceWriteoffDocumentService; 041 import org.kuali.kfs.sys.KFSConstants; 042 import org.kuali.kfs.sys.batch.AbstractStep; 043 import org.kuali.kfs.sys.batch.Job; 044 import org.kuali.kfs.sys.batch.TestingStep; 045 import org.kuali.kfs.sys.context.SpringContext; 046 import org.kuali.rice.kew.exception.WorkflowException; 047 import org.kuali.rice.kim.bo.Person; 048 import org.kuali.rice.kim.service.PersonService; 049 import org.kuali.rice.kns.UserSession; 050 import org.kuali.rice.kns.bo.Parameter; 051 import org.kuali.rice.kns.document.Document; 052 import org.kuali.rice.kns.service.BusinessObjectService; 053 import org.kuali.rice.kns.service.DateTimeService; 054 import org.kuali.rice.kns.service.DocumentService; 055 import org.kuali.rice.kns.service.PersistenceStructureService; 056 import org.kuali.rice.kns.util.GlobalVariables; 057 import org.kuali.rice.kns.util.KualiDecimal; 058 import org.kuali.rice.kns.util.ObjectUtils; 059 import org.kuali.rice.kns.workflow.service.KualiWorkflowDocument; 060 061 public class CustomerInvoiceDocumentBatchStep extends AbstractStep implements TestingStep { 062 063 private static final long MAX_SEQ_NBR_OFFSET = 1000; 064 065 CustomerInvoiceDocumentService customerInvoiceDocumentService; 066 BusinessObjectService businessObjectService; 067 DocumentService documentService; 068 DateTimeService dateTimeService; 069 Collection<String> createdInvoices = new ArrayList<String>(); 070 071 072 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(CustomerInvoiceDocumentBatchStep.class); 073 074 // parameter constants and logging 075 private static final int NUMBER_OF_INVOICES_TO_CREATE = 5; 076 private static final String RUN_INDICATOR_PARAMETER_NAMESPACE_CODE = ArConstants.AR_NAMESPACE_CODE; 077 private static final String RUN_INDICATOR_PARAMETER_APPLICATION_NAMESPACE_CODE = KFSConstants.APPLICATION_NAMESPACE_CODE; 078 private static final String RUN_INDICATOR_PARAMETER_NAMESPACE_STEP = "CustomerInvoiceDocumentBatchStep"; 079 private static final String RUN_INDICATOR_PARAMETER_VALUE = "N"; // Tells the job framework whether to run this job or not; set to NO because the CustomerInvoiceDocumentBatchStep needs to only be run once after database initialization. 080 private static final String RUN_INDICATOR_PARAMETER_ALLOWED = "A"; 081 private final String RUN_INDICATOR_PARAMETER_DESCRIPTION = "Tells the job framework whether to run this job or not; because the CustomerInvoiceDocumentBatchStep needs to only be run once after database initialization."; 082 private static final String RUN_INDICATOR_PARAMETER_TYPE = "CONFG"; 083 private static final String INITIATOR_PRINCIPAL_NAME = "khuntley"; 084 085 private final int currentYear = Calendar.getInstance().get(Calendar.YEAR); 086 087 public boolean execute(String jobName, Date jobRunDate) throws InterruptedException { 088 089 Parameter runIndicatorParameter = (Parameter) businessObjectService.findByPrimaryKey(Parameter.class, this.buildSearchKeyMap()); 090 if (ObjectUtils.isNull(runIndicatorParameter) || "Y".equals(runIndicatorParameter.getParameterValue())) { 091 092 GlobalVariables.clear(); 093 GlobalVariables.setUserSession(new UserSession(INITIATOR_PRINCIPAL_NAME)); 094 setDateTimeService(SpringContext.getBean(DateTimeService.class)); 095 096 Date billingDate = getDateTimeService().getCurrentDate(); 097 List<String> customernames; 098 099 if ((jobName.length() <=8 ) && (jobName.length() >= 4)) { 100 setCustomerInvoiceDocumentService(SpringContext.getBean(CustomerInvoiceDocumentService.class)); 101 setBusinessObjectService(SpringContext.getBean(BusinessObjectService.class)); 102 setDocumentService(SpringContext.getBean(DocumentService.class)); 103 104 customernames = Arrays.asList(jobName); 105 } else { 106 customernames = Arrays.asList("ABB2", "3MC17500","ACE21725","ANT7297","CAR23612", "CON19567", "DEL14448", "EAT17609", "GAP17272"); 107 } 108 109 // create non-random data 110 if (customernames.size() > 1) { 111 for (int i = 0; i < NUMBER_OF_INVOICES_TO_CREATE; i++) { 112 113 billingDate = DateUtils.addDays(billingDate, -30); 114 115 createCustomerInvoiceDocumentForFunctionalTesting("HIL22195", billingDate, 1, new KualiDecimal(10), new BigDecimal(1), "2336320", "BL", "BUSCF"); // $10 entries 116 createCustomerInvoiceDocumentForFunctionalTesting("IBM2655", billingDate, 2, new KualiDecimal(10), new BigDecimal(1), "2336320", "BL", "IBCE"); // $20 entries 117 createCustomerInvoiceDocumentForFunctionalTesting("JAS19572", billingDate, 3, new KualiDecimal(10), new BigDecimal(1), "2336320", "BL", "WRB"); // $30 entries 118 119 Thread.sleep(500); 120 } 121 } 122 123 // easy dynamic data creation 124 if (customernames.size() == 1) { 125 billingDate = jobRunDate; 126 createCustomerInvoiceDocumentForFunctionalTesting(customernames.get(0), billingDate, 1, new KualiDecimal(10), new BigDecimal(1), "1111111", "BA", "MATT"); // $10 entries 127 Thread.sleep(500); 128 } 129 130 // create lockboxes for the non-random invoices 131 Long seqNbr = findAvailableLockboxBaseSeqNbr(); 132 int scenarioNbr =1; 133 for (String createdInvoice : createdInvoices){ 134 createLockboxesForFunctionalTesting(createdInvoice, seqNbr, scenarioNbr); 135 Thread.sleep(500); 136 seqNbr++; 137 if (scenarioNbr<=6) { 138 scenarioNbr++; 139 } 140 else { 141 scenarioNbr = 1; 142 } 143 } 144 145 // create random data 146 // if (customernames.size() > 1) { 147 // for (String customername : customernames) { 148 // 149 // billingDate = getDateTimeService().getCurrentDate(); 150 // 151 // for( int i = 0; i < NUMBER_OF_INVOICES_TO_CREATE; i++ ){ 152 // 153 // billingDate = DateUtils.addDays(billingDate, -30); 154 // 155 // createCustomerInvoiceDocumentForFunctionalTesting(customername,billingDate, 0, null, null, "1031400", "BL"); 156 // Thread.sleep(500); 157 // 158 // } 159 // } 160 // } 161 162 163 164 // save runParameter as "N" so that the job won't run until DB has been cleared 165 setInitiatedParameter(); 166 } 167 return true; 168 } 169 170 private long findAvailableLockboxBaseSeqNbr() { 171 LockboxService lockboxService = SpringContext.getBean(LockboxService.class); 172 return lockboxService.getMaxLockboxSequenceNumber() + MAX_SEQ_NBR_OFFSET; 173 } 174 175 private boolean dupLockboxRecordExists(Long seqNbr) { 176 Map<String,Long> pks = new HashMap<String,Long>(); 177 pks.put("invoiceSequenceNumber", seqNbr); 178 Lockbox dupLockBox = (Lockbox) businessObjectService.findByPrimaryKey(Lockbox.class, pks); 179 return (dupLockBox != null); 180 } 181 182 /** 183 * This method sets a parameter that tells the step that it has already run and it does not need to run again. 184 */ 185 private void setInitiatedParameter() { 186 // first see if we can find an existing Parameter object with this key 187 Parameter runIndicatorParameter = (Parameter) businessObjectService.findByPrimaryKey(Parameter.class, this.buildSearchKeyMap()); 188 if (runIndicatorParameter == null) 189 { 190 runIndicatorParameter = new Parameter(); 191 runIndicatorParameter.setVersionNumber(new Long(1)); 192 runIndicatorParameter.setParameterNamespaceCode(CustomerInvoiceDocumentBatchStep.RUN_INDICATOR_PARAMETER_NAMESPACE_CODE); 193 runIndicatorParameter.setParameterDetailTypeCode(CustomerInvoiceDocumentBatchStep.RUN_INDICATOR_PARAMETER_NAMESPACE_STEP); 194 runIndicatorParameter.setParameterName(Job.STEP_RUN_PARM_NM); 195 runIndicatorParameter.setParameterDescription(RUN_INDICATOR_PARAMETER_DESCRIPTION); 196 runIndicatorParameter.setParameterConstraintCode(CustomerInvoiceDocumentBatchStep.RUN_INDICATOR_PARAMETER_ALLOWED); 197 runIndicatorParameter.setParameterTypeCode(CustomerInvoiceDocumentBatchStep.RUN_INDICATOR_PARAMETER_TYPE); 198 runIndicatorParameter.setParameterApplicationNamespaceCode(CustomerInvoiceDocumentBatchStep.RUN_INDICATOR_PARAMETER_APPLICATION_NAMESPACE_CODE); 199 } 200 runIndicatorParameter.setParameterValue(CustomerInvoiceDocumentBatchStep.RUN_INDICATOR_PARAMETER_VALUE); 201 businessObjectService.save(runIndicatorParameter); 202 } 203 204 private Map<String,Object> buildSearchKeyMap() 205 { 206 Map<String,Object> pkMapForParameter = new HashMap<String,Object>(); 207 PersistenceStructureService psService = SpringContext.getBean(PersistenceStructureService.class); 208 209 // set up a list of all the field names and values of the fields in the Parameter object. 210 // the OJB names are nowhere in Kuali properties, apparently. 211 // but, since we use set routines above, we know what the names must be. if they change at some point, we will have to change the set routines anyway. 212 // we can change the code here also when we do that. 213 Map<String,Object> fieldNamesValuesForParameter = new HashMap<String,Object>(); 214 fieldNamesValuesForParameter.put("parameterNamespaceCode",CustomerInvoiceDocumentBatchStep.RUN_INDICATOR_PARAMETER_NAMESPACE_CODE); 215 fieldNamesValuesForParameter.put("parameterDetailTypeCode",CustomerInvoiceDocumentBatchStep.RUN_INDICATOR_PARAMETER_NAMESPACE_STEP); 216 fieldNamesValuesForParameter.put("parameterName",Job.STEP_RUN_PARM_NM); 217 fieldNamesValuesForParameter.put("parameterConstraintCode",CustomerInvoiceDocumentBatchStep.RUN_INDICATOR_PARAMETER_ALLOWED); 218 fieldNamesValuesForParameter.put("parameterTypeCode",CustomerInvoiceDocumentBatchStep.RUN_INDICATOR_PARAMETER_TYPE); 219 220 // get the primary keys and assign them to values 221 List<String> parameterPKFields = psService.getPrimaryKeys(Parameter.class); 222 for (String pkFieldName: parameterPKFields) 223 { 224 pkMapForParameter.put(pkFieldName,fieldNamesValuesForParameter.get(pkFieldName)); 225 } 226 return (pkMapForParameter); 227 } 228 229 private Lockbox populateLockbox(String invoiceNumber, Long seqNbr) { 230 231 CustomerInvoiceDocument customerInvoiceDocument = customerInvoiceDocumentService.getInvoiceByInvoiceDocumentNumber(invoiceNumber); 232 233 Lockbox newLockbox = new Lockbox(); 234 newLockbox.setFinancialDocumentReferenceInvoiceNumber(invoiceNumber); 235 newLockbox.setCustomerNumber(customerInvoiceDocument.getCustomer().getCustomerNumber()); 236 newLockbox.setInvoiceTotalAmount(customerInvoiceDocument.getTotalDollarAmount()); 237 newLockbox.setInvoicePaidOrAppliedAmount(customerInvoiceDocument.getOpenAmount()); 238 newLockbox.setBillingDate(customerInvoiceDocument.getBillingDate()); 239 newLockbox.setCustomerPaymentMediumCode("CK"); 240 newLockbox.setBankCode("1003"); 241 newLockbox.setBatchSequenceNumber(8004); 242 newLockbox.setInvoiceSequenceNumber(seqNbr); 243 newLockbox.setLockboxNumber("66249"); 244 245 return newLockbox; 246 } 247 248 private void createLockboxesForFunctionalTesting(String invoiceNumber, Long seqNbr, int testtype) throws InterruptedException { 249 250 Lockbox newLockbox = populateLockbox(invoiceNumber, seqNbr); 251 252 // 1) Payment matches customer (CUST_NBR), invoice number (FDOC_REF_INV_NBR), and amount (AR_INV_PD_APLD_AMT). These should auto-approve, the remaining scenarios should not. 253 if (testtype == 1) { 254 // dont need to do anything, its auto-set to pay the OpenAmount on the invoice 255 } 256 257 // 2) Payment matches customer and invoice, but the invoice has no outstanding balance (due to a previous payment, a credit memo, or a write-off) 258 if (testtype == 2) { 259 newLockbox.setInvoicePaidOrAppliedAmount(newLockbox.getInvoiceTotalAmount()); 260 writeoffInvoice(invoiceNumber); 261 } 262 263 // 3) Payment matches customer and invoice, but the amount of the payment exceeds the outstanding balance on the invoice. 264 if (testtype == 3) { 265 newLockbox.setInvoicePaidOrAppliedAmount(newLockbox.getInvoicePaidOrAppliedAmount().add(new KualiDecimal("100.00"))); 266 } 267 268 // 4) The payment matches customer and invoice, but the amount is short-paid (less than the invoice outstanding balance) 269 if (testtype == 4) { 270 newLockbox.setInvoicePaidOrAppliedAmount(newLockbox.getInvoicePaidOrAppliedAmount().subtract(new KualiDecimal("1.00"))); 271 } 272 273 // 5) The payment matches a customer number, but the invoice number is missing 274 if (testtype == 5) { 275 newLockbox.setFinancialDocumentReferenceInvoiceNumber(null); 276 } 277 278 // 6) The payment matches a customer number, but the invoice number is invalid 279 if (testtype == 6) { 280 newLockbox.setFinancialDocumentReferenceInvoiceNumber("999999"); 281 } 282 283 // 7) The payment matches nothing (not even the customer number) 284 if (testtype == 7) { 285 newLockbox.setFinancialDocumentReferenceInvoiceNumber("999999"); 286 newLockbox.setCustomerNumber("KEY17536"); 287 } 288 289 LOG.info("Creating customer LOCKBOX [" + seqNbr.toString() + "] for invoice " + invoiceNumber); 290 if (dupLockboxRecordExists(seqNbr)) { 291 throw new RuntimeException("Trying to enter duplicate Lockbox.invoiceSequenceNumber, which will fail, and should never happen."); 292 } 293 businessObjectService.save(newLockbox); 294 } 295 296 public void writeoffInvoice(String invoiceNumberToWriteOff) { 297 CustomerInvoiceWriteoffDocumentService writeoffService = SpringContext.getBean(CustomerInvoiceWriteoffDocumentService.class); 298 Person initiator = SpringContext.getBean(PersonService.class).getPersonByPrincipalName(INITIATOR_PRINCIPAL_NAME); 299 300 // have the service create us a new writeoff doc 301 String writeoffDocNumber; 302 try { 303 writeoffDocNumber = writeoffService.createCustomerInvoiceWriteoffDocument(initiator, invoiceNumberToWriteOff, 304 "Created by CustomerInvoiceDocumentBatch process."); 305 } 306 catch (WorkflowException e) { 307 throw new RuntimeException("A WorkflowException was thrown when trying to create a new Invoice Writeoff document.", e); 308 } 309 310 // load the newly created writeoff doc from the db 311 CustomerInvoiceWriteoffDocument writeoff; 312 try { 313 writeoff = (CustomerInvoiceWriteoffDocument) documentService.getByDocumentHeaderId(writeoffDocNumber); 314 } 315 catch (WorkflowException e) { 316 throw new RuntimeException("A WorkflowException was thrown when trying to load Invoice Writeoff doc #" + writeoffDocNumber + ".", e); 317 } 318 319 boolean wentToFinal = false; 320 try { 321 wentToFinal = waitForStatusChange(60, writeoff.getDocumentHeader().getWorkflowDocument(), new String[] {"F", "P"}); 322 } 323 catch (Exception e) { 324 throw new RuntimeException("An Exception was thrown when trying to monitor writeoff doc #" + writeoffDocNumber +" going to FINAL.", e); 325 } 326 327 // if the doc didnt go to final, then blanket approve the doc, bypassing all rules 328 if (!wentToFinal) { 329 try { 330 if (writeoff.getDocumentHeader().getWorkflowDocument().stateIsFinal()) { 331 332 } 333 writeoff.getDocumentHeader().getWorkflowDocument().blanketApprove("BlanketApproved by CustomerInvoiceDocumentBatch process."); 334 } 335 catch (WorkflowException e) { 336 throw new RuntimeException("A WorkflowException was thrown when trying to blanketApprove Invoice Writeoff doc #" + writeoffDocNumber + ".", e); 337 } 338 339 // wait for it to go to final 340 wentToFinal = false; 341 try { 342 wentToFinal = waitForStatusChange(60, writeoff.getDocumentHeader().getWorkflowDocument(), new String[] {"F", "P"}); 343 } 344 catch (Exception e) { 345 throw new RuntimeException("An Exception was thrown when trying to monitor writeoff doc #" + writeoffDocNumber +" going to FINAL.", e); 346 } 347 } 348 349 if (!wentToFinal) { 350 throw new RuntimeException("InvoiceWriteoff document #" + writeoffDocNumber + " failed to route to FINAL."); 351 } 352 } 353 354 public boolean waitForStatusChange(int numSeconds, KualiWorkflowDocument document, String[] desiredStatus) throws Exception { 355 DocWorkflowStatusMonitor monitor = new DocWorkflowStatusMonitor(SpringContext.getBean(DocumentService.class), "" + document.getRouteHeaderId(), desiredStatus); 356 return waitUntilChange(monitor, numSeconds, 5); 357 } 358 359 /** 360 * Iterates, with pauseSeconds seconds between iterations, until either the given ChangeMonitor's valueChanged method returns 361 * true, or at least maxWaitSeconds seconds have passed. 362 * 363 * @param monitor ChangeMonitor instance which watches for whatever change your test is waiting for 364 * @param maxWaitSeconds 365 * @param pauseSeconds 366 * @return true if the the ChangeMonitor's valueChanged method returned true before time ran out 367 */ 368 public boolean waitUntilChange(DocWorkflowStatusMonitor monitor, int maxWaitSeconds, int pauseSeconds) throws Exception { 369 long maxWaitMs = maxWaitSeconds * 1000; 370 long pauseMs = pauseSeconds * 1000; 371 372 boolean valueChanged = false; 373 boolean interrupted = false; 374 long startTimeMs = System.currentTimeMillis(); 375 long endTimeMs = startTimeMs + maxWaitMs; 376 377 Thread.sleep(pauseMs / 10); // the first time through, sleep a fraction of the specified time 378 valueChanged = monitor.valueChanged(); 379 while (!interrupted && !valueChanged && (System.currentTimeMillis() < endTimeMs)) { 380 try { 381 Thread.sleep(pauseMs); 382 } 383 catch (InterruptedException e) { 384 interrupted = true; 385 } 386 valueChanged = monitor.valueChanged(); 387 } 388 return valueChanged; 389 } 390 391 // public void writeoffInvoice(String invoiceToWriteOff) { 392 // CustomerCreditMemoDetailService customerCreditMemoDetailService = SpringContext.getBean(CustomerCreditMemoDetailService.class); 393 // CustomerCreditMemoDocument customerCreditMemoDocument; 394 // CustomerCreditMemoDetail customerCreditMemoDetail = new CustomerCreditMemoDetail(); 395 // CustomerInvoiceDocument customerInvoiceDocument; 396 // 397 // try { 398 // customerInvoiceDocument = (CustomerInvoiceDocument) documentService.getNewDocument(CustomerInvoiceDocument.class); 399 // LOG.info("\nCreated customer invoice document " + customerInvoiceDocument.getDocumentNumber()); 400 // } catch (WorkflowException e) { 401 // throw new RuntimeException("Customer Invoice Document creation failed."); 402 // } 403 // 404 // customerInvoiceDocumentService.setupDefaultValuesForNewCustomerInvoiceDocument(customerInvoiceDocument); 405 // customerInvoiceDocument.getDocumentHeader().setDocumentDescription("TEST paid off CUSTOMER INVOICE DOCUMENT"); 406 // customerInvoiceDocument.getAccountsReceivableDocumentHeader().setCustomerNumber("KAT17282"); 407 // customerInvoiceDocument.setBillingDate(getDateTimeService().getCurrentSqlDate()); 408 // 409 // CustomerAddress customerBillToAddress = SpringContext.getBean(CustomerAddressService.class).getPrimaryAddress("KAT17282"); 410 // 411 // customerInvoiceDocument.setCustomerBillToAddress(customerBillToAddress); 412 // customerInvoiceDocument.setCustomerBillToAddressIdentifier(1); 413 // customerInvoiceDocument.setBillingAddressTypeCode("P"); 414 // customerInvoiceDocument.setBillingAddressName(customerBillToAddress.getCustomerAddressName()); 415 // customerInvoiceDocument.setBillingLine1StreetAddress(customerBillToAddress.getCustomerLine1StreetAddress()); 416 // customerInvoiceDocument.setBillingLine2StreetAddress(customerBillToAddress.getCustomerLine2StreetAddress()); 417 // customerInvoiceDocument.setBillingCityName(customerBillToAddress.getCustomerCityName()); 418 // customerInvoiceDocument.setBillingStateCode(customerBillToAddress.getCustomerStateCode()); 419 // customerInvoiceDocument.setBillingZipCode(customerBillToAddress.getCustomerZipCode()); 420 // customerInvoiceDocument.setBillingCountryCode(customerBillToAddress.getCustomerCountryCode()); 421 // customerInvoiceDocument.setBillingAddressInternationalProvinceName(customerBillToAddress.getCustomerAddressInternationalProvinceName()); 422 // customerInvoiceDocument.setBillingInternationalMailCode(customerBillToAddress.getCustomerInternationalMailCode()); 423 // customerInvoiceDocument.setBillingEmailAddress(customerBillToAddress.getCustomerEmailAddress()); 424 // customerInvoiceDocument.addSourceAccountingLine(createCustomerInvoiceDetailForFunctionalTesting(customerInvoiceDocument, new KualiDecimal(1), new BigDecimal(100), "2336320", "BL", "ISRT" )); 425 // 426 // customerCreditMemoDetail.setCreditMemoItemQuantity(new BigDecimal(100)); 427 // customerCreditMemoDetail.setDuplicateCreditMemoItemTotalAmount(); 428 // try { 429 // // the document header is created and set here 430 // 431 // customerCreditMemoDocument = (CustomerCreditMemoDocument) DocumentTestUtils.createDocument(SpringContext.getBean(DocumentService.class), CustomerCreditMemoDocument.class); 432 // } 433 // catch (WorkflowException e) { 434 // throw new RuntimeException("Document customerCreditMemoDocument creation failed."); 435 // } 436 // customerCreditMemoDocument.setFinancialDocumentReferenceInvoiceNumber(customerInvoiceDocument.getDocumentNumber()); 437 // customerCreditMemoDocument.setInvoice(customerInvoiceDocument); 438 // customerCreditMemoDocument.populateCustomerCreditMemoDetails(); 439 // 440 // List<CustomerCreditMemoDetail> customerCreditMemoDetails = customerCreditMemoDocument.getCreditMemoDetails(); 441 // for (CustomerCreditMemoDetail customerCreditMemoDetail : customerCreditMemoDetails) { 442 // customerCreditMemoDetail.setCreditMemoItemQuantity(new BigDecimal(1)); 443 // customerCreditMemoDetail.setCreditMemoItemTotalAmount(new KualiDecimal(100)); 444 // customerCreditMemoDetail.setCreditMemoLineTotalAmount(new KualiDecimal(100)); 445 // } 446 // 447 // try { 448 // documentService.blanketApproveDocument(customerInvoiceDocument, null, null); 449 // Thread.sleep(5000); 450 // documentService.blanketApproveDocument(customerCreditMemoDocument, null, null); 451 // LOG.info("Created customer credit memo " + customerCreditMemoDocument.getDocumentNumber()); 452 // } catch (WorkflowException e) { 453 // throw new RuntimeException("Customer Invoice Document routing failed."); 454 // } 455 // LOG.info("Created customer credit memo " + customerCreditMemoDocument.getDocumentNumber()); 456 // 457 // } 458 459 460 public void createCustomerInvoiceDocumentForFunctionalTesting(String customerNumber, Date billingDate, int numinvoicedetails, KualiDecimal nonrandomquantity, BigDecimal nonrandomunitprice, String accountnumber, String chartcode, String invoiceitemcode) { 461 SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy"); 462 463 CustomerInvoiceDocument customerInvoiceDocument; 464 try { 465 customerInvoiceDocument = (CustomerInvoiceDocument)documentService.getNewDocument(CustomerInvoiceDocument.class); 466 LOG.info("Created customer invoice document " + customerInvoiceDocument.getDocumentNumber()); 467 } catch (WorkflowException e) { 468 throw new RuntimeException("Customer Invoice Document creation failed."); 469 } 470 471 customerInvoiceDocumentService.setupDefaultValuesForNewCustomerInvoiceDocument(customerInvoiceDocument); 472 //customerInvoiceDocument.getDocumentHeader().setDocumentDescription(customerNumber+" - TEST CUSTOMER INVOICE DOCUMENT");// - BILLING DATE - "+sdf.format(billingDate)); 473 customerInvoiceDocument.getDocumentHeader().setDocumentDescription("TEST CUSTOMER INVOICE DOCUMENT"); 474 customerInvoiceDocument.getAccountsReceivableDocumentHeader().setCustomerNumber(customerNumber); 475 customerInvoiceDocument.setBillingDate(new java.sql.Date(billingDate.getTime())); 476 477 CustomerAddress customerBillToAddress = SpringContext.getBean(CustomerAddressService.class).getPrimaryAddress(customerNumber); 478 // CustomerAddress customerShipToAddress = SpringContext.getBean(CustomerAddressService.class).getPrimaryAddress(customerNumber); 479 480 customerInvoiceDocument.setCustomerBillToAddress(customerBillToAddress); 481 customerInvoiceDocument.setCustomerBillToAddressIdentifier(1); 482 customerInvoiceDocument.setBillingAddressTypeCode("P"); 483 customerInvoiceDocument.setBillingAddressName(customerBillToAddress.getCustomerAddressName()); 484 customerInvoiceDocument.setBillingLine1StreetAddress(customerBillToAddress.getCustomerLine1StreetAddress()); 485 customerInvoiceDocument.setBillingLine2StreetAddress(customerBillToAddress.getCustomerLine2StreetAddress()); 486 customerInvoiceDocument.setBillingCityName(customerBillToAddress.getCustomerCityName()); 487 customerInvoiceDocument.setBillingStateCode(customerBillToAddress.getCustomerStateCode()); 488 customerInvoiceDocument.setBillingZipCode(customerBillToAddress.getCustomerZipCode()); 489 customerInvoiceDocument.setBillingCountryCode(customerBillToAddress.getCustomerCountryCode()); 490 customerInvoiceDocument.setBillingAddressInternationalProvinceName(customerBillToAddress.getCustomerAddressInternationalProvinceName()); 491 customerInvoiceDocument.setBillingInternationalMailCode(customerBillToAddress.getCustomerInternationalMailCode()); 492 customerInvoiceDocument.setBillingEmailAddress(customerBillToAddress.getCustomerEmailAddress()); 493 494 // customerInvoiceDocument.setCustomerShipToAddress(customerShipToAddress); 495 // customerInvoiceDocument.setShippingAddressTypeCode("P"); 496 // customerInvoiceDocument.setShippingAddressName(customerShipToAddress.getCustomerAddressName()); 497 // customerInvoiceDocument.setShippingLine1StreetAddress(customerShipToAddress.getCustomerLine1StreetAddress()); 498 // customerInvoiceDocument.setShippingLine2StreetAddress(customerShipToAddress.getCustomerLine2StreetAddress()); 499 // customerInvoiceDocument.setShippingCityName(customerShipToAddress.getCustomerCityName()); 500 // customerInvoiceDocument.setShippingStateCode(customerShipToAddress.getCustomerStateCode()); 501 // customerInvoiceDocument.setShippingZipCode(customerShipToAddress.getCustomerZipCode()); 502 // customerInvoiceDocument.setShippingCountryCode(customerShipToAddress.getCustomerCountryCode()); 503 // customerInvoiceDocument.setShippingAddressInternationalProvinceName(customerShipToAddress.getCustomerAddressInternationalProvinceName()); 504 // customerInvoiceDocument.setShippingInternationalMailCode(customerShipToAddress.getCustomerInternationalMailCode()); 505 // customerInvoiceDocument.setShippingEmailAddress(customerShipToAddress.getCustomerEmailAddress()); 506 507 508 if (ObjectUtils.isNotNull(nonrandomquantity)&&ObjectUtils.isNotNull(nonrandomunitprice)&&numinvoicedetails>=1) { 509 for (int i = 0; i < numinvoicedetails; i++) { 510 customerInvoiceDocument.addSourceAccountingLine(createCustomerInvoiceDetailForFunctionalTesting(customerInvoiceDocument, nonrandomquantity, nonrandomunitprice, accountnumber, chartcode, invoiceitemcode)); 511 } 512 } else { 513 int randomnuminvoicedetails = (int) (Math.random()*9); // add up to 9 514 if (randomnuminvoicedetails==0) randomnuminvoicedetails=1; // add at least one 515 for (int i = 0; i < randomnuminvoicedetails; i++) { 516 customerInvoiceDocument.addSourceAccountingLine(createCustomerInvoiceDetailForFunctionalTesting(customerInvoiceDocument, null, null, accountnumber, chartcode, invoiceitemcode)); 517 } 518 } 519 try { 520 documentService.blanketApproveDocument(customerInvoiceDocument, null, null); 521 createdInvoices.add(customerInvoiceDocument.getDocumentNumber()); 522 LOG.info("Submitted customer invoice document " + customerInvoiceDocument.getDocumentNumber()+" for "+customerNumber+" - "+sdf.format(billingDate)+"\n\n"); 523 } catch (WorkflowException e){ 524 throw new RuntimeException("Customer Invoice Document routing failed."); 525 } 526 } 527 528 public CustomerInvoiceDetail createCustomerInvoiceDetailForFunctionalTesting(CustomerInvoiceDocument customerInvoiceDocument, KualiDecimal nonrandomquantity, BigDecimal nonrandomunitprice, String accountnumber, String chartcode, String invoiceitemcode){ 529 530 KualiDecimal quantity; 531 BigDecimal unitprice; 532 533 if (ObjectUtils.isNull(nonrandomquantity)) { 534 quantity = new KualiDecimal(100*Math.random()); // random number 0 to 100 total items // TODO FIXME <-- InvoiceItemQuantities of more than 2 decimal places cause rule errors; BigDecimal values such as 5.3333333333 should be valid InvoiceItemQuantities 535 } else { 536 quantity = nonrandomquantity; 537 } 538 if (ObjectUtils.isNull(nonrandomunitprice)) { 539 unitprice = new BigDecimal(1); // 0.00 to 100.00 dollars per item 540 } else { 541 unitprice = nonrandomunitprice; 542 } 543 544 KualiDecimal amount = quantity.multiply(new KualiDecimal(unitprice)); // setAmount has to be set explicitly below; so we calculate it here 545 //LOG.info("\n\n\n\n\t\t\t\t quantity="+quantity.toString()+"\t\t\t\tprice="+unitprice.toString()+"\t\t\t\tamount="+amount.toString()+"\t\t\t\t"+customerInvoiceDocument.getCustomerName()); 546 547 CustomerInvoiceDetail customerInvoiceDetail = new CustomerInvoiceDetail(); 548 customerInvoiceDetail.setDocumentNumber(customerInvoiceDocument.getDocumentNumber()); 549 customerInvoiceDetail.setChartOfAccountsCode(chartcode); 550 customerInvoiceDetail.setAccountNumber(accountnumber); // other BL account numbers: 2231401 2324601 551 customerInvoiceDetail.setFinancialObjectCode("1800"); 552 customerInvoiceDetail.setAccountsReceivableObjectCode("8118"); 553 customerInvoiceDetail.setInvoiceItemCode(invoiceitemcode); 554 customerInvoiceDetail.setInvoiceItemServiceDate(dateTimeService.getCurrentSqlDate()); 555 customerInvoiceDetail.setInvoiceItemUnitPrice(unitprice); 556 customerInvoiceDetail.setInvoiceItemQuantity(quantity.bigDecimalValue()); 557 customerInvoiceDetail.setInvoiceItemTaxAmount(new KualiDecimal(100)); 558 customerInvoiceDetail.setTaxableIndicator(true); 559 customerInvoiceDetail.setAmount(amount); 560 customerInvoiceDetail.setPostingYear(currentYear); 561 562 563 return customerInvoiceDetail; 564 } 565 566 567 public DateTimeService getDateTimeService() { 568 return dateTimeService; 569 } 570 571 572 public void setDateTimeService(DateTimeService dateTimeService) { 573 this.dateTimeService = dateTimeService; 574 } 575 576 577 public DocumentService getDocumentService() { 578 return documentService; 579 } 580 581 582 public void setDocumentService(DocumentService documentService) { 583 this.documentService = documentService; 584 } 585 586 public CustomerInvoiceDocumentService getCustomerInvoiceDocumentService() { 587 return customerInvoiceDocumentService; 588 } 589 590 591 public void setCustomerInvoiceDocumentService(CustomerInvoiceDocumentService customerInvoiceDocumentService) { 592 this.customerInvoiceDocumentService = customerInvoiceDocumentService; 593 } 594 595 596 public BusinessObjectService getBusinessObjectService() { 597 return businessObjectService; 598 } 599 600 601 public void setBusinessObjectService(BusinessObjectService businessObjectService) { 602 this.businessObjectService = businessObjectService; 603 } 604 605 private class DocWorkflowStatusMonitor { 606 final DocumentService documentService; 607 final private String docHeaderId; 608 final private String[] desiredWorkflowStates; 609 610 public DocWorkflowStatusMonitor(DocumentService documentService, String docHeaderId, String desiredWorkflowStatus) { 611 this.documentService = documentService; 612 this.docHeaderId = docHeaderId; 613 this.desiredWorkflowStates = new String[] { desiredWorkflowStatus }; 614 } 615 616 public DocWorkflowStatusMonitor(DocumentService documentService, String docHeaderId, String[] desiredWorkflowStates) { 617 this.documentService = documentService; 618 this.docHeaderId = docHeaderId; 619 this.desiredWorkflowStates = desiredWorkflowStates; 620 } 621 622 public boolean valueChanged() throws Exception { 623 Document d = documentService.getByDocumentHeaderId(docHeaderId.toString()); 624 625 String currentStatus = d.getDocumentHeader().getWorkflowDocument().getRouteHeader().getDocRouteStatus(); 626 627 for (int i = 0; i < desiredWorkflowStates.length; i++) { 628 if (StringUtils.equals(desiredWorkflowStates[i], currentStatus)) { 629 return true; 630 } 631 } 632 return false; 633 } 634 } 635 } 636