Firing Maximo workflow event from code - event-handling

In our Maximo workflow we have a few schemas in which work order reaches a Condition node with a check on a startdate. If current date is less than it's startdate then work order goes to a Wait node with "maximo.workorder.update" condition. So when the scheduled date for WO comes people need to go to WO tracking and save this WO manually. Only then it continues it's way through the workflow. Otherwise WO will sit on that Wait node till the end of time.
What I want to do is to trigger this update event by crontask everyday so when the right date comes WO will wake up by itself.
I inspected source code for a Save button in WO tracking application and found that no matter what there's MboRemoteSet.save() method call. I assumed that you need to get some changes done and then call save() on the right MboSet. Also I know that in DB there's table called EVENTRESPONSE that keeps track of WOs sitting on the Wait nodes in workflow.
My crontask class contains this code:
MXServer mxServer = MXServer.getMXServer();
UserInfo userInfo = mxServer.getUserInfo("maxadmin");
woSet = mxServer.getMboSet("WORKORDER", userInfo);
...
String query = "select sourceid as WORKORDERID from EVENTRESPONSE"
+ " where eventname = 'maximo.workorder.update'"
+ " and sourcetable = 'WORKORDER'";
SqlFormat sqf = new SqlFormat("workorderid IN (" + query + ")");
woSet.setWhere(sqf.format());
MboRemote wo;
Date currentDate = new Date();
for (int i = 0; (wo = woSet.getMbo(i)) != null; i++) {
System.err.println(wo.getString("description"));
wo.setValue("CHANGEDATE", currentDate);
}
woSet.save();
workorder.changedate successfully refreshes but "maximo.workorder.update" event doesn't proc and WO stays on the Wait node.
So, how should I fire maximo.workorder.update?

This response comes a year late, I understand, but it may help others.
It is possible to use an "Escalation" to identify all work orders that have had their time to come and use an action on the escalation to update something on the work order. This will result in Maximo saving the change, thereby triggering the wait node of the workflow, all without any code, just configurations.
I have done something similar in the past and usually I end up flipping a YORN field that I had created for this purpose.

Related

Trigger Beam ParDo at window closing only

I have a pipeline that read events from Kafka. I want to count and log the event count only when the window closes. By doing this I will only have one output log per Kafka partition/shard on each window. I use a timestamp in the header which I truncate to the hour to create a collection of hourly timestamps. I group the timestamps by hour and I log the hourly timestamp and count. This log will be sent to Grafana to create a dashboard with the counts.
Below is how I fetch the data from Kafka and where it defines the window duration:
int windowDuration = 5;
p.apply("Read from Kafka",KafkaIO.<byte[], GenericRecord>read()
.withBootstrapServers(options.getSourceBrokers().get())
.withTopics(srcTopics)
.withKeyDeserializer(ByteArrayDeserializer.class)
.withValueDeserializer(ConfluentSchemaRegistryDeserializerProvider
.of(options.getSchemaRegistryUrl().get(), options.getSubject().get()))
.commitOffsetsInFinalize())
.apply("Windowing of " + windowDuration +" seconds" ,
Window.<KafkaRecord<byte[], GenericRecord>>into(
FixedWindows.of(Duration.standardSeconds(windowDuration))));
The next step in the pipeline is to produce two collections from the above collection one with the events as GenericRecord and the other with the hourly timestamp, see below. I want a trigger (I believe) to be applied only two the collection holding the counts. So that it only prints the count once per window. Currently as is, it prints a count every time it reads from Kafka creating a large number of entries.
tuplePCollection.get(createdOnTupleTag)
.apply(Count.perElement())
.apply( MapElements.into(TypeDescriptors.strings())
.via( (KV<Long,Long> recordCount) -> recordCount.getKey() +
": " + recordCount.getValue()))
.apply( ParDo.of(new LoggerFn.logRecords<String>()));
Here is the DoFn I use to log the counts:
class LoggerFn<T> extends DoFn<T, T> {
#ProcessElement
public void process(ProcessContext c) {
T e = (T)c.element();
LOGGER.info(e);
c.output(e);
}
}
You can use the trigger “Window.ClosingBehavior”. You need to specify under which conditions a final pane will be created when a window is permanently closed. You can use these options:
FIRE_ALWAYS: Always Fire the last Pane.
FIRE_IF_NON_EMPTY: Only Fire the last pane if there is new data since
previous firing.
You can see this example.
// We first specify to never emit any panes
.triggering(Never.ever())
// We then specify to fire always when closing the window. This will emit a
// single final pane at the end of allowedLateness
.withAllowedLateness(allowedLateness, Window.ClosingBehavior.FIRE_ALWAYS)
.discardingFiredPanes())
You can see more information about this trigger.

