We are in the process of doing a complete revamp of how we use ImageNow in AP. We’re moving to a new Workflow process and new Document Types, which is a big deal. We have been using the same setup/process that we designed with Perceptive five years ago. A lot has changed since then and we’ve been putting on bandaids for the last year or so, but we finally decided it was time to pull the trigger and start over.
As part of the redesign, we’re going from seven invoice document types (I’m not sure why we ever thought that was a good idea) to two: PO Invoice and Non-PO Invoice. The business requirements are that all Non-PO Invoices are audited for accuracy by a separate person. PO Invoices do not require auditing because we’re using Lawson, which utilizes a three-way match process between PO-Receiver-Invoice. We are going to have one “Processing” super queue, separated out into several sub-queues. When a clerk completes a document, they need to route PO Invoices to a Complete queue, but the Non-PO Invoices need to be routed to an Auditing queue. After the Auditing queue, the document is routed to Complete.
There are four ways to do this that I can think of:
- Assume the users will always route correctly
Yeah right. Everyone makes mistakes. Even if we only had one mistake, Murphy’s Law says it will be a $1M+ payout that will get picked for audit. - Have separate processing queues
We’re shooting for less queues, so not really an option. - Set up an outbound script on the queue to verify that they are routing the correct document type to the correct place
I’m not sure if it’s possible, but I sure don’t like the idea of dynamically changing the route with an outbound script. It’s entirely possible that this is the intent of the outbound action; someone from Perceptive would need to weigh in on that – but the only thing I’ve ever seen them used for is updating values (like setting a value on a custom property). - Set up an inbound script on the Auditing and Complete queues to route back Doc Types as necessary.
The full requirement is: PO Invoices sent to Auditing should be routed back to where they came from and Non-PO Invoices sent to Complete should be sent back to where they came from UNLESS they came from Auditing. (In case you’re wondering, we’re routing back instead of to the correct place for two reasons 1: teaching tool 2: metrics)
So there’s the rub. In ImageNow 6.5, there is no iScript method to get the previous queue name. There is a method to route back to the previous queue, but I don’t really have the luxury of blindly routing back as it relates to the Complete queue since both the Processing queue and the Audit queue route there. However, there is an iScript method to get the routing history of a workflow item. The basic idea is to work backwards through the history (ignoring the current queue) and look for the last queue that the item was routed from. We can do this by looking for the last “Routed Out” action and examining the Queue Name.
Here is my previousQueue function:
It is expected that you will pass in a INWfItem object. The function will return either a Queue Name as a string or false.
// ------------------------------------------------------------------- // Function: getPreviousQueue // Purpose: Finds the most recent queue that the item was in // excluding current // Args(type): wfitem (INWfItem object) // Returns: Queue Name - String / false - Boolean // ------------------------------------------------------------------- function getPreviousQueue(wfitem) { var ROUTED_OUT_STATE = 5 /* Finished */; var ROUTED_OUT_STATE_DETAIL = 2 /* Routed out */; var queueName = false; if (!wfitem) { printf("no item found\n"); return queueName; } var history = wfitem.getHistory(); //work backwards through history to find last routed out queue for (var i=(history.length-1);i>=0;i--) { if (ROUTED_OUT_STATE == history[i].state && ROUTED_OUT_STATE_DETAIL == history[i].stateDetail) { queueName = history[i].queueName; break; } } return queueName; }
All in all, pretty simple. Here’s how it’s used as an inbound script (Note that I have one script that is used on both queues).
var wfitem = INWfItem.get(currentWfItem.id); var wfCurrentQ = currentWfQueue.name; var msgReason; var Q_Complete = "AP-Complete"; var Q_Complete_DocType = "PO Invoice"; var Q_Audit = "AP Audit"; var Q_Audit_Doctype = "Non-PO Invoice"; var wfStatus = 1; //Idle condition //Verify that a wf item was picked up if (wfitem == null) { printf("Failed to get item. Error: %s\n", getErrMsg()); return; } //Set document based on wf item doc.id = wfitem.objectId; //Get document if (!doc.getInfo()) { printf("Failed to get item. Error: %s\n", getErrMsg()); return; } // snipped bunch of other code msgReason = "Document sent to wrong queue"; //Route back from Audit Queue if (wfCurrentQ == Q_Audit && Q_Audit_DocType != wfitem.docTypeName) { return routeItemBack(wfitem,msgReason); } //Check if queue is AP Complete //we only want to route back if it didn't come from Audit var previousQueue = getPreviousQueue(wfitem); if (wfCurrentQ == Q_Complete && Q_Audit_Doctype == wfitem.docTypeName && previousQueue != Q_Audit) { return routeItemBack(wfitem,msgReason); }
For completeness, here is the routeItemBack function referenced in the script.
// ------------------------------------------------------------------- // Function: routeItemBack // Purpose: Routes an item to previous queue // Args(type): wfitem (INWfItem object), msgReason (string) - routing reason // Note: assumes Idle state of wfStatus set in calling script // Returns: Boolean // ------------------------------------------------------------------- function routeItemBack(wfitem,msgReason) { //Perform Routeback if (wfitem.routeBack(msgReason)) return true; else { printf("Couldn't route item. %s\n", getErrMsg()); wfitem.setState(wfStatus, "Release Hold"); } return false; }
HTH