Original Message:
Sent: 03-18-2025 08:35
From: Steven Shull
Subject: Cannot retrieve data from Interface Table, looking for solution
I don't need to know all the details around it but help me understand at a high level the purpose of the X_BILLING object. Every attribute you are setting appears to be coming from the invoice or in the case of the TRANSID, X_MXINVOICE. That makes the entire object seem redundant. IE what do you NOT have in X_MXINVOICE (since that can contain all the attributes from invoice you need along with containing the TRANSID you need) that you need in X_BILLING?
You can't use an escalation on the IFACE table X_MXINVOICE because there is no unique ID on the table.
You could write a cron task automation script that looks for records that exist in X_MXINVOICE but don't exist in X_BILLING but again, if these are both IFACE tables, it's possible for them to be recreated and all messages get lost.
You can't create an async job (think our change status in background functionality) because you have no way of knowing when the outbound message will be published to the IFACE table. This is normally a sequential queue that gets processed via a cron task. If there are any errors in a sequential queue, nothing will get written to the IFACE table until the error is handled (either fixed and reprocessed or deleted). Your message could be written to the IFACE table in 30 seconds, 30 minutes, 30 hours, 30 days, etc. And it could technically never be written if someone deleted it from the queue for some reason.
The easiest path is trying to make the entry in X_MXINVOICE work without the X_BILLING object entirely. You could try and add logic in the publish channel processing to insert the X_BILLING record but there has to be something unique about the X_BILLING object that we need to capture and I'm not understanding what it is. If it depends on live invoice data from when the transaction was saved, that's not a guarantee when the publish channel fires because again, it could be any amount of time between the save and when it gets processed from the queue. Which gets back to your best bet is the X_MXINVOICE object exclusively.
------------------------------
Steven Shull
IBM
Original Message:
Sent: 03-18-2025 00:13
From: Johann Wunder
Subject: Cannot retrieve data from Interface Table, looking for solution
Hello Steven, Thank you for your response.
I am just testing X_MXINVOICE and X_BILLING at the moment.
X_MXINVOICE and X_BILLING are empty tables. I use two "test" invoices "TEST" and "TEST1".
I set TRANSID in X_BILLING to 1 or 0 to identify if I am able to get the new record that has been added into X_MXINVOICE after approving one of the test invoices.
What I am trying to accomplish is this:
After the user approves an invoice, Maximo automatically adds record(s) into X_MXINVOICE associated with the approved invoice, these record(s) all have the same TRANSID - identifier that lets us know that these newly added record(s) are associated with the recently approved invoice.
I also need Maximo to add one record into X_BILLING using information from the approved invoice and from the new record in X_MXINVOICE associated with the approved invoice
from the approved invoice I need the following:
newbillingMbo.setValue("APPROVALNUM", invoice.getString("APPROVALNUM"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("BASETOTALCOST", invoice.getDouble("BASETOTALCOST"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("CHANGEBY", invoice.getString("CHANGEBY"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("CHANGEDATE", invoice.getDate("CHANGEDATE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("DESCRIPTION", invoice.getString("DESCRIPTION"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("DOCUMENTTYPE", invoice.getString("DOCUMENTTYPE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("DUEDATE", invoice.getDate("DUEDATE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("ENTERBY", invoice.getString("ENTERBY"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("ENTERDATE", invoice.getDate("ENTERDATE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("GLPOSTDATE", invoice.getDate("GLPOSTDATE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("HASLD", invoice.getInt("HASLD"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("HISTORYFLAG", invoice.getInt("HISTORYFLAG"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("INVOICEDATE", invoice.getDate("INVOICEDATE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("INVOICEID", invoice.getInt("INVOICEID"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("INVOICENUM", invoice.getString("INVOICENUM"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("PAYMENTTERMS", invoice.getString("PAYMENTTERMS"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("PONUM", invoice.getString("PONUM"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("POSITEID", invoice.getString("POSITEID"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("SITEID", invoice.getString("SITEID"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("STATUS", invoice.getString("STATUS"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("STATUSDATE", invoice.getDate("STATUSDATE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("TOTALCOST", invoice.getDouble("TOTALCOST"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("VENDOR", invoice.getString("VENDOR"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("VENDORINVOICENUM", invoice.getString("VENDORINVOICENUM"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("X_BILLINGNUMBER", invoice.getString("INVOICENUM"), MboConstants.NOACCESSCHECK)
from one of the new added records in X_MXINVOICE associated with the approved invoice, i need the TRANSID associated with these X_MXINVOICE records to set the new entry in X_BILLING with the same TRANSID:
newbillingMbo.setValue("TRANSID", mxinvoiceMbo.getInt("TRANSID"), MboConstants.NOACCESSCHECK)
The idea here is to make sure the new X_BILLING entry and the new X_MXINVOICE entries all have the same transid since they are all created and added into thier tables when an invoice is approved.
My initial approach was to use an automation script with an object launch point (OBJECT: INVOICE, EVENT: Save, when Invoice MBO is updated, AFTER COMMIT)
from psdi.server import MXServer
from psdi.mbo import MboConstants
mxServer = MXServer.getMXServer()
userInfo = mbo.getUserInfo()
siteid = mbo.getString("SITEID")
status = mbo.getString("STATUS")
if siteid == 'CK005' and status == 'APPR':
invoice = mbo
billingSet = mxServer.getMboSet("X_BILLING", userInfo)
billingSet.reset()
newbillingMbo = billingSet.add(MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("APPROVALNUM", invoice.getString("APPROVALNUM"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("BASETOTALCOST", invoice.getDouble("BASETOTALCOST"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("CHANGEBY", invoice.getString("CHANGEBY"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("CHANGEDATE", invoice.getDate("CHANGEDATE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("DESCRIPTION", invoice.getString("DESCRIPTION"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("DOCUMENTTYPE", invoice.getString("DOCUMENTTYPE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("DUEDATE", invoice.getDate("DUEDATE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("ENTERBY", invoice.getString("ENTERBY"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("ENTERDATE", invoice.getDate("ENTERDATE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("GLPOSTDATE", invoice.getDate("GLPOSTDATE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("HASLD", invoice.getInt("HASLD"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("HISTORYFLAG", invoice.getInt("HISTORYFLAG"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("INVOICEDATE", invoice.getDate("INVOICEDATE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("INVOICEID", invoice.getInt("INVOICEID"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("INVOICENUM", invoice.getString("INVOICENUM"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("PAYMENTTERMS", invoice.getString("PAYMENTTERMS"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("PONUM", invoice.getString("PONUM"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("POSITEID", invoice.getString("POSITEID"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("SITEID", invoice.getString("SITEID"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("STATUS", invoice.getString("STATUS"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("STATUSDATE", invoice.getDate("STATUSDATE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("TOTALCOST", invoice.getDouble("TOTALCOST"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("VENDOR", invoice.getString("VENDOR"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("VENDORINVOICENUM", invoice.getString("VENDORINVOICENUM"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("X_BILLINGNUMBER", invoice.getString("INVOICENUM"), MboConstants.NOACCESSCHECK)
mxinvoiceSet = mxServer.getMboSet("X_MXINVOICE", userInfo)
mxinvoiceSet.setWhere("SITEID = '{}' AND INVOICENUM = '{}' AND STATUSDATE = '{}'".format(siteid, mbo.getString("INVOICENUM"), mbo.getDate("STATUSDATE"))
mxinvoiceSet.reset()
mxinvoiceMbo = mxinvoiceSet.getMbo(0)
newbillingMbo.setValue("TRANSID", mxinvoiceMbo.getInt("TRANSID"), MboConstants.NOACCESSCHECK)
billingSet.save(MboConstants.NOACCESSCHECK)
looking at your response and from my testing, I am not getting any records in X_MXINVOICE becuase the script is executing before maximo adds the new records into X_MXINOVICE. (I guess this is the queue you mentioned).
Becuase of this i also tried to use similar automation script with an object launch point (object: x_mxinvoice, executes when a new x_mxinvoice record is added into x_mxinvoice, after save or after commit)
from psdi.server import MXServer
from psdi.mbo import MboConstants
mxServer = MXServer.getMXServer()
userInfo = mbo.getUserInfo()
siteid = mbo.getString("SITEID")
if siteid == <SITEIDGOESHERE>:
billingSet = mxServer.getMboSet("X_BILLING", userInfo)
billingSet.reset()
newbillingMbo = billingSet.add(MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("TRANSID", mbo.getInt("TRANSID"), MboConstants.NOACCESSCHECK)
invoiceSet = mxServer.getMboSet("X_MXINVOICE", userInfo)
invoiceSet.setWhere("SITEID = '{}' AND INVOICENUM = '{}' AND STATUSDATE = '{}'".format(siteid, mbo.getString("INVOICENUM"), mbo.getDate("STATUSDATE"))
invoiceSet.reset()
invoice = invoiceSet.getMbo(0)
newbillingMbo.setValue("APPROVALNUM", invoice.getString("APPROVALNUM"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("BASETOTALCOST", invoice.getDouble("BASETOTALCOST"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("CHANGEBY", invoice.getString("CHANGEBY"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("CHANGEDATE", invoice.getDate("CHANGEDATE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("DESCRIPTION", invoice.getString("DESCRIPTION"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("DOCUMENTTYPE", invoice.getString("DOCUMENTTYPE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("DUEDATE", invoice.getDate("DUEDATE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("ENTERBY", invoice.getString("ENTERBY"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("ENTERDATE", invoice.getDate("ENTERDATE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("GLPOSTDATE", invoice.getDate("GLPOSTDATE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("HASLD", invoice.getInt("HASLD"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("HISTORYFLAG", invoice.getInt("HISTORYFLAG"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("INVOICEDATE", invoice.getDate("INVOICEDATE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("INVOICEID", invoice.getInt("INVOICEID"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("INVOICENUM", invoice.getString("INVOICENUM"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("PAYMENTTERMS", invoice.getString("PAYMENTTERMS"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("PONUM", invoice.getString("PONUM"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("POSITEID", invoice.getString("POSITEID"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("SITEID", invoice.getString("SITEID"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("STATUS", invoice.getString("STATUS"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("STATUSDATE", invoice.getDate("STATUSDATE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("TOTALCOST", invoice.getDouble("TOTALCOST"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("VENDOR", invoice.getString("VENDOR"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("VENDORINVOICENUM", invoice.getString("VENDORINVOICENUM"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("X_BILLINGNUMBER", invoice.getString("INVOICENUM"), MboConstants.NOACCESSCHECK)
billingSet.save(MboConstants.NOACCESSCHECK)
but this wouldnt work either. so what would be my best approach to get data from both the approved invoice and x_mxinvoice entrys after the user approves an invoice. would i need a script for integration using publish channel? instead of a script with object launch point?
------------------------------
Johann Wunder
King & George LLC
Original Message:
Sent: 03-17-2025 21:06
From: Steven Shull
Subject: Cannot retrieve data from Interface Table, looking for solution
Outbound messages are sent via publish channels. Publish channels are triggered during the save of the object but it writes to a JMS (or Kafka) queue that then later gets processed to send to the endpoint (HTTP, file, IFACE table, etc.) defined on the publish channel. You won't have the message available in the IFACE table until after it's processed. These are typically via sequential queue that gets processed as a cron task. And any errors that occur can block the queue for extended periods of time.
IFACE tables are populated via SQL insert statements rather than MBOs so it won't trigger automation script events.
I'm not understanding what you're trying to accomplish exactly here to help propose a recommended solution. Is X_BILLING another IFACETABLE? It looks like the only thing you are setting based on X_MXINVOICE is you're setting TRANSID on X_BILLING to 1 or 0 based on whether you have existing messages in the IFACE table. Beyond the technical challenges, you need to be careful because IFACE tables will be recreated when schemas change and none of your records will exist in the IFACE table when it is recreated. That means Monday invoice 1001 could find a record in the X_MXINVOICE table and Tuesday after the IFACE table is recreated invoice 1001 could not have a record in the X_MXINVOICE table. That could lead to undesired behavior.
I'd consider tracking something on the invoice record if you're only trying to track whether an invoice has been sent.
------------------------------
Steven Shull
IBM
Original Message:
Sent: 03-17-2025 11:39
From: Johann Wunder
Subject: Cannot retrieve data from Interface Table, looking for solution
x_mxinvoice database configuration setup:
- Object: x_mxinvoice
- Service: Mic (MICSERVICE)
x_billing database configuration setup:
- Object: x_billing
- Service: CUSTAPP (Custom Application Service
After an invoice is approved, Maximo automatically adds records into the Interface Table called X_MXINCVOICE.
I created an automation script with an object launch point (object: invoice, executes when invoice is update, after save) where I am trying to copy data from the approved invoice into a custom table named x_billing and data from the newly added records in x_mxinvoice.
The script only retrieves data from the approved invoice but does not retrieve any data from x_mxinvoice.
I have also tried using a different automation script with an object launch point (object x_mxinvoice, executes when a new x_mxinvoice record is added into x_mxinvoice, after save or after commit) to get the data after a new record is added into x_mxinvoice table and still nothing is retrieved.
Using both methods, I can still not retrieve any record from x_mxinvoice. Even though, when I run my query in sql server to see if there are records in x_mxinvoice, the newly added records are in the table.
Its like the scripts cannot access data from x_mxinvoice after the invoice is approved because the scripts are executing before maximo creates and adds records into x_mxinvoice.
Do you know what the issue might be? If so, what would be a possible solution? Below is both automation scripts (NOTE, both are not active at the same time. I tested both individually)
automation script with an object launch point (object: invoice, executes when invoice is update, after save):
from psdi.server import MXServer
from psdi.mbo import MboConstants
mxServer = MXServer.getMXServer()
userInfo = mbo.getUserInfo()
siteid = mbo.getString("SITEID")
status = mbo.getString("STATUS")
if siteid == <SITEIDGOESHERE> and status == 'APPR':
invoice = mbo
mxinvoiceSet = mxServer.getMboSet("X_MXINVOICE", userInfo)
mxinvoiceSet.setWhere("SITEID = '{}' AND INVOICENUM = '{}'".format(siteid, mbo.getString("INVOICENUM")))
mxinvoiceSet.reset()
mxinvoiceMbo = mxinvoiceSet.getMbo(0)
billingSet = mxServer.getMboSet("X_BILLING", userInfo)
billingSet.setWhere("SITEID = '{}' AND INVOICENUM = '{}'".format(siteid, mbo.getString("INVOICENUM")))
billingSet.reset()
newbillingMbo = billingSet.add(MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("APPROVALNUM", invoice.getString("APPROVALNUM"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("BASETOTALCOST", invoice.getDouble("BASETOTALCOST"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("CHANGEBY", invoice.getString("CHANGEBY"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("CHANGEDATE", invoice.getDate("CHANGEDATE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("DESCRIPTION", invoice.getString("DESCRIPTION"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("DOCUMENTTYPE", invoice.getString("DOCUMENTTYPE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("DUEDATE", invoice.getDate("DUEDATE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("ENTERBY", invoice.getString("ENTERBY"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("ENTERDATE", invoice.getDate("ENTERDATE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("GLPOSTDATE", invoice.getDate("GLPOSTDATE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("HASLD", invoice.getInt("HASLD"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("HISTORYFLAG", invoice.getInt("HISTORYFLAG"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("INVOICEDATE", invoice.getDate("INVOICEDATE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("INVOICEID", invoice.getInt("INVOICEID"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("INVOICENUM", invoice.getString("INVOICENUM"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("PAYMENTTERMS", invoice.getString("PAYMENTTERMS"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("PONUM", invoice.getString("PONUM"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("POSITEID", invoice.getString("POSITEID"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("SITEID", invoice.getString("SITEID"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("STATUS", invoice.getString("STATUS"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("STATUSDATE", invoice.getDate("STATUSDATE"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("TOTALCOST", invoice.getDouble("TOTALCOST"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("VENDOR", invoice.getString("VENDOR"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("VENDORINVOICENUM", invoice.getString("VENDORINVOICENUM"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("X_BILLINGNUMBER", invoice.getString("INVOICENUM"), MboConstants.NOACCESSCHECK)
# test to see if x_mxinvoice record exists
if mxinvoiceMbo is not None:
newbillingMbo.setValue("TRANSID", 1, MboConstants.NOACCESSCHECK)
else:
newbillingMbo.setValue("TRANSID", 0, MboConstants.NOACCESSCHECK)
billingSet.save(MboConstants.NOACCESSCHECK)
automation script with an object launch point (object x_mxinvoice, executes when a new x_mxinvoice record is added into x_mxinvoice, after save or after commit)
from psdi.server import MXServer
from psdi.mbo import MboConstants
mxServer = MXServer.getMXServer()
userInfo = mbo.getUserInfo()
siteid = mbo.getString("SITEID")
if siteid == <SITEIDGOESHERE>:
billingSet = mxServer.getMboSet("X_BILLING", userInfo)
billingSet.setWhere("SITEID = '{}' AND INVOICENUM = '{}'".format(siteid, mbo.getString("INVOICENUM")))
billingSet.reset()
billing = billingSet.getMbo(0)
if billing is None:
newbillingMbo = billingSet.add(MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("INVOICENUM", mbo.getString("INVOICENUM"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("PONUM", mbo.getString("PONUM"), MboConstants.NOACCESSCHECK)
newbillingMbo.setValue("X_BILLINGNUMBER", mbo.getString("INVOICENUM"), MboConstants.NOACCESSCHECK)
billingSet.save(MboConstants.NOACCESSCHECK)
#Administration
#Customizations
#MaximoApplicationSuite
------------------------------
Johann Wunder
King & George LLC
------------------------------