That is fantastic-looking stuff there!
Re: adding comments to Closed tickets -- that's pretty standard Maximo, can't edit something that's closed; I'm not surprised that that's not allowed. One specific question for you Jade: In this portion of the Script:
#### ACTIONS - COMM LOG ####
if (create_comm): ## Create communication log entry ##
if (not record_closed):
c = varRecord.getMboSet("COMMLOG").add(11L);
else:
c = mbo.getMboSet("OPEN_TICKETS").moveFirst().getMboSet("COMMLOG").add(11L);
Am I reading this right, that if the record is in Closed status, it's going to add the CommLog entry to the first open Ticket it can find?
Re: email from external parties -- at least it's documented! For my situation, I've currently got thousands of college students, more may come or go at any semester change, and I don't have Maximo integrated to any directory system that'll keep this updated for me. Not sure that I'd want to take on managing it manually or semi-manually (e.g. data dump 2 or 3 times per year). But it looks like you've got a way around that in your script. . .interesting!
Re: can't add Communications to Work Orders -- now that's an interesting issue. I've got to assume it's mostly about licensing. So help me play this out (everyone): If I had a technician in the field with a
Work Order, and he needs to communicate/collaborate with the "customer" and I provide a Comm Template for this. That Comm Template is going to need the Object Key Identifier and TicketID, so when the customer responds, the
Ticket (SR) would be updated with their reply. I assume getting the TicketID in the Comm Template can be done via relationship dotted notation, and that the correspondence from both technician and customer would be visible on both the Work Order and SR. However, what if there are many SR's mapped (related) to one Work Order. . .like two roommates turn in a request for the same issue in their room, or two teachers turn in the same request for a classroom? Which "customer" is going to be collaborated with? It seems to me that at that point, the communications need to happen on the Work Order -- but the customer likely isn't authorized/licensed to make updates to Work Orders. How does this work in real life?
------------------------------
Travis Herron
Pensacola Christian College
------------------------------
Original Message:
Sent: 12-01-2021 09:10
From: Jade Warren
Subject: questions on using Email Listener
The object key delimiters must SURROUND the primary key, thus ##keyvaluehere## ... out-of-the-box, the key value must exist in the SUBJECT of the mail item.
We have found ourselves significantly disappointed with the limitations of the listener; it is VERY picky about what it will accept and process, and we have identified at least three business cases that the listener cannot address:
1) Adding communications to closed tickets--one would think that this would be acceptable and useful, but if a ticket is closed, the listener rejects it
2) Processing e-mails from "external parties"--we are a cooperative and so our service desk occasionally handles requests from staff at our 28 member owners...we simply CANNOT be the HR department for 28 independent companies, but unless EVERY incoming e-mail has a corresponding person record in Maximo, the listener will reject
3) Adding communications to WORK ORDERS ... I cannot fathom why IBM doesn't enable this, but the out-of-the-box functionality is such that either the object key matches to a ticket (happy path) or it doesn't and the mail item is rejected (sad path)
Because of this, we have supplemented the listener with several automation scripts to address the business cases above. Obviously these scripts encapsulate our specific requirements, but the overall idea may be useful.
INBOUNDCOMM.SAVE
from psdi.server import MXServer;
from psdi.mbo import MboConstants;
from java.util import HashMap;
## get context
mailid = mbo.getString("MAILID");
obj_key = mbo.getString("OBJECTKEY");
object_name = mbo.getString("OBJECTNAME");
status = mbo.getString("STATUS");
subject = mbo.getString("SUBJECT");
message = mbo.getString("MSGBODY");
sender = mbo.getString("CHANGEBY");
vError = mbo.getString("ERROR");
## flags
found = False;
record_exists = False;
record_closed = False;
create_comm = False;
create_record = False;
proceed = True if mailid == "" else False;
## correct situations where the OBJECTKEY wasn't populated due to poor coding
if (obj_key == ""):
s = subject.find("##");
e = subject.find("##", s + 2);
if (s != -1 and e != -1): ## double delimiters exist...
obj_key = subject[s+2:e];
mbo.setValue("OBJECTKEY", obj_key, 11L);
if (not mbo.isNull("OBJECTKEY")):
tkt_set = mbo.getMboSet("$TKT", "TICKET", "ticketid = '" + obj_key + "'");
tkt = tkt_set.moveFirst();
wo_set = mbo.getMboSet("$WO", "WORKORDER", "wonum = '" + obj_key + "'");
wo = wo_set.moveFirst();
if (tkt != None): ## Check ticket table
object_name = tkt.getString("CLASS");
mbo.setValue("OBJECTNAME", object_name);
record_exists = True;
record_closed = True if tkt.getBoolean("HISTORYFLAG") else False;
UID = tkt.getLong("TICKETUID");
varRecord = tkt;
elif (wo != None):
object_name = wo.getString("WOCLASS");
mbo.setValue("OBJECTNAME", object_name);
record_exists = True;
record_closed = True if wo.getBoolean("HISTORYFLAG") else False;
UID = wo.getLong("WORKORDERID");
varRecord = wo;
else:
record_exists = False;
## start doing record clean-up
if (subject == ""):
subject = "<empty subject>";
mbo.setValue("SUBJECT", subject, 11L);
if (sender == "" or sender == "MAXADMIN" or vError.find("Person does not exist") != -1):
sender == "EXTERNAL";
mbo.setValue("CHANGEBY", "EXTERNAL", 11L);
mbo.setValue("PERSONID", "EXTERNAL", 11L);
if (mailid == "" and status == "NEW" and subject[:13] == "Undeliverable"):
mbo.setValue("STATUS", "COMP_ERR", 11L);
mbo.setValue("ERROR", "Processed by GRE script", 11L);
mbo.setValue("MAILID", mailid + "undeliverable_", 11L);
## Truncate SEND TO field
s = mbo.getString("SENDTO");
if (len(s) > 255):
mbo.setValue("SENDTO", s[:250] + "...", 11L);
## start taking action against the record
if (mailid != "" and status == "WORKFLOW" and vError != ""):
mbo.setValue("STATUS", "COMP_CL", 11L);
mbo.setValue("ERROR", "Processed by GRE script", 11L);
proceed = False;
mbo.setValue("MAILID", mailid + "workflow_", 11L);
if (not record_exists and obj_key != "" and mailid == ""): ## in this case, a bogus object key was fed to the listener
mbo.setValue("STATUS", "ERROR_GRE", 11L);
mbo.setValue("ERROR", "Object key " + obj_key + " does not exist in either the TICKET or WORKORDER table. No action.");
proceed = False;
mbo.setValue("MAILID", mailid + "bad_key_", 11L);
if (proceed and record_exists) and (
(status == "INVALID") or
(status in ("ERROR", "NEW") and mbo.getString("PERSONID") == "EXTERNAL") or
(record_closed) or
(object_name not in ("SR", "PROBLEM"))
):
## in this case, the record exists in Maximo and we DO want a COMM LOG entry
create_comm = True;
if (proceed and not record_exists and ((status == "INVALID") or (status in ("ERROR", "NEW") and mbo.getString("PERSONID") == "EXTERNAL")) and mailid == ""):
create_record = True;
create_comm = True;
#### ACTIONS - CREATE TICKET ####
if (create_record): ## Create ticket ##
ctx = HashMap();
ctx.put("mbo", mbo);
service.invokeScript("LSTNCRSR", ctx);
obj_key = mbo.getString("OBJECTKEY");
varRecord = mbo.getMboSet("GRE_SR").moveFirst();
#### ACTIONS - COMM LOG ####
if (create_comm): ## Create communication log entry ##
if (not record_closed):
c = varRecord.getMboSet("COMMLOG").add(11L);
else:
c = mbo.getMboSet("OPEN_TICKETS").moveFirst().getMboSet("COMMLOG").add(11L);
src_fields = ["CC", "BCC", "SUBJECT", "CHANGEBY", "CREATEDATE", "SENDFROM", "SENDTO", "REPLYTO", "MSGBODY"];
dst_fields = ["CC", "BCC", "SUBJECT", "CREATEBY", "CREATEDATE", "SENDFROM", "SENDTO", "REPLYTO", "MESSAGE"];
c.copyValue(mbo, src_fields, dst_fields, 11L);
c.setValue("INBOUND", 1, 11L);
## Add attachments to newly created comm log entry
aset = mbo.getMboSet("DOCLINKS");
xset = c.getMboSet("DOCLINKS");
a = aset.moveFirst();
while (a != None):
x = xset.add();
fields = ["DOCUMENT", "DOCTYPE", "DOCINFOID"];
x.copyValue(a, fields, fields, 11L);
a = aset.moveNext();
if (vError == ""):
vError = "COMM LOG updated.";
else:
vError = vError + " " + "COMM LOG updated.";
if (record_closed):
c.setValue("OWNERID", UID, 11L);
c.setValue("OWNERTABLE", object_name, 11L);
#### FINAL CLEAN-UP ####
if (create_record == 1 or create_comm == 1):
mbo.setValue("MAILID", mailid + "processed_", 11L);
mbo.setValue("ERROR", vError, 11L);
if (create_record == 1):
mbo.