Change workflow attribute value from outside workflow instance

Options

Hello,

I'm still green to to OScript, so I'm not sure if what I'm asking is possible.

What I'm doing:

I have a dashboard-style Webreport that lists all instances of a workflow that are on a particular step. These workflow instances are grouped into to two tables based on the value of one of the workflow's attributes (set to string 'FALSE' by default when the workflow is initiated). The top table lists all of the instances that have the attribute set to the default, and the bottom table lists all instances that have the attribute set to 'TRUE'.

What I'm trying to do:

Each column of the first table has an HTML button (Add to work package) that runs a sub-webreport, feeding in the SubWork and task ID of the workflow instance as parameters. I want this sub-webreport to grab the workflow instance and change the value of the workflow attribute to 'TRUE', so that it will end up in the second table (after a page refresh or ajax call).

I can't use the SETWFATTR action sub-tag because it will only work if I'm using it within a webreport step or have the destination set to workflow.

If there is a way to change a workflow attribute from outside of the workflow instance using OScript, I could use the [LL_WEBREPORT_STARTSCRIPT /] tag. Has anyone had to do something similar?

Tagged:

Comments

  • Appu Nair
    edited April 28, 2021 #2
    Options
    In Oscript what we do is if we know two parameters workid and subworkid this allows a Oscripter to load what we call a work package. The work package OOB has 3 when you add form it becomes 4 , transmittals, WR etc it gets added and you can isolate the data structure. So with this Oscripters can manipulate the work package. If you know the taskid then you can do things like save etc. The same thing out of Oscript can be done in industry-standard languages like java or c# by using SOAP(CWS) or REST or old lapi. Rest is the new kid on black so feature parity is a problem there. . So if you want to see Oscript snippets minus any WR let me know I will show links etc I think what you are doing in WR Script is running some Oscript but some things available in Oscript is deliberately prevented in WR because of possible problems.

    For your self-research look in the old workflows/ Builder forum. You will find WF data structure parsing code in there
    Link 1 https://knowledge.opentext.com/knowledge/cs.dll?func=ll&objId=786303&objAction=view
    Link2 https://knowledge.opentext.com/knowledge/cs.dll?func=ll&objId=763674&objAction=view

    From time to time I post things in my blog too https://appukili.wordpress.com/
    Ossie Moore does it http://www.oscriptadventures.com/
    Greg Griffiths does it https://www.greggriffiths.org/

    Apart from me(I have been contributing to Oscript and others for about 18 plus years) look for code snippets Donna Nalls , Jeff Lang , @"John Simon" , Andre Roy, and countless OT contributors and search terms like ‘event scripts’ . I have written and posted tons of examples in the old forums


    #AOTDEV1D
  • I found a bunch of reusable WF Scripts I had https://knowledge.opentext.com/knowledge/cs.dll?func=ll&objId=63636347&objAction=browse&viewType=1

    the Oscript has some documentation written hopefully you can understand

    #AOTDEV1D

  • The help is appreciated Appu Nair. I'll look over all of this and update if I can get something working.

  • If you have the WorkID and SubworkID, you could use OScript as per Appu's recommendation to modify/save the work package.

    Once you wrap it in a custom web report sub-tag that has the necessary IDs and parameters, you could call it from a webreport.

    I have added some example code for accessing the WF package below.

    Good Luck!

    ---

    Some code to access the work object:

    WAPIWORK work = prgCtx.WSession().AllocWork()

    if ( !IsError( WAPI.AccessWork( work, WORK_WORKID, SUBWORK_SUBWORKID ) ) )

    ...

    end

    ---

    //Using WAPIWORK, set a named WF Attribute

    function void SetWFAttribute( object prgCtx, WAPIWORK work, string dname, list val )

      Object  obj = $WFMain.WFPackageSubsystem.GetItemByName( 'WFAttributes' )

      RecArray array = $WFMain.WAPIPkg.LoadWorkData( prgCtx, work )

      if ( IsDefined( obj ) )

       Record r

       Boolean found = False

       Assoc wfAttrData = Undefined

       for r in array

        if ( { r.TYPE, r.SUBTYPE } == { obj.fType, obj.fSubType } )

         found = True

         wfAttrData = r.USERDATA

         break

        end

       end

       if ( found )

        Assoc child

        found = False

        for child in wfAttrData.Content.RootSet.Children

         if child.DisplayName == dname

           wfAttrData.Content.RootSet.ValueTemplate.Values[ 1 ].( child.ID ).Values = val 

           found = true

         end

        end

        if ( found )

         success = obj.SaveWorkData( prgCtx, work, Undefined, wfAttrData )

        end

       end

      end

    end  

  • UPDATE:

    I've resorted to setting up a request handler to handle the execution of this function:

    http://nbp-otcs-sbx2.nbpower.com/OTCS/cs.exe?func=WFAtt.changeVal&work=2880257&UpdatableAttribute=initiator_Name&UpdatableAttributeValue=testVal

    I have the UpdateWFAttribute function defined in the root object of my module and I am calling it from the Execute() block of my request handler:

    When I test it, CSIDE throws an error at the function call saying that "WAPIWORK work" is not defined:

    I tried initializing it as "WAPIWORK work = prgCtx.WSession().AllocWork()" before feeding it into the UpdateWFAttribute function, but I suspect this won't work the way I'm trying it. While I can see that my PrgSession object has a WSession() variable, it does not seem to have any return value that I can work with:

    I'm probably making some rookie mistake or misunderstanding how to grab the work package using WAPIWORK.

    Any feedback would be appreciated.

  • Appu Nair
    edited May 20, 2021 #7
    Options

    if you see Klaus's code or my code (in my code which is an eventscript I get the work passed in)

    WAPIWORK work = prgCtx.WSession().AllocWork()

    if ( !IsError( WAPI.AccessWork( work, WORK_WORKID, SUBWORK_SUBWORKID ) ) )...

    end

    what you are doing possibly wrong here is in an RH the request that you are submitting is everything that the browser has sent to that execute line. However, think like this

    If a WF map has been initiated and saved in the database (select * from WWork where Workid=12345 and SubWorkid=12345)

    this line WAPI.AccessWork( work, WORK_WORKID, SUBWORK_SUBWORKID ) accesses the work and actually puts the data structure into the AllocWork variable.

    WAPI.AccessWork( work, 12345, 12345) //now the work handle has the values or data structures...

    request.workflowid cast as an integer Str.StringToValue(request.workflowid ) may not compile just writing from memory

    pass two variables in your RH like this workid=12345&subworkid=12345 changing it to a running workflow

    Note: it is only chance that the two numbers usually are identical if a WF spawns a sub wf it will have a different number

    in other words, what you have done is a simple work placeholder but nothing to access it...


    #AOTDEV1D

  • Thanks for the quick response, I think I'm understanding.

    I took your advice and added in a subworkid variable. I also ran the recommended report and confirmed that I am passing values for an existing workflow:

    I've added a call to AccessWork as well. It looks like I have a WAPIWORK object now, but it's empty:

    I've tried feeding AccessWork the integer values that I want as well (i.e: WAPI.AccessWork( work, 2986347, 2986347 ) ) instead of the variable names, but ended up with the same result. I've confirmed that these id's are correct by checking the url of the form task:

    The workflow I'm targeting is sitting with a status of 2 in WWork, so I know it's a valid executing workflow.

  • I see some issues and I cant fully think through the sequence operation. When you manipulate the WF Data Structure within an event script there are some extra calls that prepare the workflow. I think it is shown in old builder docs. Unfortunately, OT retired the documents from yesteryears. From your screencap, it is very obvious that that the variable is not having anything of use like my first foray into this many years ago. I include this link because you can see a screencap of the variables https://appukili.wordpress.com/2013/10/25/event-scripts-debugging/

    As things happen with old things and memory we used to do this very easily. I am trying to find an old RH code that I had. Since you know builder(CSIDE) if you want a head start I would run a WF step through WR Step code and look at the sequence it goes through.

    Another way I would have attempted this is to create some simple soap code and walk through its setup. When you use SOAP to change WF there is a sequence of events you have to do and you can of course debug them with CSIDE

    https://appukili.wordpress.com/2014/11/16/workflow-service-example-to-get-a-attachment-id/ a long time back I played with soap as well.

    I am not sure if you need to set some WAPI flags and LoadTaskStatus to get through your endeavour. I think you said this before you couldn't use an event script because it has to be user-driven from a dashboard. Don't worry we will all support.

    @John Simon ,@Greg Griffiths @Hugh Ferguson do you see what more the poster needs to do?

    #AOTD1D

  • I'll have a look over the weekend at the code, but I would start by looking at similar Request Handlers, e.g. Workflow Status or My Assignments for a Workflow task and follow the code down as you perform the actions, they will need to load the Workflow context and details to allow you to interact with it, there may also be some helper methods that abstract the low level details as well.

  • Appu Nair
    edited May 21, 2021 #11
    Options

    To me, it looks like what you would do and I looked in some old code.

    WAPIWORK work = WAPI.AllocWork( .fPrgCtx.WSession().fSession ) //based on the prgCtx of RH and hopefully that this guy has workflow manager rights on the workflow.

    Wapi.AccessWork( work, 12345 ) //this would create the handle fully

    //Create an Assoc so that we can return the work as we plan.

    Assoc wfinfo

    wfInfo.work = work

    wfInfo.generalData = $WFMAIN.WAPIPkg.GetMapStatusInfo( .fPrgCtx, 12345 , 12345 )

    wfInfo.workPackages = $WFMAIN.WAPIPkg.LoadWorkData( .fPrgCtx, wfInfo.work )

    //at this point look at the Assoc and you should have something in workpackages //the WFF attributes and form data are packages that you further manaipulate

    #AOTDEV1D

  • @BoyInR @Greg Griffiths I was able to quickly test this in my dev system 16.2.8 to test this and it worked flawlessly for me. I have to say that I am using otadmin@otds.admin.These are some word screen cap instructions. I just searched in the webwork for an OT script.. and then I used the script I wrote in 2003-2006 to change it. https://knowledge.opentext.com/knowledge/cs.dll/Properties/78461073

    the work variable does look like it doesn't have anything like old builder however that is for another day.


    #AOTDEV1D

  • Only thought I have on this is that the workID/subworkID might be accurate and represent a WF that is in progress and valid, but the user running the WAPI.AccessWork() call may or may not have rights to see those details. Make sure that the user you're using is at least a manager of the WF (you'd think that Admin user would have bypass on this but maybe not).

    Another thought I had was that if you're already in the juice as it were with Oscript, you might consider an event script in your workflows that would write any data you need out to your own table somewhere, meaning you could access those data you require with a simple WebReport querying that table, using the WF/SubWF ID's as keys.

    Just thinking out loud.

    -Hugh (other Oscript guy around here).