Apex Trigger Between Two Child Objects

I am in the early stages of learning Apex and trying to write some code for a particular scenario. I have two custom objects called Outstanding and Transaction that are both children of an Account. I want to write a trigger that updates the end date of the Outstanding record that has a start date >= the start date on the Transaction and an end date < the end date on the Transaction. I want the end date on the correct Outstanding record to change to the end date on the Transaction.
Example:
Transaction: Start_Date__c (is changed to)= 1/2/2019
End_Date__c=1/31/2020
Outstanding Records:
Start_Date__c 1/4/2018 End_Date__c 1/4/2019
Start_Date__c 1/4/2019 End_Date__c 1/4/2020
Start_Date__c 1/4/2020 End_Date__c 1/4/2021
When the Transaction's start date is changed to 1/2/2019, I want the trigger to find the relevant Outstanding record 2 and update the end date to 12/31/2019.
Hopefully, that makes sense. If it doesn't, please let me know and I'll try to explain it again. Any help would be appreciated. Thanks.
You have to write a trigger on your Transaction Object on after update context. Please try the below codes.
**Trigger** :
`trigger TransactionTrigger on Transaction__c (after update) {
Map<Id,Transaction__c> accTraMap = new Map<Id,Transaction__c>();
for(Transaction__c transac : trigger.new){
accTraMap.put(transac.Account__c, transac);
}
if(!accTraMap.isEmpty()){
TransactionTriggerHandler.afterUpdate(accTraMap);
}
}`
**Class :**
public class TransactionTriggerHandler {
public static void afterUpdate(Map<Id,Transaction__c> accTransMap){
list<Outstanding__c> outstanding = [SELECT Id, Name, StartDate__c, EndDate__c, Account__c
FROM Outstanding__c where Account__c in:accTransMap.keyset()];
list<Outstanding__c> outstandingToUpdate = new list<Outstanding__c>();
for(Outstanding__c o : outstanding){
if(accTransMap.containsKey(o.Account__c)){
if(o.StartDate__c >= accTransMap.get(o.Account__c).Start_Date__c && o.EndDate__c < accTransMap.get(o.Account__c).End_Date__c){
o.EndDate__c = o.EndDate__c.toStartOfMonth().addDays(-1);
outstandingToUpdate.add(o);
}
}
}
system.debug('\n updated outstanding '+outstandingToUpdate);
if(!outstandingToUpdate.isEmpty()){
update outstandingToUpdate;
}
}
}

Utilities.formatDate() in Google Apps Script outputs previous date (e.g. input 25.05.2015 -> output 24.05.2015)

I have a problem with Google Docs' Utilities.formatDate() function.
I have a spreadsheet that contains all of the orders we place in the lab. When an order is delivered our lab manager enters the delivery date in the relevant cell in such a spreadsheet, in the following format: dd.MM.yyyy.
I created a script that, provided certain conditions, will email whoever placed that order alerting them that the order has been delivered on that particular date. Here is the code:
function DeliveryAlerts() {
try {
var email_dict = {"Y":"Y#Z.com"}
var spreadsheet = SpreadsheetApp.openById("ABC");
SpreadsheetApp.setActiveSpreadsheet(spreadsheet);
var sheet = spreadsheet.getSheetByName("Orders");
var values = sheet.getRange("A2:Q251").getValues();
var bgcolours = sheet.getRange("A2:Q251").getBackgrounds();
for(var i=0;i<=249;i++)
{
var j = i + 2;
if (values[i][16]=="Yes" && values[i][11]!="" && bgcolours[i][16]!="#b8b8b8")
{
var email_address = email_dict[values[i][13]];
var cur_date = Utilities.formatDate(values[i][11], "GMT+1", "EEE dd.MM.yyyy");
var message = "Hello there,\n\nYour order of " + values[i][4] + " has been delivered on "+ cur_date +".\n\nBest wishes";
var subject = "Delivery alert";
MailApp.sendEmail(email_address, subject, message,{replyTo:"abc#abc.com", name:"ABC"});
sheet.getRange("Q"+j).setBackground("#b8b8b8");
}
}
} catch (err) {
MailApp.sendEmail("abc#abc.com", "Delivery Alerts Script in Order Master List", err);
}
}
I use
Utilities.formatDate(values[i][11], "GMT+1", "EEE dd.MM.yyyy") to reformat the date from, say, 25.05.2015 (that is, the value in the cell) to Mon 25.05.2015. However, what I get instead is Sun 24.05.2015.
Does anybody know what is going on?
Thank you in advance.
Nicola
Check the time zone setting in the script editor. Under the FILE menu, choose PROJECT PROPERTIES in the script editor. It's possible to have a different time zone setting in Apps Script, than is in the spreadsheet. This is a common issue that arises. Apps Script allows a separate time zone setting from the spreadsheet. Also, even if the time is only off by one minute, if the time setting of the date is all zeros, it's common to get the problem that you are having. When a user enters a date, it's possible that no time setting is made. So the time is set to all zeros. The date is correct, but the time is all zeros. Even if the date was typed in at 3 in the afternoon, for example, and the date is correct, the time setting can be midnight of that day. So, even if you subtracted one second from that date, it would now be the day before.

