Visual Builder

Get Involved. Join the Conversation.

Topic

    Mark Chappell
    How to read from 2 Business Object in 1 Action Chain
    Topic posted June 22, 2019 by Mark ChappellBronze Medal: 1,250+ Points, last edited June 22, 2019, tagged Action Flows, Business Objects, REST, SaaS Integration 
    106 Views, 18 Comments
    Title:
    How to read from 2 Business Object in 1 Action Chain
    Summary:
    How to read from 2 Business Object (parent and child) in 1 Action Chain and contruct a single payload?
    Content:

    Hi OVBCS Guru’s

    I need some help with my OVBCS Application. I am a novice with OVBCS, and I am sure my question is a simple enough task / standard design pattern for the more experienced OVBCS practitioners out there ?? How can I construct a single payload (i.e. variable) from 2 business objects (parent and child), within the same action chain, so I can then call an external REST API passing the parent child payload to it?

    I have built a simple Sales Order application, with 1 Sales Order header and 1 Sales Order Lines table. These are based on separate Header and Lines Business Objects. I’ve created a relationship between them and have functionality to restrict the line records based on the header record selected.  I have a button within the header record table, which when pressed, gets the header record via the BO REST Endpoint, and populates a variable I’ve created. 

    This variable is based on a Service Connection I’ve created, which is based on an external REST API I want to call. This is an OICS Integration I’ve built. I can assign the data from my Header Table into my variable, and then call my Integration via an Action Chain triggered on the Button press, all good so far.

    However, my problem is, I need to also obtain the Line data on my button press action. I have attempted to update my Action Chain, to first call the REST Endpoint of the Header BO, passing to it the current action chain key value. I am then assigning the returned values to my variable. 

    My intention was then to call the REST Endpoint for my child BO and then have another Assign action to map, all of the Lines returned, to the Line Array in the same variable as above… Is this the correct approach?

    If so, how to I call the Lines BO REST Endpoint, to return only those lines associated with the Header record? As the REST Endpoints are by default taking the BO ID value? I’ve attached my VB APP, and Word Doc with additional screen shots. 

    Any help with this will be greatly appreciated.

    Thank you

    Mark.

    Document:

    Comment

     

    • Shay Shmeltzer

      Depends on how your page is constructed, but assuming that you have a master detail on the page with a form for the master and you are adding a list or table as the collection for the detail, then 

      When you use the "Add Data" quick start on the third step of the wizard you get a place where you can specify the filter criteria for the data that will be shown in the table.

      You can use that to filter the details based on the master id. (You can also add that filter criteria after the fact as shown here - https://youtu.be/oXu37_d_Rx4?t=128 )

       

      • Shay Shmeltzer

        By the way, you can actually get the master and the detail info in a single REST request using the expand option see the doc here:

        Fetching a Child Business Object                                     

        You'll need to enable the accessor from the master to the detail (edit the relationship definition and check the box).

        Then when you call the master you'll want to pass the URL parameter expand=accessorName

        You can set this in the json of the action chain adding this to the urlParameters section something like:

                "callDept": {
                  "module": "vb/action/builtin/restAction",
                  "parameters": {
                    "endpoint": "businessObjects/get_Department",
                    "uriParams": {
                      "Department_Id": "{{ $chain.variables.selection[0] }}",
                      "expand": "employeesCollection"
                    }
                  },
                  "outcomes": {
                    "success": "assignVariables1"
                  }
                },

        • David Konecny

          Alternative and possibly simpler way to fetch base record with its children is to define "type" which contains both base record and the children and then select that type in "Response Type" in your "Call REST Endpoint" action. Doing that tells VB what fields you are expecting to receive and VB take cares about creating REST call params for you automagically (which under the hook will result into using "expand" query param). To make it work you need to create Type from Endpoint (in Variables -> Types -> +Type -> From Endpoint)

    • David Konecny

      I would follow Shay's advice to fetch base record and its children in one call. But to answer your question, children would be read the same way as the parent - add after "assignVariables1" another RestAction call but this time for endpoint "getall_SOLineBusObject-sOBusObjectObject" and it will require SOLineBusObject_Id parameter just like the parent.

      Btw looking at your ForumPost document one thing which looks suspicious is that in your assignVariables1 you are assigning single retrieved sales order into myPostVar.SalesOrders and SalesOrders is array - why array when you are fetching single record?

      -David

      • Mark Chappell

        Hi David,

        thanks for your comments. I've updated the app based on the feedback from yourself and Shay.

        I've also created a new variable, based on mt external REST, which is a single Sales Order and an Array for Lines.

        However, as my latest update - see below - When I map from teh Lines array in my variable - to the my new variable (as described above) the external REST API is not called... 

        removing the Line item mapping - then the external REST is called...

        clearly something not quite right with my set up.

        any help is greatly appreciated.

         

        thanks 

        Mark

         

    • Shay Shmeltzer

      Here is a little blog/video that covers the solution (including David's suggestions):

      Master Detail on a Single Page with a Single REST Call

       

    • Mark Chappell

      Thanks Guys - I really appreciate your efforts - I will review and attempt to add this functionality today, and provide an update.

      Mark

    • Mark Chappell

      Hi guys,

      I’m looking at the solution offered by Shay, i.e. to ensure the relationship between master and child, is set up and accessor both switched on.

      Then create a new type based on the Master BO – here I can now see the REST will return the master and child BO…

      Then create a MasterDetail variable based on this type…

      Then ensure the REST call to the Master BO, returns Response Type as new type created above…

       

      Then in the button action chain, call the Master BO REST, and map the master and child to my POST variable (which is based on my REST API that I want to call…)

      Then call the REST Endpoint and pass to it my variable…

       

      All seems straight forward and I can do all of the above – however, when I map an attribute from the child array of the new MasterDetail variable (based on my new type as above) – the external REST is NOT called?

      When I only map to the POST variable, from the Master attributes of my MasterDetail – it works fine and the external REST is called…

      I can’t figure out yet, what is causing this problem – but when I’m mapping from the child array – it is failing…

      Again, any help would be greatly appreciated…

       

      Thanks

      Mark

    • Mark Chappell
    • Mark Chappell

      Hi Shay

      Thanks for the tip about, developer tools in Chrome.

      I am not getting any obvious errors, but when I map from the source to the target REST API, and map at the item array level – the call to the external API is not actioned.

      When I simply hard code values at the item level the external call works?

      I am at a loss?

      I’ve attached a word doc with screen shots and I’ve attached my VB App.

      Thanks

      Mark

    • Mark Chappell

      word doc with screen shots

    • Mark Chappell
      • Shay Shmeltzer

        I can't test your application since it strips away the user/pass from the service connections.

        When you run your app and the REST call doesn't get invoked - what do you see in the browser console? Any errors? Does the action of variable assignment works? Do you see the correct values in the variable in the console?

      • David Konecny

        One thing I noticed which is not working in your app is this: in ButtonActionChain1 there is RestAction call for businessObjects/get_SOBusObject where SOBusObject_Id is mapped to $page.variables.v_AllHeaderRow.id which is often (at least in my testing) undefined. The SOBusObject_Id should be mapped to $chain.variables.key (or $chain.variables.current.row.id). This error leads to chain terminating immediately and never progressing to passing data into external call. Is that your primary problem? Because once I fixed this I can see that NHSSC_MO_INT0005_ECOM_SLSORDR_OM/4.0/salesorder is being called always when "Import to OM" is clicked and its payload look valid too (though as Shay said I cant test it either as we don't have credentials).

        -David

         

        • David Konecny

          On second look at your app there are few other things I would suggest to change. Im attaching your app will all the changes implemented just for the sake of example:

          * in ButtonActionChain1 split assignment into v_myPOSTSalesOrder into two parts: #1) sales order record assignment and #2) assignment of order lines. While doing that I also changed Reset of v_myPOSTSalesOrder to "empty"

          * once I did that I noticed that businessObjects/get_SOBusObject call never returns any Lines - only base object is fetched. The cause for that Im guessing is that you added SOLineBusObject.sOBusObject field later right? As it is reference field BUT value of this field in null in all your records.

          * which made me curious how is it possible that Lines are shown correctly in main-start page? :-) And answer for that is that you are using filter criterion which is using SOLineBusObject.salesOrderID instead of SOLineBusObject.sOBusObject. I would not do that and replace it with SOLineBusObject.sOBusObject

          * sales order table has both selection listener and first-selected-row - only one is needed. I deleted the selection one

          * v_AllHeaderRow variable is not really needed - row listener on SalesOrder table has access to sale's row data and can pass them to both TableFirstSelectedRowChangeChain2 and also to ButtonActionChain1

          * upon page loading the lines table always shows all lines available as filter criteria from selected sales order table is not set yet. one way to deal with that it is to set initial query criteria on order lines to some non-sense value which returns nothing (see how I did it if not clear)

          * the assignment you are doing in ButtonActionChain1 is quite complex. I think I found a VB bug which I need to track down and file which happens in scenario like yours where items of array are bound to a difference array and SOME values are defaulted. In order to make this work I had to workaround it by defining a new object variable "defaultOrderLineValues" directly in the ButtonActionChain1 chain (when you open action chain there are three icons in vertical toolbar - Action Chain, Variables, Metadata - and this new variables can be found in the second section) and I assigned to this object default values which later go into SalesOrder.Lines records (eg. currencyCode, OrderedUOMCode, etc). If you are more familiar with coding JavaScript it would be very simple to turn this declarative VB assignment which is way too complex for my taste into simpler and more readable JS code. Let me know if you'd want to explore that more.

          So right now /salesorder external action is called with payload which looks correct to me - it has both base order and also order line values. I hope attached app will make it clearer and that I solved the problem you had.