1

Updated:

In Maximo 7.6.1.1, I have custom fields in these tables:

  • WORKORDER: X & Y
  • ASSET: X & Y
  • LOCATIONS: X & Y

I would like to populate the X & Y fields in WORKORDER using the logic below.

(The logic is similar--but slightly different--to the logic in the auto-create spatial search.)

At a high level:

  • If exists, use WOSERVICEADDRESS.LATITUDEY & LONGITUDEX
  • Else, use ASSET.X & Y
  • Else, use LOCATIONS.X & Y

Proposed pseudo-code:

Scenario: A user is creating a new work order or editing an existing work order.

When the WO is saved:

01    1.  In the related WOSERVICEADDRESS table:
02
03        if WOSERVICEADDRESS.LATITUDEY gets edited:
04
05            if WOSERVICEADDRESS.LATITUDEY is not null:
06                then update WORKORDER.X & Y with WOSERVICEADDRESS.LATITUDEY & LONGITUDEX
07
08           #Handle the scenario where the WOSERVICEADDRESS.LATITUDEY is changed to null:
09
10            elseif WORKORDER.ASSETNUM is not null:
11                then update WORKORDER.X & Y with the related values in ASSET.X & Y
12
13            elseif WORKORDER.LOCATION is not null:
14                then update WORKORDER.X & Y with the related values in LOCATIONS.X & Y
15    
16    2.  In the WORKORDER table: 
17
18        (if WORKORDER.ASSETNUM gets edited or if WORKORDER.LOCATION gets edited) and if WOSERVICEADDRESS.LATITUDEY is null
19
20        then:
21            if WORKORDER.ASSETNUM is not null:
22            then update WORKORDER.X & Y with the related values in ASSET.X & Y
23
24            elseif WORKORDER.LOCATION is not null:
25            then update WORKORDER.X & Y with the related values in LOCATIONS.X & Y.

Is there a way to do this Jython Automation script (without slowing down the workorder application)?

(Keyword: Maximo Spatial)

User1974
  • 276
  • 1
  • 17
  • 63
  • 1
    This seems very similar to your question here: https://stackoverflow.com/questions/57582369/maximo-use-script-to-update-work-order-when-a-related-table-is-updated. The only difference would be to create an "example" that is your work order situation. – Dex Dec 16 '19 at 13:13

3 Answers3

2

For #2 and #3, you can use something like this: - Create an autoscript on Work Order Object - Save event - Create two variables: assetnum and location and bind them to the assetnum and location fields - Use the "var_modified" flag to determine if a variable is updated:

x = ""
y = ""

if assetnum_modified or location_modified:
  if location:
    x = mbo.getString("ASSET.LONGITUDEX")
    y = mbo.getString("ASSET.LATITUDEY")
  elif assetnum:
    x = mbo.getString("ASSET.LONGITUDEX")
    y = mbo.getString("ASSET.LATITUDEY")

woaddr = mbo.getMboSet("SERVICEADDRESS").getMbo(0)
if woaddr.getString("LONGITUDEX"):
  x = woaddr.getString("LONGITUDEX")
  y = woaddr.getString("LATITUDEY")

mbo.setValue("LONGITUDEX", x)
mbo.setValue("LATITUDEY", y)

For WO Service Address, it is a bit tricky because it is a different table. If performance is a huge problem with your system, the solution could be to create a separate script on the WOSERVICEADDRESS object and have logic to handle "Add/Update" and "Delete" event according to your rule

Tran Viet
  • 61
  • 3
  • 3
    A couple of warnings with this (other than the use of the ASSET relationship in the location section of the code). If assetnum was modified and location was not, but location is filled in, it would still pull over the location's x and y, not the assets. This may be desired, as your stated goal creates some funny behavior that depends on which field was filled in most recently. The bigger problem though is that this will always set your x and y fields, even if nothing has changed. In fact, if the location and asset did not change and the service address is empty, this would *clear* your fields. – Dex Dec 17 '19 at 13:20
  • 2
    I strongly discourage attribute-bound explicit variables (i.e. on the Variables tab) because they increase set-up and tear-down performance costs for running your script. In this case, I would use `mbo.getString("ASSETNUM") != mbo.getMboValue("ASSETNUM").getInitialValue().asString()` to see if ASSETNUM changed. – Preacher Dec 18 '19 at 18:31
  • 1
    Especially in high-traffic objects, like WORKORDER, I advocate not having your object launch point fire if there is nothing to do. In this case, I would have conditions like this in my Object Event Condition: `:assetnum != :$old_assetnum` – Preacher Dec 18 '19 at 18:37
  • Doesn't that also have a decent amount of setup and teardown, to run that query? – Dex Dec 19 '19 at 00:30
  • @Dex, Are you referring to my attribute-bound explicit variables comment, or to my high-traffic objects comment? – Preacher Dec 19 '19 at 15:10
  • 2
    @Dex Assuming you were talking about my high-traffic objects comment, the setup, execution, teardown cost of running a properly formed Object Event Condition is usually less than the setup, execution, teardown costs of running the script that ends up doing nothing, in my experience. To a user dealing with one record, the difference may not be noticeable, but the impact to PMWOGEN and possibly the List tab could be. If I can say so without sounding biased, the query only has to do a little string substitution, then use a connection from the pool to run a query against DUMMY_TABLE. – Preacher Dec 19 '19 at 23:05
  • 1
    Yeah, I was referring to the object event condition (the only query listed so far). Maximo's query code isn't that simple, so I find it hard to believe that it is relatively cheap compared to a do-nothing script, but I'll take your word for it. I haven't done any kind of testing or examination of that setup. – Dex Dec 20 '19 at 02:40
  • Interesting discussion on script optimisation. I'd add a null check on `woaddr` or check for `isEmpty()` on the WOSERVICEADDRESS set. – JPTremblay Dec 20 '19 at 14:20
