Is ImageNow External Messaging Agent the best free bundled product ever? The answer depends on whether you’re using it or not. If you are, then your answer is yes. If you’re not, WHY AREN’T YOU?
ImageNow External Messaging Agent is one of those products that begs for use-cases. Based on the delivered documentation, it’s hard to conceptualize what it can do for you or even how to use it. There is a nice technical paper on the Perceptive support site, but it’s not easy to find. I’m going to give you two actual use cases using Lawson and Accounts Payable.
What is External Messaging agent? Simply put, it is a way to pass information between ImageNow and any external system that can process the messages. External Messaging Agent is table-based unlike other messaging systems like Websphere MQ or JMS. The upside is that if your external system doesn’t support true messaging, you can still use External Messaging Agent (assuming you can read from and write to the tables). There are two tables (IN_EXTERN_MSG:header and IN_EXTERN_MSG_PROP:detail) that contain the messages, and a service on the ImageNow machine monitors the tables. Iscript methods are used to both read and write messages on the ImageNow side, and SQL is used from the external system. Using External Messaging Agent is pretty simple. Write a message from the ImageNow side with your information for the external system to pick up, or read a message written by the external system and do something with it in ImageNow. Once you’ve successfully processed a message, you mark it as complete (or one of the other “processed” statuses – see the documentation for details) and External Messaging Agent cleans out the completed messages based on your config.
Use Case #1 – Messages to ImageNow – Lawson Vendor Merge
The business case is that our keys for AP Invoices in ImageNow are: Vendor, Company, Invoice, PO, Invoice Amount. When we merge vendors in Lawson (because of acquisition or duplicate vendors) Lawson gets updated and the “old” vendor number essentially goes away. However, unless we update ImageNow, we will have a hard time of finding the Invoice in the future and any “Vendor” queries in ImageNow will be incorrect. How we handle this is to have a design studio screen in Lawson where the AP staff can submit a request to merge vendors in ImageNow. The Design Studio screen triggers a Lawson Process Flow that creates the appropriate message records that are then processed in ImageNow by the External Messaging Agent.
Because of the Header-Detail structure, we have to create the header record first, then add the detail, then update the Header to a “Ready to Process” status. As I mentioned, we do this with Lawson Process Flow, but a perl script, PLSQL, etc should all accomplish the same thing.
First we need to generate unique ID’s for the messages. The best way to do this is to use the full date (including time). If you have sequencing turned on for your DB, you might be able to use that as well.
dtDate = new Date();
STRID = 'VendorMerge' + String(dtDate).replace(/ /g,"_");
Here are the SQL statements (my ImageNow is on SQL server, so I’m using their specific date/time functions). Each is executed individually and if any one of them fails, the next is not executed.
--Create Header Record
INSERT INTO IN_EXTERN_MSG (EXTERN_MSG_ID, MSG_TYPE, MSG_NAME, MSG_DIRECTION, MSG_STATUS, START_TIME)
VALUES ( '<!STRID>', 'MERGEVENDORS','MERGEVENDORS', 1, 0, CURRENT_TIMESTAMP)
--Insert Old Vendor ID message property
INSERT INTO IN_EXTERN_MSG_PROP (EXTERN_MSG_ID, PROP_NAME, PROP_TYPE,PROP_VALUE)
VALUES ('<!STRID>', 'OLDVENDOR', 0,'<!OLDVENDOR>')
--Insert New Vendor ID message property
INSERT INTO IN_EXTERN_MSG_PROP (EXTERN_MSG_ID, PROP_NAME, PROP_TYPE,PROP_VALUE)
VALUES ('<!STRID>', 'NEWVENDOR', 0,'<!NEWVENDOR>')
--Update Status of Message Header
SET MSG_STATUS = 1
WHERE EXTERN_MSG_ID = '<!STRID>'
On the ImageNow side, an Iscript processes the messages it receives. In this case, we do a document move on any documents that have the “old” Vendor number to the “new” Vendor number. Apologies in advance, I have a handler function for VSL queries that I’m too lazy to “undo” for the demonstration. If you’re interested, drop me a note and I’ll post the code. VSL is a real bear to deal with and it seems to change from version to version, which is why I prefer my handler function.
var limit = 1000;
var externalMsgObj = getInputPairs();
var strOldVendorID = externalMsgObj["OLDVENDOR"];
var strNewVendorID = externalMsgObj["NEWVENDOR"];
var boolSuccess = true;
var strVSL = "([drawer] = 'Normal_Invoices' OR [drawer] = 'Vendor_Maintenance') AND [folder] = '" + strOldVendorID + "'";
var results = vslQuery(strVSL,limit,false,false);
printf("No Vendor Records found.");
//Check for additional records and log
printf("There are more documents. Not all were selected.");
//Loop through result array
for (i = 0; i < results.length; i++)
//Build keys for new document
var docid = results[i].id;
var tokey = new INKeys(results[i].drawer, strNewVendorID, results[i].tab,
results[i].f3, results[i].f4, results[i].f5, results[i].docTypeName);
//Move document to new key values and append if file with keys exists
if(INDocManager.moveDocument(docid, tokey, "APPEND"))
printf("Old Doc: %s To Doc: %s",docid,docmt.id);
printf("Could not move document: %s\n",getErrMsg());
boolSuccess = false;
//Set message status based on process
Use Case #2 – Messages from ImageNow – Document Notifications
The business case is related to Employee Expenses. Because Employee Expenses are “self-service”, the receipts for the expense are not necessarily recorded when the expense is entered. We do not want to send expenses out for approval until the receipts have been stored in ImageNow. The first step in the Employee Expense approval flow is an Inbasket for receipts. Once the receipts are received by ImageNow, a message is written out. The message is picked up by a separate Process Flow that performs the approval process and allows the expenses to continue in the approval process. I will post separately on how the full Employee Expense process works, but for background, once a linked expense receipt document is routed to the “complete” queue, the following script is triggered.
#define MSG_TYPE "EEX"
#define MSG_NAME "ApproveReceipts"
function main ()
var wfItem = INWfItem.get(currentWfItem.id);
if (wfItem == null)
printf("Could not retrieve workflow information. Error: %s",getErrMsg());
//Set document based on wf item
var doc = new INDocument();
doc.id = wfItem.objectId;
printf("Could not retrieve document information for workflow itemID: %s. Error: %s",wfItem.id,getErrMsg());
printf("Approving Doc: Vendor: %s Comany: %s Invoice: %s DocID: %s",doc.folder, doc.tab, doc.f3, doc.id);
//Build Message Object
var msg = new INExternMsg();
msg.type = MSG_TYPE;
msg.name = MSG_NAME;
msg.direction = ExternMsgDirection.Outbound;
msg.status = ExternMsgStatus.New;
msg.startTime = new Date();
msg.addProperty("DocumentID", ExternMsgPropType.Undefined, doc.id);
msg.addProperty("Vendor", ExternMsgPropType.Undefined, doc.folder);
msg.addProperty("Company", ExternMsgPropType.Undefined, doc.tab);
msg.addProperty("Invoice", ExternMsgPropType.Undefined, doc.f3);
printf("Could not send message for doc: Vendor: %s Comany: %s Invoice: %s DocID: %s. Error is: \n",doc.folder, doc.tab, doc.f3, doc.id,getErrMsg());
On the Process Flow side, we get the messages intended for us, then update the work units. First, the SQL to get the messages. Get the message Header, then get the details of the message.
WHERE MSG_DIRECTION = 2
AND MSG_TYPE = 'EEX'
AND MSG_NAME = 'ApproveReceipts'
AND MSG_STATUS = 1
--Get Message details
SELECT PROP_NAME, PROP_VALUE
WHERE EXTERN_MSG_ID ='<!SQLQueryMsg_EXTERN_MSG_ID>'
Because we get several records back for the details, we parse them like this. If anyone else has any better ideas (for Lawson Process Flow), I’m all ears.
strCompany = addLeadingZeros(SQLQueryProps_PROP_VALUE, 4);
strVendor =addLeadingSpaces(SQLQueryProps_PROP_VALUE, 9, false) ;
strInvoice = SQLQueryProps_PROP_VALUE;
strDocID = SQLQueryProps_PROP_VALUE;
We perform the actions on the workunits and then update the message as necessary. See this post for how to perform Inbasket actions with Process Flow.
SET MSG_STATUS = 4, END_TIME = CURRENT_TIMESTAMP
WHERE EXTERN_MSG_ID = '<!SQLQueryMsg_EXTERN_MSG_ID>'
The possibilities for using ImageNow External Messaging Agent are practically endless which is what makes it so powerful. I hope you’re convinced to start using it.