Trigger works but test doesn't cover 75% of the code

I have a trigger which works in the sandbox. The workflow checks the field in the campaign level and compares it with the custom setting. If it matches, then it returns the target to the DS Multiplier field. The trigger looks as follows
trigger PopulateTarget on Campaign (before insert, before update)
{
for(Campaign campaign : Trigger.new)
{
if (String.isNotBlank(campaign.Apex_Calculator__c) == true)
{
DSTargets__c targetInstance = DSTargets__c.getInstance(campaign.Apex_Calculator__c);
{
String target = targetInstance .Target__c;
campaign.DS_Target_Multiplier__c = Target;
}
}
}
}
However, I had problems to write a proper test to this and asked for the help on the internet. I received the test
#isTest
private class testPopulateTarget{
static testMethod void testMethod1(){
// Load the Custom Settings
DSTargets__c testSetting = new DSTargets__c(Name='Africa - 10 Weeks; CW 10',Target__c='0.1538', SetupOwnerId = apexCalculatorUserId);
insert testSetting;
// Create Campaign. Since it would execute trigger, put it in start and stoptests
Test.startTest();
Campaign testCamp = new Campaign();
// populate all reqd. fields.
testCamp.Name = 'test DS campaign';
testCamp.RecordTypeId = '012200000001b3v';
testCamp.Started_Campaign_weeks_before_Event__c = '12 Weeks';
testCamp.ParentId= '701g0000000EZRk';
insert testCamp;
Test.stopTest();
testCamp = [Select ID,Apex_Calculator__c,DS_Target_Multiplier__c from Campaign where Id = :testCamp.Id];
system.assertEquals(testCamp.DS_Target_Multiplier__c,testSetting.Target__c);// assert that target is populated right
}
}
Such test returns the error "Compile Error: Variable does not exist: apexCalculatorUserId at line 6 column 122". If I remove that ApexCalculator part System.assertEquals then the test passes. However it covers 4/6 part of the code (which is 66%)
Could anyone help me how should I amend the code to make the coverage of 75%?
Yes, apexCalculatorUserId has not been defined. The code you were given appears to be incomplete. You'll need to look at the constructor DSTargets__c and see what kind of ID it is expecting there.
At a guess, you could try UserInfo.getUserId() to get the ID of the current user, but that may not be the ID that's expected in the constructor. It would be worth trying it to see if the test coverage improves.
1) Replace apexCalculatorUserId with UserInfo.getUserId()
2) I'm not sure what kind of field is Apex_Calculator__c on campaign. If its not a formula you want to insert a new line before "insert testCamp". Something like:
testCamp.Apex_Calculator__c = UserInfo.getUserId();

GWT incubator table data ordering issue

I have implemented a gwt incubator table following the example at http://zenoconsulting.wikidot.com/blog:17
this works great however, the order of rows is not same as it is passed using the list object.
the data in this example is set in the following part of the code:
public long showMessages(ArrayList<Message> list) {
long start = System.currentTimeMillis();
// update the count
countLabel.setText("There are "+ list.size() + " messages.");
// reset the table model data
tableModel.setData(list);
// reset the table model row count
tableModel.setRowCount(list.size());
// clear the cache
cachedTableModel.clearCache();
// reset the cached model row count
cachedTableModel.setRowCount(list.size());
// force to page zero with a reload
pagingScrollTable.gotoPage(0, true);
long end = System.currentTimeMillis();
return end - start;
}
Please provide some solution to fix this issue.
awesome! thank you! somehow i ignored this part and internally down the line code was using a hashMap to manage table data which obviously does not retain the sort order. i changed it to linkedHashMap and it worked