Maximo Open Forum

 View Only
  • 1.  How to save a record from an Attribute Launchpoint Script

    Posted 11-28-2023 13:53

    I feel like I should know this, but I can't get it to work correctly. . .please help.

    Some background:  This is Maximo 7608.  Our process is that after Work Orders are created, the next thing that I require to happen is choosing an Owner Group.  We use this to narrow it down to the Department we're assigning it to, e.g. Plumbing, Painting, Electrical, HVAC, etc.

    Also part of that process at the beginning of a Work Order's life is that the customer -- the Reported By and On Behalf Of people -- get an email response to at least acknowledge & document that we created the Work Order. (In case you're wondering, we're not using Service Request functionality AT ALL.).

    I have several scripts (because one script is too big to fit!) that fill in other field values (e.g. Supervisor, Work Group, Lead (when possible)) based on the choice of Owner Group.  These have worked well for several years, and utilize an Attribute Launchpoint Script on the OWNERGROUP attribute.

    But I need to do something different in a few occasions.  Sometimes a Work Order comes in that belongs to a Department that doesn't use Maximo.  Sure, we could just redirect the email or phone call, but I like the idea of providing better customer service by taking it in, creating the record, the customer getting the email acknowledgement, and we just handle it amongst ourselves.  We don't have a centralized Help Desk to do this, but I also don't expect our customers to understand our organizational structure.

    So, what I want to happen is, 

    1. Work Order gets created
    2. Owner Group is chosen, but it's a Group that doesn't use Maximo
    3. This should kick off the script, same as it does when the Group does use Maximo
    4. The Script gathers the data from the Work Order, assembles it into an email, sends the email to that Department's Help Desk or point-of-contact, and cancels the Work Order.

    And I think I've got all that working!. . .EXCEPT I get some weird behavior if the Work Order wasn't saved BEFORE making the choice of Owner Group.  I've had it send the email but the Work Order disappears entirely (never saved).  I've had it where it does everything exactly how I want it. . .but to the wrong record.  I've had it to where it failed to retain/save the CAN entry in the WOSTATUS table.  I've had it change the historyflag and end up displaying an error that the Work Order is read-only.  There's probably other fails I've encountered.

    Can it be done?  How do I tell it to save, and have that synchronously interact with the user's session, from an Attribute Launchpoint?

    Code sample below.

    import java
    from java.util import Calendar
    from java.util import Date
    from psdi.server import MXServer
    from psdi.mbo import MboConstants
    from psdi.mbo import MboSet
    from com.ibm.tivoli.maximo.util.mbo import IterableMboSet
    
    now = MXServer.getMXServer().getDate()
    calendar = Calendar.getInstance()
    calendar.add(Calendar.SECOND, 2)
    nowplus2sec = calendar.getTime()
    currentUser = user
    hasLD = mbo.getInt("HASLD")
    wonum = mbo.getString("WONUM")
    woclass = mbo.getString("WOCLASS")
    status = mbo.getString("STATUS")
    woDescription = mbo.getString("DESCRIPTION")
    location = mbo.getString("LOCATION")
    assetnum = mbo.getString("ASSETNUM")
    ownergroup = mbo.getString("OWNERGROUP")
    siteid = mbo.getString("SITEID")
    orgid = mbo.getString("ORGID")
    reportDate = mbo.getDate('REPORTDATE')
    reportedBy = mbo.getString("REPORTEDBY")
    reportedByPhone = mbo.getString("PCCREPORTEDBYPHONE")
    reportedByEmail = mbo.getString("PCCREPORTEDBYEMAIL")
    onBehalfOf = mbo.getString("ONBEHALFOF")
    onBehalfOfPhone = mbo.getString("PCCONBEHALFOFPHONE")
    onBehalfOfEmail = mbo.getString("PCCONBEHALFOFEMAIL")
    
    if interactive:
    
        if onupdate or onadd:
    
            # these are the groups that don't use Maximo
            if ownergroup.startswith('INT-') or ownergroup.startswith('ENV-') or ownergroup.startswith('GR-') or \
                    ownergroup.startswith('SECUR-') or ownergroup.startswith('SCENE-') or ownergroup.startswith('CAB-') or \
                    ownergroup.startswith('AUTO-') or ownergroup.startswith('RP-') or ownergroup.startswith('IT-') or \
                    ownergroup.startswith('CPD-') or ownergroup.startswith('TELE-') or ownergroup == 'VID-LIGHTING':
    
                #this will be the email's subject line
                h_woHead = "<p><b>Work Order transferred out from Maximo</b></p>" \
                           "<p></p>" \
                           "<p>A Maximo user has transferred the following work order to your department:</p>" \
                           "<p></p>" \
                           "<p><b>Work Order Number:  </b>" + wonum + ", " + woDescription + "</p><p></p>"
    
                #this is figuring out some of the content for the email body
                if hasLD == 1:
    
                    LongDescriptionSet = mbo.getMboSet("LONGDESCRIPTION")
                    LongDescriptionSet.setQbeExactMatch("true")
    
                    if LongDescriptionSet.count() > 0:
                        LongDescriptionMbo = LongDescriptionSet.getMbo(0)
                        longDescription = str(LongDescriptionMbo.getString("LDTEXT").encode('utf-8'))
    
                        h_woHead = h_woHead + "<p><b>Details/Additional Comments:  </b>" + longDescription + "</p><p></p>"
    
                    LongDescriptionSet.setFlag(MboConstants.DISCARDABLE, True)
                    LongDescriptionSet.close()
    
                if location is not None:
    
                    LocationSet = mbo.getMboSet("LOCATION")
                    LocationSet.setQbeExactMatch("true")
    
                    if LocationSet.count() > 0:
                        LocationMbo = LocationSet.getMbo(0)
                        locationDescription = str(LocationMbo.getString("DESCRIPTION"))
    
                        h_woHead = h_woHead + "<p><b>For Location:  </b>" + location + ", " + locationDescription + "</p><p></p>"
    
                    LocationSet.setFlag(MboConstants.DISCARDABLE, True)
                    LocationSet.close()
    
                if assetnum is not None:
    
                    AssetSet = mbo.getMboSet("ASSET")
                    AssetSet.setQbeExactMatch("true")
    
                    if AssetSet.count() > 0:
    
                        AssetMbo = AssetSet.getMbo(0)
                        assetDescription = str(AssetMbo.getString("DESCRIPTION"))
                        assetSerialnum = str(AssetMbo.getString("SERIALNUM"))
    
                        if not assetSerialnum is None:
    
                            h_woHead = h_woHead + "<p><b>For Asset:  </b>" + assetnum + ", " + assetDescription + ", Serial #" + assetSerialnum + "</p><p></p>"
    
                        else:
    
                            h_woHead = h_woHead + "<p><b>For Asset:  </b>" + assetnum + ", " + assetDescription + "</p><p></p>"
    
                    AssetSet.setFlag(MboConstants.DISCARDABLE, True)
                    AssetSet.close()
    
                if reportedBy is not None:
                    h_woHead = h_woHead + "<p><b>Reported By:  </b>" + reportedBy + "</p><p></p>"
    
                if reportedByEmail is not None:
                    h_woHead = h_woHead + "<p><b>Email:  </b>" + reportedByEmail + "</p><p></p>"
    
                if reportedByPhone is not None:
                    h_woHead = h_woHead + "<p><b>Phone:  </b>" + reportedByPhone + "</p><p></p>"
    
                if onBehalfOf is not None:
                    h_woHead = h_woHead + "<p><b>On Behalf Of:  </b>" + onBehalfOf + "</p><p></p>"
    
                if onBehalfOfEmail is not None:
                    h_woHead = h_woHead + "<p><b>Email:  </b>" + onBehalfOfEmail + "</p><p></p>"
    
                if onBehalfOfPhone is not None:
                    h_woHead = h_woHead + "<p><b>Phone:  </b>" + onBehalfOfPhone + "</p><p></p>"
    
                if reportDate is not None:
                    h_woHead = h_woHead + "<p><b>Request Date:  </b>" + str(reportDate) + "</p><p></p>"
    
                LastWorkLogSet = mbo.getMboSet("PCC_MOST_RECENT_WORKLOG")
                LastWorkLogSet.setQbeExactMatch("true")
                if LastWorkLogSet.count() > 0:
                    LastWorkLogMbo = LastWorkLogSet.getMbo(0)
                    worklogDescription = str(LastWorkLogMbo.getString("DESCRIPTION"))
                    worklogCreateBy = str(LastWorkLogMbo.getString("CREATEBY"))
                    worklogHasLD = LastWorkLogMbo.getInt("HASLD")
    
                    if worklogHasLD == 0:
                        h_woHead = h_woHead + "<p></p><p>Additional Information from Technician:</p>" \
                                              "<p><b>Created By:  </b>" + worklogCreateBy + "</p>" \
                                              "<p><b>Summary:  </b>" + worklogDescription + "</p><p></p>"
    
                    else:  # worklogHasLD == 1:
                        workLogLongDescriptionSet = LastWorkLogMbo.getMboSet("PCC_LONGDESCRIPTION")
                        workLogLongDescriptionSet.setQbeExactMatch("true")
                        if workLogLongDescriptionSet.count() > 0:
                            workLogLongDescriptionMbo = workLogLongDescriptionSet.getMbo(0)
                            workLogLongDescription = str(workLogLongDescriptionMbo.getString("LDTEXT").encode('utf-8'))
                            h_woHead = h_woHead + "<p></p><p>Additional Information from Technician:</p>" \
                                                  "<p><b>Created By:  </b>" + worklogCreateBy + "</p>" \
                                                  "<p><b>Summary:  </b>" + worklogDescription + "</p>" \
                                                  "<p><b>Additional Details:  </b>" + workLogLongDescription + "</p>"
    
                        workLogLongDescriptionSet.setFlag(MboConstants.DISCARDABLE, True) 
                        workLogLongDescriptionSet.close()
    
                LastWorkLogSet.setFlag(MboConstants.DISCARDABLE, True)
                LastWorkLogSet.close()
    
                h_woHead = h_woHead + "<p>Please forward this information to someone within your department as needed.</p><p></p>"
    
                b_sendComm = (False)
    
    
                # sendComm function
                def sendComm(s_templateId, s_subject, h_message):
                    whereclause = "TEMPLATEID = '" + str(s_templateId) + "'"
                    ctMboSet = mbo.getMboSet("$commtemp", "COMMTEMPLATE", whereclause)
                    ctMboSet.setQbeExactMatch("true")
                    ctMbo = ctMboSet.getMbo(0)
                    if (ctMbo is not None):
                        ctMbo.setValue("SUBJECT", s_subject, MboConstants.NOACCESSCHECK | MboConstants.NOVALIDATION_AND_NOACTION)
                        ctMbo.setValue("MESSAGE", h_message, MboConstants.NOACCESSCHECK | MboConstants.NOVALIDATION_AND_NOACTION)
                        ctMbo.sendMessage(mbo)
                        ctMboSet.setFlag(MboConstants.DISCARDABLE, True)
                        ctMboSet.close()
    
                    else:
                        ctMboSet.setFlag(MboConstants.DISCARDABLE, True)
                        ctMboSet.close()
    
                    return
    
                # the IF condition here is intended to cover BOTH if the Work Order has, or has not, been saved; and the chosen Owner Group is for our Interiors Dept.
                # NEW is a custom status we made as a synonym of WAPPR, and logically comes before WAPPR in our process flow.
                if ((ownergroup_previous is None or ownergroup_previous == '') or (status == 'NEW' and not
                (ownergroup_previous is None or ownergroup_previous == ''))) and ownergroup.startswith('INT-'):
    
                    b_sendComm = True
                    s_templateId = "WOTRNSFRINTERIOR"
                    s_subject = "Work Order " + wonum + " Transferred from Maximo to Interiors Department"
                    # Build HTML for message
                    h_message = h_woHead
                    sendComm(s_templateId, s_subject, h_message)
    
                    warngroup = 'workorder'
                    warnkey = 'WOCancelInBackground'
    
                    # this seems to be where it's failing; it won't Cancel AND Save properly, especially if there was no previous Save done yet.
                    mbo.changeStatus("CAN", now, "transferred to Interiors", MboConstants.NOACCESSCHECK | MboConstants.NOVALIDATION)
    
                elif not (ownergroup_previous is None or ownergroup_previous == '') and ownergroup.startswith('INT-'):
    
                    # I don't allow users to transfer PMs.  We planned for it to be assigned to them. If we need to change that, then I need to
                    # be aware of it and fix the source PM record.
                    if pmNum is not None or (parentWO is not None and parentPMNum is not None):
    
                        errorgroup = 'workorder'
                        errorkey = 'DoNotTransferPM'
    
                    else:
    
                        #if this Work Order has been worked on by someone already, I expect them to document what they've already done, 
                        #and I give them 10 minutes to finish writing the Work Note and choose the new Owner Group they want to transfer it to
                        workLogSql = " recordkey = '" + wonum + "' and class = '" + woclass + "' and siteid " \
                                 "= '" + siteid + "' and createby = '" + currentUser + "' and createdate > (getdate() - 0.006944)"  # arbitrarily ~ 10 minutes ago
                        workLogSet = mbo.getMboSet("CUSTOMWOWORKLOG", "WORKLOG", workLogSql)
    
                        if workLogSet.count() <= 0:
    
                            workLogSet.setFlag(MboConstants.DISCARDABLE, True)
                            workLogSet.close()
                            errorgroup = 'workorder'
                            errorkey = 'MakeALogEntry2'
    
                        else:
    
                            b_sendComm = True
                            s_templateId = "WOTRNSFRINTERIOR"
                            s_subject = "Work Order " + wonum + " Transferred from Maximo to Interiors Department"
                            # Build HTML for message
                            h_message = h_woHead
                            sendComm(s_templateId, s_subject, h_message)
    
                            workLogSet.setFlag(MboConstants.DISCARDABLE, True)
                            workLogSet.close()
    
                            if status == 'WSCH' or status == 'APPR' or status == 'WMATL' or status == 'INPRG' or status == 'PAUSED':
                                
                                # FNOTDONE is a synonym of INPRG; a later Escalation action will move it to NOTDONE which is a synonym of COMP.
                                # We use this status instead of CAN so as to allow the recording of parts and labor against the Work Order.
                                mbo.changeStatus("FNOTDONE", now, "transferred to Interiors",  MboConstants.NOACCESSCHECK | MboConstants.NOVALIDATION)
    
                            else:
    
                                mbo.changeStatus("APPR", now, "required for FNOTDONE", MboConstants.NOACCESSCHECK | MboConstants.NOVALIDATION)
                                mbo.changeStatus("FNOTDONE", nowplus2sec, "transferred to Interiors", MboConstants.NOACCESSCHECK | MboConstants.NOVALIDATION)
    
                        mbo.setValueNull('lead')
                        mbo.setValueNull('persongroup')
                        mbo.setValueNull('supervisor')
    
    # snipping here; the script IRL repeats all the above with different values for each of the other non-Maximo departments.

    #Administration
    #Customizations
    #WorkManagement

    ------------------------------
    Travis Herron
    Pensacola Christian College
    ------------------------------


  • 2.  RE: How to save a record from an Attribute Launchpoint Script

    Posted 11-28-2023 18:31

    I recommend changing your launch point to the Object and after the save event.

    If you want to test if your record needs to be saved, you can use mbo.toBeSaved() and to force a save mbo.getThisMboSet().save(), which I don't recommend to do as this will trigger a save on all WOs pending in your MboSet. In most cases, this is what causes the message "This record was updated by another user."



    ------------------------------
    Maycon Belfort
    BPD Zenith
    ------------------------------