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