/* * The Kuali Financial System, a comprehensive financial management system for higher education. * * Copyright 2005-2014 The Kuali Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kuali.kfs.module.ar.batch; import java.math.BigDecimal; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.time.DateUtils; import org.kuali.kfs.module.ar.ArConstants; import org.kuali.kfs.module.ar.batch.service.LockboxService; import org.kuali.kfs.module.ar.businessobject.CustomerAddress; import org.kuali.kfs.module.ar.businessobject.CustomerInvoiceDetail; import org.kuali.kfs.module.ar.businessobject.Lockbox; import org.kuali.kfs.module.ar.document.CustomerInvoiceDocument; import org.kuali.kfs.module.ar.document.CustomerInvoiceWriteoffDocument; import org.kuali.kfs.module.ar.document.service.CustomerAddressService; import org.kuali.kfs.module.ar.document.service.CustomerInvoiceDocumentService; import org.kuali.kfs.module.ar.document.service.CustomerInvoiceWriteoffDocumentService; import org.kuali.kfs.sys.KFSConstants; import org.kuali.kfs.sys.batch.AbstractStep; import org.kuali.kfs.sys.batch.Job; import org.kuali.kfs.sys.batch.TestingStep; import org.kuali.rice.core.api.datetime.DateTimeService; import org.kuali.rice.core.api.util.type.KualiDecimal; import org.kuali.rice.coreservice.api.parameter.EvaluationOperator; import org.kuali.rice.coreservice.api.parameter.Parameter; import org.kuali.rice.coreservice.api.parameter.ParameterType; import org.kuali.rice.kew.api.WorkflowDocument; import org.kuali.rice.kew.api.exception.WorkflowException; import org.kuali.rice.krad.UserSession; import org.kuali.rice.krad.document.Document; import org.kuali.rice.krad.service.BusinessObjectService; import org.kuali.rice.krad.service.DocumentService; import org.kuali.rice.krad.util.GlobalVariables; import org.kuali.rice.krad.util.ObjectUtils; public class CustomerInvoiceDocumentBatchStep extends AbstractStep implements TestingStep { private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(CustomerInvoiceDocumentBatchStep.class); protected static final long MAX_SEQ_NBR_OFFSET = 1000; protected CustomerInvoiceDocumentService customerInvoiceDocumentService; protected BusinessObjectService businessObjectService; protected DocumentService documentService; protected DateTimeService dateTimeService; protected LockboxService lockboxService; protected CustomerAddressService customerAddressService; protected CustomerInvoiceWriteoffDocumentService writeoffService; protected Collection<String> createdInvoices = new ArrayList<String>(); // parameter constants and logging protected static final int NUMBER_OF_INVOICES_TO_CREATE = 5; protected static final String RUN_INDICATOR_PARAMETER_NAMESPACE_CODE = ArConstants.AR_NAMESPACE_CODE; protected static final String RUN_INDICATOR_PARAMETER_APPLICATION_NAMESPACE_CODE = KFSConstants.APPLICATION_NAMESPACE_CODE; protected static final String RUN_INDICATOR_PARAMETER_NAMESPACE_STEP = CustomerInvoiceDocumentBatchStep.class.getSimpleName(); protected static final String RUN_INDICATOR_PARAMETER_VALUE = "N"; // Tells the job framework whether to run this job or not; set to N because the CustomerInvoiceDocumentBatchStep needs to only be run once after database initialization. protected static final String RUN_INDICATOR_PARAMETER_ALLOWED = "A"; protected static 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."; protected static final String RUN_INDICATOR_PARAMETER_TYPE = "CONFG"; protected static final String INITIATOR_PRINCIPAL_NAME = "khuntley"; protected final int currentYear = Calendar.getInstance().get(Calendar.YEAR); @Override public boolean execute(String jobName, Date jobRunDate) throws InterruptedException { Parameter runIndicatorParameter = getParameterService().getParameter(RUN_INDICATOR_PARAMETER_NAMESPACE_CODE, RUN_INDICATOR_PARAMETER_NAMESPACE_STEP, Job.STEP_RUN_PARM_NM); if (runIndicatorParameter == null || StringUtils.equals("Y", runIndicatorParameter.getValue())) { GlobalVariables.clear(); GlobalVariables.setUserSession(new UserSession(INITIATOR_PRINCIPAL_NAME)); Date billingDate = getDateTimeService().getCurrentDate(); List<String> customernames; if ((jobName.length() <=8 ) && (jobName.length() >= 4)) { customernames = Arrays.asList(jobName); } else { customernames = Arrays.asList("ABB2", "3MC17500","ACE21725","ANT7297","CAR23612", "CON19567", "DEL14448", "EAT17609", "GAP17272"); } // create non-random data if (customernames.size() > 1) { for (int i = 0; i < NUMBER_OF_INVOICES_TO_CREATE; i++) { billingDate = DateUtils.addDays(billingDate, -30); createCustomerInvoiceDocumentForFunctionalTesting("HIL22195", billingDate, 1, new KualiDecimal(10), new BigDecimal(1), "2336320", "BL", "BUSCF"); // $10 entries createCustomerInvoiceDocumentForFunctionalTesting("IBM2655", billingDate, 2, new KualiDecimal(10), new BigDecimal(1), "2336320", "BL", "IBCE"); // $20 entries createCustomerInvoiceDocumentForFunctionalTesting("JAS19572", billingDate, 3, new KualiDecimal(10), new BigDecimal(1), "2336320", "BL", "WRB"); // $30 entries Thread.sleep(500); } } // easy dynamic data creation if (customernames.size() == 1) { billingDate = jobRunDate; createCustomerInvoiceDocumentForFunctionalTesting(customernames.get(0), billingDate, 1, new KualiDecimal(10), new BigDecimal(1), "1111111", "BA", "MATT"); // $10 entries Thread.sleep(500); } // create lockboxes for the non-random invoices Long seqNbr = findAvailableLockboxBaseSeqNbr(); int scenarioNbr =1; for (String createdInvoice : createdInvoices){ createLockboxesForFunctionalTesting(createdInvoice, seqNbr, scenarioNbr); Thread.sleep(500); seqNbr++; if (scenarioNbr<=6) { scenarioNbr++; } else { scenarioNbr = 1; } } // create random data // if (customernames.size() > 1) { // for (String customername : customernames) { // // billingDate = getDateTimeService().getCurrentDate(); // // for( int i = 0; i < NUMBER_OF_INVOICES_TO_CREATE; i++ ){ // // billingDate = KfsDateUtils.addDays(billingDate, -30); // // createCustomerInvoiceDocumentForFunctionalTesting(customername,billingDate, 0, null, null, "1031400", "BL"); // Thread.sleep(500); // // } // } // } // save runParameter as "N" so that the job won't run until DB has been cleared setInitiatedParameter(); } return true; } private long findAvailableLockboxBaseSeqNbr() { return lockboxService.getMaxLockboxSequenceNumber() + MAX_SEQ_NBR_OFFSET; } private boolean dupLockboxRecordExists(Long seqNbr) { Map<String,Long> pks = new HashMap<String,Long>(); pks.put("invoiceSequenceNumber", seqNbr); Lockbox dupLockBox = businessObjectService.findByPrimaryKey(Lockbox.class, pks); return (dupLockBox != null); } /** * This method sets a parameter that tells the step that it has already run and it does not need to run again. */ private void setInitiatedParameter() { // first see if we can find an existing Parameter object with this key Parameter runIndicatorParameter = getParameterService().getParameter(RUN_INDICATOR_PARAMETER_NAMESPACE_CODE, RUN_INDICATOR_PARAMETER_NAMESPACE_STEP, Job.STEP_RUN_PARM_NM); if (runIndicatorParameter == null) { Parameter.Builder newParm = Parameter.Builder.create(RUN_INDICATOR_PARAMETER_APPLICATION_NAMESPACE_CODE, RUN_INDICATOR_PARAMETER_NAMESPACE_CODE, RUN_INDICATOR_PARAMETER_NAMESPACE_STEP, Job.STEP_RUN_PARM_NM, ParameterType.Builder.create(RUN_INDICATOR_PARAMETER_TYPE)); newParm.setEvaluationOperator(EvaluationOperator.ALLOW); newParm.setDescription(RUN_INDICATOR_PARAMETER_DESCRIPTION); newParm.setValue("N"); getParameterService().createParameter(newParm.build()); } else { Parameter.Builder newParm = Parameter.Builder.create(runIndicatorParameter); newParm.setValue("N"); getParameterService().updateParameter(newParm.build()); } } private Lockbox populateLockbox(String invoiceNumber, Long seqNbr) { CustomerInvoiceDocument customerInvoiceDocument = customerInvoiceDocumentService.getInvoiceByInvoiceDocumentNumber(invoiceNumber); Lockbox newLockbox = new Lockbox(); newLockbox.setFinancialDocumentReferenceInvoiceNumber(invoiceNumber); newLockbox.setCustomerNumber(customerInvoiceDocument.getCustomer().getCustomerNumber()); newLockbox.setInvoiceTotalAmount(customerInvoiceDocument.getTotalDollarAmount()); newLockbox.setInvoicePaidOrAppliedAmount(customerInvoiceDocument.getOpenAmount()); newLockbox.setBillingDate(customerInvoiceDocument.getBillingDate()); newLockbox.setCustomerPaymentMediumCode("CK"); newLockbox.setBankCode("1003"); newLockbox.setBatchSequenceNumber(8004); newLockbox.setInvoiceSequenceNumber(seqNbr); newLockbox.setLockboxNumber("66249"); return newLockbox; } private void createLockboxesForFunctionalTesting(String invoiceNumber, Long seqNbr, int testtype) throws InterruptedException { Lockbox newLockbox = populateLockbox(invoiceNumber, seqNbr); // 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. if (testtype == 1) { // dont need to do anything, its auto-set to pay the OpenAmount on the invoice } // 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) if (testtype == 2) { newLockbox.setInvoicePaidOrAppliedAmount(newLockbox.getInvoiceTotalAmount()); writeoffInvoice(invoiceNumber); } // 3) Payment matches customer and invoice, but the amount of the payment exceeds the outstanding balance on the invoice. if (testtype == 3) { newLockbox.setInvoicePaidOrAppliedAmount(newLockbox.getInvoicePaidOrAppliedAmount().add(new KualiDecimal("100.00"))); } // 4) The payment matches customer and invoice, but the amount is short-paid (less than the invoice outstanding balance) if (testtype == 4) { newLockbox.setInvoicePaidOrAppliedAmount(newLockbox.getInvoicePaidOrAppliedAmount().subtract(new KualiDecimal("1.00"))); } // 5) The payment matches a customer number, but the invoice number is missing if (testtype == 5) { newLockbox.setFinancialDocumentReferenceInvoiceNumber(null); } // 6) The payment matches a customer number, but the invoice number is invalid if (testtype == 6) { newLockbox.setFinancialDocumentReferenceInvoiceNumber("999999"); } // 7) The payment matches nothing (not even the customer number) if (testtype == 7) { newLockbox.setFinancialDocumentReferenceInvoiceNumber("999999"); newLockbox.setCustomerNumber("KEY17536"); } LOG.info("Creating customer LOCKBOX [" + seqNbr.toString() + "] for invoice " + invoiceNumber); if (dupLockboxRecordExists(seqNbr)) { throw new RuntimeException("Trying to enter duplicate Lockbox.invoiceSequenceNumber, which will fail, and should never happen."); } businessObjectService.save(newLockbox); } public void writeoffInvoice(String invoiceNumberToWriteOff) { // have the service create us a new writeoff doc String writeoffDocNumber; try { writeoffDocNumber = writeoffService.createCustomerInvoiceWriteoffDocument(invoiceNumberToWriteOff, "Created by CustomerInvoiceDocumentBatch process."); } catch (WorkflowException e) { throw new RuntimeException("A WorkflowException was thrown when trying to create a new Invoice Writeoff document.", e); } // load the newly created writeoff doc from the db CustomerInvoiceWriteoffDocument writeoff; try { writeoff = (CustomerInvoiceWriteoffDocument) documentService.getByDocumentHeaderId(writeoffDocNumber); } catch (WorkflowException e) { throw new RuntimeException("A WorkflowException was thrown when trying to load Invoice Writeoff doc #" + writeoffDocNumber + ".", e); } boolean wentToFinal = false; try { wentToFinal = waitForStatusChange(60, writeoff.getDocumentHeader().getWorkflowDocument(), new String[] {"F", "P"}); } catch (Exception e) { throw new RuntimeException("An Exception was thrown when trying to monitor writeoff doc #" + writeoffDocNumber +" going to FINAL.", e); } // if the doc didnt go to final, then blanket approve the doc, bypassing all rules if (!wentToFinal) { try { if (writeoff.getDocumentHeader().getWorkflowDocument().isFinal()) { } writeoff.getDocumentHeader().getWorkflowDocument().blanketApprove("BlanketApproved by CustomerInvoiceDocumentBatch process."); } catch (Exception e) { throw new RuntimeException("A WorkflowException was thrown when trying to blanketApprove Invoice Writeoff doc #" + writeoffDocNumber + ".", e); } // wait for it to go to final wentToFinal = false; try { wentToFinal = waitForStatusChange(60, writeoff.getDocumentHeader().getWorkflowDocument(), new String[] {"F", "P"}); } catch (Exception e) { throw new RuntimeException("An Exception was thrown when trying to monitor writeoff doc #" + writeoffDocNumber +" going to FINAL.", e); } } if (!wentToFinal) { throw new RuntimeException("InvoiceWriteoff document #" + writeoffDocNumber + " failed to route to FINAL."); } } public boolean waitForStatusChange(int numSeconds, WorkflowDocument document, String[] desiredStatus) throws Exception { DocWorkflowStatusMonitor monitor = new DocWorkflowStatusMonitor(documentService, "" + document.getDocumentId(), desiredStatus); return waitUntilChange(monitor, numSeconds, 5); } /** * Iterates, with pauseSeconds seconds between iterations, until either the given ChangeMonitor's valueChanged method returns * true, or at least maxWaitSeconds seconds have passed. * * @param monitor ChangeMonitor instance which watches for whatever change your test is waiting for * @param maxWaitSeconds * @param pauseSeconds * @return true if the the ChangeMonitor's valueChanged method returned true before time ran out */ public boolean waitUntilChange(DocWorkflowStatusMonitor monitor, int maxWaitSeconds, int pauseSeconds) throws Exception { long maxWaitMs = maxWaitSeconds * 1000; long pauseMs = pauseSeconds * 1000; boolean valueChanged = false; boolean interrupted = false; long startTimeMs = System.currentTimeMillis(); long endTimeMs = startTimeMs + maxWaitMs; Thread.sleep(pauseMs / 10); // the first time through, sleep a fraction of the specified time valueChanged = monitor.valueChanged(); while (!interrupted && !valueChanged && (System.currentTimeMillis() < endTimeMs)) { try { Thread.sleep(pauseMs); } catch (InterruptedException e) { interrupted = true; } valueChanged = monitor.valueChanged(); } return valueChanged; } public void createCustomerInvoiceDocumentForFunctionalTesting(String customerNumber, Date billingDate, int numinvoicedetails, KualiDecimal nonrandomquantity, BigDecimal nonrandomunitprice, String accountnumber, String chartcode, String invoiceitemcode) { SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy"); CustomerInvoiceDocument customerInvoiceDocument; try { customerInvoiceDocument = (CustomerInvoiceDocument)documentService.getNewDocument(CustomerInvoiceDocument.class); LOG.info("Created customer invoice document " + customerInvoiceDocument.getDocumentNumber()); } catch (WorkflowException e) { throw new RuntimeException("Customer Invoice Document creation failed."); } customerInvoiceDocumentService.setupDefaultValuesForNewCustomerInvoiceDocument(customerInvoiceDocument); //customerInvoiceDocument.getDocumentHeader().setDocumentDescription(customerNumber+" - TEST CUSTOMER INVOICE DOCUMENT");// - BILLING DATE - "+sdf.format(billingDate)); customerInvoiceDocument.getDocumentHeader().setDocumentDescription("TEST CUSTOMER INVOICE DOCUMENT"); customerInvoiceDocument.getAccountsReceivableDocumentHeader().setCustomerNumber(customerNumber); customerInvoiceDocument.setBillingDate(new java.sql.Date(billingDate.getTime())); CustomerAddress customerBillToAddress = customerAddressService.getPrimaryAddress(customerNumber); customerInvoiceDocument.setCustomerBillToAddress(customerBillToAddress); customerInvoiceDocument.setCustomerBillToAddressIdentifier(1); customerInvoiceDocument.setBillingAddressTypeCode("P"); customerInvoiceDocument.setBillingAddressName(customerBillToAddress.getCustomerAddressName()); customerInvoiceDocument.setBillingLine1StreetAddress(customerBillToAddress.getCustomerLine1StreetAddress()); customerInvoiceDocument.setBillingLine2StreetAddress(customerBillToAddress.getCustomerLine2StreetAddress()); customerInvoiceDocument.setBillingCityName(customerBillToAddress.getCustomerCityName()); customerInvoiceDocument.setBillingStateCode(customerBillToAddress.getCustomerStateCode()); customerInvoiceDocument.setBillingZipCode(customerBillToAddress.getCustomerZipCode()); customerInvoiceDocument.setBillingCountryCode(customerBillToAddress.getCustomerCountryCode()); customerInvoiceDocument.setBillingAddressInternationalProvinceName(customerBillToAddress.getCustomerAddressInternationalProvinceName()); customerInvoiceDocument.setBillingInternationalMailCode(customerBillToAddress.getCustomerInternationalMailCode()); customerInvoiceDocument.setBillingEmailAddress(customerBillToAddress.getCustomerEmailAddress()); if (ObjectUtils.isNotNull(nonrandomquantity)&&ObjectUtils.isNotNull(nonrandomunitprice)&&numinvoicedetails>=1) { for (int i = 0; i < numinvoicedetails; i++) { customerInvoiceDocument.addSourceAccountingLine(createCustomerInvoiceDetailForFunctionalTesting(customerInvoiceDocument, nonrandomquantity, nonrandomunitprice, accountnumber, chartcode, invoiceitemcode)); } } else { int randomnuminvoicedetails = (int) (Math.random()*9); // add up to 9 if (randomnuminvoicedetails==0) { randomnuminvoicedetails=1; // add at least one } for (int i = 0; i < randomnuminvoicedetails; i++) { customerInvoiceDocument.addSourceAccountingLine(createCustomerInvoiceDetailForFunctionalTesting(customerInvoiceDocument, null, null, accountnumber, chartcode, invoiceitemcode)); } } try { documentService.blanketApproveDocument(customerInvoiceDocument, null, null); createdInvoices.add(customerInvoiceDocument.getDocumentNumber()); LOG.info("Submitted customer invoice document " + customerInvoiceDocument.getDocumentNumber()+" for "+customerNumber+" - "+sdf.format(billingDate)+"\n\n"); } catch (WorkflowException e){ throw new RuntimeException("Customer Invoice Document routing failed."); } } public CustomerInvoiceDetail createCustomerInvoiceDetailForFunctionalTesting(CustomerInvoiceDocument customerInvoiceDocument, KualiDecimal nonrandomquantity, BigDecimal nonrandomunitprice, String accountnumber, String chartcode, String invoiceitemcode){ KualiDecimal quantity; BigDecimal unitprice; if (ObjectUtils.isNull(nonrandomquantity)) { 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 } else { quantity = nonrandomquantity; } if (ObjectUtils.isNull(nonrandomunitprice)) { unitprice = new BigDecimal(1); // 0.00 to 100.00 dollars per item } else { unitprice = nonrandomunitprice; } KualiDecimal amount = quantity.multiply(new KualiDecimal(unitprice)); // setAmount has to be set explicitly below; so we calculate it here //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()); CustomerInvoiceDetail customerInvoiceDetail = new CustomerInvoiceDetail(); customerInvoiceDetail.setDocumentNumber(customerInvoiceDocument.getDocumentNumber()); customerInvoiceDetail.setChartOfAccountsCode(chartcode); customerInvoiceDetail.setAccountNumber(accountnumber); // other BL account numbers: 2231401 2324601 customerInvoiceDetail.setFinancialObjectCode("1800"); customerInvoiceDetail.setAccountsReceivableObjectCode("8118"); customerInvoiceDetail.setInvoiceItemCode(invoiceitemcode); customerInvoiceDetail.setInvoiceItemServiceDate(dateTimeService.getCurrentSqlDate()); customerInvoiceDetail.setInvoiceItemUnitPrice(unitprice); customerInvoiceDetail.setInvoiceItemQuantity(quantity.bigDecimalValue()); customerInvoiceDetail.setInvoiceItemTaxAmount(new KualiDecimal(100)); customerInvoiceDetail.setTaxableIndicator(true); customerInvoiceDetail.setAmount(amount); customerInvoiceDetail.setPostingYear(currentYear); return customerInvoiceDetail; } @Override public DateTimeService getDateTimeService() { return dateTimeService; } @Override public void setDateTimeService(DateTimeService dateTimeService) { this.dateTimeService = dateTimeService; } public DocumentService getDocumentService() { return documentService; } public void setDocumentService(DocumentService documentService) { this.documentService = documentService; } public CustomerInvoiceDocumentService getCustomerInvoiceDocumentService() { return customerInvoiceDocumentService; } public void setCustomerInvoiceDocumentService(CustomerInvoiceDocumentService customerInvoiceDocumentService) { this.customerInvoiceDocumentService = customerInvoiceDocumentService; } public BusinessObjectService getBusinessObjectService() { return businessObjectService; } public void setBusinessObjectService(BusinessObjectService businessObjectService) { this.businessObjectService = businessObjectService; } public LockboxService getLockboxService() { return lockboxService; } public void setLockboxService(LockboxService lockboxService) { this.lockboxService = lockboxService; } public CustomerInvoiceWriteoffDocumentService getWriteoffService() { return writeoffService; } public void setWriteoffService(CustomerInvoiceWriteoffDocumentService writeoffService) { this.writeoffService = writeoffService; } public CustomerAddressService getCustomerAddressService() { return customerAddressService; } public void setCustomerAddressService(CustomerAddressService customerAddressService) { this.customerAddressService = customerAddressService; } private class DocWorkflowStatusMonitor { final DocumentService documentService; final private String docHeaderId; final private String[] desiredWorkflowStates; public DocWorkflowStatusMonitor(DocumentService documentService, String docHeaderId, String desiredWorkflowStatus) { this.documentService = documentService; this.docHeaderId = docHeaderId; this.desiredWorkflowStates = new String[] { desiredWorkflowStatus }; } public DocWorkflowStatusMonitor(DocumentService documentService, String docHeaderId, String[] desiredWorkflowStates) { this.documentService = documentService; this.docHeaderId = docHeaderId; this.desiredWorkflowStates = desiredWorkflowStates; } public boolean valueChanged() throws Exception { Document d = documentService.getByDocumentHeaderId(docHeaderId.toString()); String currentStatus = d.getDocumentHeader().getWorkflowDocument().getStatus().getCode(); for (int i = 0; i < desiredWorkflowStates.length; i++) { if (StringUtils.equals(desiredWorkflowStates[i], currentStatus)) { return true; } } return false; } } }