Maximo Open Forum

 View Only
  • 1.  Would someone be willing to critique my work on an Automation Script?

    Posted 08-08-2024 17:22

    Here's the requirement:

    Our Locations Hierarchy has some 8000 location records.  Of those, a few (~400) are houses or apartments that we rent to employees.

    This may or may not be relevant to the discussion, but we have a single Org and a single Site.

    Years ago, I made added some attributes to a few tables and made a clone of the Person Groups application to help manage the people moving into or out of these locations.  Yes, I'm aware of the Users and Custodians functionality (more on that below), but, trust me, for other reasons, this is the interface we want to use to manage who lives in these houses.  When we create these "housing" Person Groups (indicated simply by a boolean in a custom field called PCC_ISHOUSINGGROUP), we make PERSONGROUP.PERSONGROUP value to be the same as the LOCATIONS.LOCATION value; e.g., for a house at 123 Main Street, the LocationID would be 123MAIN, and the Person Group that is going to contain the tenants is also 123MAIN.

    But now, I ALSO want to use the Users and Custodians functionality; and I don't want to do double-work. So what I want is: as a Person is added to, deleted from, or updated within one of these Person Groups, that the same data would be entered in the LOCATIONUSERCUST table for the corresponding Location.

    Steps toward solution:

    1. Created a relationship on the PERSONGROUPTEAM table:

      Relationship ---- PCC_LOCATIONUSERCUST_LOCATION
      Child Object ---- LOCATIONUSERCUST
      WHERE Clause ---- personid = :resppartygroup and location = :persongroup

    2. Create an Automation Script with Object Launch Point:

      Launch Point ---- LOCATIONUSERCUSTPERSONGROUPSYN
      Description ---- Sync tenants in a Person Group to the LOCATIONUSERCUST table for the matching locations
      Object ---- PERSONGROUPTEAM
      Object Event Condition ---- persongroup in (select persongroup from persongroup where pcc_ishousinggroup = 1)
      Events ---- Save
      Save ---- After Save; checked all three boxes (Add, Update, Delete)
      Script Language ---- python
      Variables:
      groupdefault ---- Launch Point Attribute=GROUPDEFAULT
      persongroup ---- Launch Point Attribute=PERSONGROUP
      resppartygroup ---- Launch Point Attribute=RESPPARTYGROUP

    3. The script itself:
    from psdi.mbo import MboConstants
    from psdi.mbo import MboRemote
    from psdi.mbo import MboSetRemote
    
    if onupdate:
    
        locationusercustSet = mbo.getMboSet("PCC_LOCATIONUSERCUST_LOCATION")
        locationusercustSet.setValue("ISPRIMARY", groupdefault, MboConstants.NOACCESSCHECK | MboConstants.NOVALIDATION)
        locationusercustSet.setValue("ISUSER", 1, MboConstants.NOACCESSCHECK | MboConstants.NOVALIDATION)
        locationusercustSet.save()
        locationusercustSet.close()
    
    if onadd:
    
        locationusercustSet = mbo.getMboSet("PCC_LOCATIONUSERCUST_LOCATION")
        newLocationUserCust = locationusercustSet.add()
        newLocationUserCust.setValue("PERSONID", resppartygroup, MboConstants.NOACCESSCHECK | MboConstants.NOVALIDATION)
        newLocationUserCust.setValue("LOCATION", persongroup, MboConstants.NOACCESSCHECK | MboConstants.NOVALIDATION)
        newLocationUserCust.setValue("ISPRIMARY", groupdefault, MboConstants.NOACCESSCHECK | MboConstants.NOVALIDATION)
        newLocationUserCust.setValue("ISUSER", 1, MboConstants.NOACCESSCHECK | MboConstants.NOVALIDATION)
        newLocationUserCust.setValue("SITEID", "PCC", MboConstants.NOACCESSCHECK | MboConstants.NOVALIDATION)
        locationusercustSet.save()
        locationusercustSet.close()
    
    if ondelete:
    
        locationusercustSet = mbo.getMboSet("PCC_LOCATIONUSERCUST_LOCATION")
        locationusercustSet.deleteAndRemove(MboConstants.NOACCESSCHECK | MboConstants.NOVALIDATION)
        locationusercustSet.save()
        locationusercustSet.close()



    Believe it or not, this is the first time I've had to write a script where some other table is being manipulated.  So far, my onupdate is getting a null pointer exception at Line 8, and my onadd is getting an BMXAA4176E - attribute ORGID does not exist error. (I then tried adding ORGID and SITEID as Literal variables, but that didn't seem to help.) I'm hoping there's someone here that can just look at these few lines of code and critique it.


    TIA,

    Travis


    #Administration
    #Customizations

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


  • 2.  RE: Would someone be willing to critique my work on an Automation Script?

    Posted 25 days ago

    Anyone?



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



  • 3.  RE: Would someone be willing to critique my work on an Automation Script?

    Posted 24 days ago

    You need to get the mbo here.

    locationusercustSet.setValue


    ------------------------------
    Manu Maganti
    EMA, Inc
    ------------------------------



  • 4.  RE: Would someone be willing to critique my work on an Automation Script?

    Posted 24 days ago

    Hi Travis,

    Sorry for the late response to this, I am not sure how I missed it earlier.

    For critiques, here we go:

    You can import multiple classes from a package like so:

    from psdi.mbo import MboSetRemote, MboRemote, MboConstants

    That said, you are not using MboSetRemote or MboRemote in your code so those are not required.

    That brings us to the MboConstants, which for every entry you are skipping validation and read-only rules. There are cases when this is valid and desirable, but as a default position you should be working in a way that respects Maximo's business rules and generally these should not be required.

    As Manu pointed out, you are trying to set a value on the set and not on a specific record. Note that this also applies to your ondelete code.  I am a little unclear on logic, but what I think you want is:

        locationusercustSet = mbo.getMboSet("PCC_LOCATIONUSERCUST_LOCATION")
        locationusercust = locationusercustSet.getMbo(0) # get the first Mbo and I assume only
        # locationusercust = locationusercustSet.moveFirst() # This is another way of doing the same thing.
    
        locationusercust.setValue("ISPRIMARY", groupdefault)

    You may not have included the full script, but it groupdefault is not defined anywhere in the script, so you will need to make sure that is defined somewhere.

    Next, you are saving and closing the set, which is going to cause a problem since you retrieved the set off a relationship from the parent.  In this case you do not need or want to either save or close the set because its lifecycle is going to be handled by the parent Mbo.  When the parent Mbo saves and closes so will the part of the transaction you are adding here.

    Some other things I would consider are checking that the implicit mbo variable is set as a matter of defensive programming. Something like this.

    if 'mbo' in globals():

    Same goes for any other implicit / global variables you are using such as onupdate, ondelete, etc.

    You may also want to consider using a main function as I describe here: https://www.sharptree.io/blog/2021/2021-11-03-js-functions/

    I find this is just a good pattern to follow and helps keep a clear execution path.

    If you have any specific questions, feel free to reach out.

    Regards,

    Jason



    ------------------------------
    Jason VenHuizen
    Sharptree
    ------------------------------



  • 5.  RE: Would someone be willing to critique my work on an Automation Script?

    Posted 24 days ago

    I'm starting to feel like I'm way off. . .

    What I "simply" want is:

    We have lots of Person Groups.

    There's a custom boolean field on the PERSONGROUP table.

    Some of those Person Groups have that boolean field checked (value = 1).  For the Person Groups that have this field checked, it is also already true that the PERSONGROUP.PERSONGROUP (the ID field) will have an exactly-matching LOCATIONS.LOCATION. 

    For those Person Groups where that boolean is checked, then as (primary) Members are added, removed, or modified (really just if whoever is the Group Default changes -- Site Default and Org Default are irrelevant to me here in our single Org/single Site implementation), then I want those changes to be mirrored in the corresponding Location's Users list.

    For example: suppose we have a rental house at 123 Main Street.  I would have created a LOCATIONS record with LOCATIONS.LOCATION = 123MAIN.  I also would create a Person Group with PERSONGROUP.PERSONGROUP = 123MAIN; and on this record, my custom boolean field would be checked (value = 1).

    So, in this Person Group, I add Members:

    --Albert, as the Group Default, Sequence 1

    --Billy, Sequence 2

    --Charlie, Sequence 3

    What I want to happen is that Albert, Billy, and Charlie are added as Users to LOCATIONUSERCUST for Location = 123MAIN; and Albert would be the primary User.

    Later, Albert gets removed from the Person Group.  To allow that to happen, Charlie gets set as the Group Default.  At the same time, Doug is added as a new member of the Person Group.

    So now the same should be seen in the LocationUserCust list for 123MAIN: Charlie is now the primary user, Doug is added as a user, Albert is deleted from the user list.

    My initial attempts were to do this for each record in PERSONGROUPTEAM, but there were times I would get an error stating that someone needed to be the primary.  I presume that's due to that I had changed the Group Default within the Person Group, so two records got updated, so the script should have fired for both of them, and it happened to have processed the one who was no longer the Group Default first, so that on the LocationUserCust side there wouldn't have been anyone marked as the Primary.

    So now I think I need to have this as an Object Launch Point script on Object = PERSONGROUP, not PERSONGROUPTEAM.



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



  • 6.  RE: Would someone be willing to critique my work on an Automation Script?

    Posted 12 days ago
    Edited by Matt F 12 days ago

    Hey Travis,

    How did you make out? @Jason VenHuizen, please correct me if I'm wrong, but I think it might be best for Travis to perhaps leverage a multi-launchpoint script here? Working with Person Groups as you are, I think you'll need to manage both PERSONGROUP and PERSONGROUPTEAM. I do this in one scenario where I have a Action launchpoint script to Create a temporary person group based on a certain launch point, and then I have it delete that Person Group based on another launch point. 

    if launchPoint == "LAUNCHPOINT_NAME":
        do this
    
    elif launchPoint == "LAUNCHPOINT_NAME2":
        do that


    However, as I continue to think about this, if you're never create/deleting the groups themselves, but just managing the people within them, it should be fine to use only PERSONGROUPTEAM if I'm understanding correctly.

    In your script, you can also set the groupdefault to 1 for the first person added. I do this in mine. If I didn't share my example with you already, let me know and I can.



    ------------------------------
    Matt F
    ------------------------------



  • 7.  RE: Would someone be willing to critique my work on an Automation Script?

    Posted 12 days ago

    Haven't figured it out yet, but have had to put it on the back burner for the start of our semester and a couple of other higher-priority things.  But there are a couple of forum members who have offered to help!

    I think it is safe to say that the Location record would already exist.  Then I'd have a Person Group with an ID value the same as the Location ID.  For example, Location = CS2158 already exists.  Then, I'd create a Person Group with ID = CS2158.

    At the time of Person Group creation, I might make the Group, Save it, then add members; or I might create it and add members then Save.  Later, I might add members, remove one or more members, change which member is the Group Default, or delete the Group -- even if it has members in it.  These are all things that Maximo allows for the Person Group.  I want all those changes to be reflected in the corresponding Location's Users list, except for when deleting the Group, I only want the Users purged, but don't delete or change status to the Location itself.



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



  • 8.  RE: Would someone be willing to critique my work on an Automation Script?

    Posted 11 days ago

    Noted!

    I'd be happy to try and tackle it with ya when time frees up for both of us. Feel free to send me a message with your e-mail and we can chat offline.



    ------------------------------
    Matt F
    ------------------------------