1

Going with the idea that you want the solution pieced together more explicitly from the answer in the other question, the other answer here, the comments from the other answer here, and the updated requirements, I've created an amalgamation of all that. I have not tested this at all, some relationships, event conditions or exact hops through the API may be incorrect. This also assumes that if either the X or Y are filled in at a spot that takes precedence but the other isn't, that you still want to use filled in value and the blank value from that spot.

Because these are on two different objects, there will be a slight inefficiency handling updates on the service address because that needs to be handled on its own. First, create an automation script launch point on the SERVICEADDRESS object. Set it to run on "add" and "update" and to do those "before save". Add an object event condition of :longitudex != :$old_longitudex or :latitudey != :$old_latitudey. Make that script the following:

# Assume this change is being made from the UI, so the work order will be the owner of the
# SERVICEADDRESS object. This way your modifications can be reflected on screen and not cause a
# refetch error if the user also modified work order in this same transaction.
wo = mbo.getOwner()
if wo is not None:
    wo.setValue("X", mbo.getString("LONGITUDEX"))
    wo.setValue("Y", mbo.getString("LATITUDEY"))

This takes care of updating the workorder's fields with the service address fields if they are changed. They will always overwrite what is on the work order so they will take precedent, as your requirements dictate. If someone clears these values and then saves, this would try to clear the values on the work order too, which may not be desired if there actually is an asset or location x and y. You can't really handle that without removing the event condition on the next script, which you don't really want to do if you want to keep it from running as often as you say you do.

Second, create an automation script launch point on the WORKORDER object. Set it to run on "add" and "update" and to do those "before save". Add an object event condition of :asset != :$old_asset or :location != :$old_location. Make that script the following:

saddr = mbo.getMboSet("SERVICEADDRESS").getMbo(0)
if saddr is None or (saddr.getString("LONGITUDEX") == "" and saddr.getString("LATITUDEY") == ""):
    asset = mbo.getMboSet("ASSET")
    location = mbo.getMboSet("LOCATION")
    if asset is not None and (asset.getString("X") != "" or asset.getString("Y") != ""):
        mbo.setValue("X", asset.getString("X"))
        mbo.setValue("Y", asset.getString("Y"))
    else if location is not None and (location.getString("X") != "" or location.getString("Y") != ""):
        mbo.setValue("X", location.getString("X"))
        mbo.setValue("Y", location.getString("Y"))

This script takes care of updating the workorder from the asset or location any time one of those is modified, as long as there isn't an x or y on the serviceaddress. If it turns out neither the asset or location have an x or y on them, it will skip setting the workorder's values, thereby leaving any value already there in place (which should be nothing though, since the serviceaddress wouldn't have had a value either, if it got this far).

Dex
  • 1,241
  • 6
  • 13
  • This really helps. Thank you. I was having a hard time piecing it all together. Regarding a point in your third paragraph, `"If someone clears these values and then saves, this would try to clear the values on the work order too, which may not be desired if there actually is an asset or location x and y."` Would there be a reason I couldn't add lines `#08` to `#14` from my pseudo-code to your first script -- to handle that issue? https://i.stack.imgur.com/QPt2R.png – User1974 Dec 21 '19 at 02:47
  • 1
    Yeah, I suppose that works. It duplicates a majority of the code in the second script, which is unfortunate, but it does close that gap. – Dex Dec 21 '19 at 04:05
0

An alternative to an automation script could be to use attribute formulas:

enter image description here

NVL(SERVICEADDRESS$LatitudeY,NVL(ASSET$Y,NVL(LOCATION$Y,"")))
NVL(SERVICEADDRESS$LongitudeX,NVL(ASSET$X,NVL(LOCATION$X,"")))

I'm guessing that the formulas run every time the WO is saved, which means this option doesn't match the requirements in the question.

But the formulas are dead simple, and likely won't affect performance, so they might be a viable option.

More information about Maximo formulas here: Formulas 1 (PDF) and Formulas 2 (PDF).


Note: I couldn't figure out how to return null (if all the search fields were null).

User1974
  • 276
  • 1
  • 17
  • 63
  • I think it would be tricky to return null when using NVL, as its express purpose is to "remove" null values for fields. – Dex Dec 23 '19 at 03:25