Solved

FSM Business Rule - expression subtract from value

  • 5 March 2020
  • 5 replies
  • 944 views

Userlevel 5
Badge +12

I have this problem with implementing a business case. The case I have is as follows.

  • In task_steps I have filled in a quantity (lets call it x) in user_def_num1 for step_id =66
  • This task_steps record with a quantity needs to be processed by the business rules and add a non_part_usage record. 
  • My business rule needs to output the quantity if it is higher then 25 and then create the non_part_usage record with a quantity of x - 25. 

I am trying to do this with an XML business rule, but I am aware that I need to use some expression. I only do not know how to do that. This is my code which needs to insert the record. As you can see I fetch the quantity with an xpath_node from an hierarchy_select result called ‘result01’.

Without the expression stuff it gives me the quantity, but I need to subtract 25 from this value.

<update_non_part_usage>
<non_part_usage>
<request_id>@request_id</request_id>
<task_id>@task_id</task_id>
<npu_id></npu_id>
<description>Auto Inserted by SEC CODE mapping BR</description>
<line_code>SEC4</line_code>
<line_code_type>SEC</line_code_type>
<quantity xpath_node="//task_steps_hierarchy_select_result[@result_name='result01']/task_steps/user_def_num1" - 25]></quantity>
<insert is_initialized="False" />
</non_part_usage>
</update_non_part_usage>

This is how my business rule screen looks like now. 

 

icon

Best answer by josdepijper 10 April 2020, 15:09

View original

5 replies

Userlevel 7
Badge +24

Have you tried it with the  - 25 inside the quotes? XML is not my strong suite but I think the calculation needs to be inside the select rather than after.

Userlevel 5
Badge +17

You cannot combine an xpath attribute for field value assignment with an expression in XML.  Assuming the business process is triggered by a task_steps record, then you already have the value you need in the triggering record, which you can reference in an expression.  I don’t think you need to query the task_steps record unless your business process is triggered by a transaction on a different table.

I would try removing the hierarchy select, and just doing the update as follows.  I would also use an expression in the business rule criteria instead of using the validation XML for better performance.  You want to limit how often you ask the server to access the database.

<update_non_part_usage>
<non_part_usage>
<request_id>@request_id</request_id>
<task_id>@task_id</task_id>
<npu_id></npu_id>
<description>Auto Inserted by SEC CODE mapping BR</description>
<line_code>SEC4</line_code>
<line_code_type>SEC</line_code_type>
<quantity>@expression[task_steps.user_def_num1 - 25]</quantity>
<insert is_initialized="False" />
</non_part_usage>
</update_non_part_usage>

Lastly, make sure you have task_steps.user_def_num1 set force_select = Y in custom metadata.

 

Userlevel 5
Badge +12

This can be done via a perform_evaluate_expression which you have to add to you XML message. 

 <perform_evaluate_expression result_name="result03">
<parameters>
<table_name>task_steps</table_name>
<keys>
<key_item>
<column_name>task_step_id</column_name>
<column_value xpath_node="//task_steps_hierarchy_select_result[@result_name='result01']/task_steps/task_step_id" />
</key_item>
</keys>
<expression>task_steps.user_def_num1 - 25</expression>
</parameters>
</perform_evaluate_expression>

In this perform you have to pass in your value with “xpath_node=***” , *** is a string which is referring to another hierarchy select where your original value came from.  This hierarchy selects of my original value looks like below code. You need it to specify the *** part of the xpath_node.

 <hierarchy_select return_only_requested_attrs="true" max_rows="1" result_name="result01">
<primary_table>task_steps</primary_table>
<attrs>
<attr>task_steps.user_def_num1</attr>
<attr>task_steps.task_step_id</attr>
</attrs>
<from>
<table>task_steps</table>
</from>
<where>
<data_constraint>
<constraint>
<left_operand>task_steps.user_def2</left_operand>
<operator>eq</operator>
<right_operand>@request_id</right_operand>
</constraint>
<constraint>
<left_operand>task_steps.step_id</left_operand>
<operator>eq</operator>
<right_operand>66</right_operand>
</constraint>
<constraint>
<left_operand>task_steps.step_type</left_operand>
<operator>eq</operator>
<right_operand>PRODVAL</right_operand>
</constraint>
</data_constraint>
</where>
</hierarchy_select>

The result of the perform_evaluate_expression can then be passed to you update message, also via a xpath_node. 

 </update_non_part_usage>
<update_non_part_usage>
<non_part_usage>
<request_id>@request_id</request_id>
<task_id>@task_id</task_id>
<npu_id></npu_id>
<description>Auto Inserted by SEC CODE mapping BR</description>
<line_code>SEC4</line_code>
<line_code_type>SEC</line_code_type>
<quantity xpath_node="//perform_evaluate_expression_result[@result_name='result03']/response" />
<insert is_initialized="False" />
</non_part_usage>
</update_non_part_usage>

Then the last part where you have to be carefull with is that you perform all the xml code within a “perform_batch” and tell it how to run through the code with a tag.

<perform_batch>
// Choose one of beneath methods. //
<sequential_dependent/>
<sequential_independent/>
<sequential_dependent/>
<sequential_independent/>

//
This is what it means...
· sequential_independent—each message in the batch is executed one at a time, in order; if one message operation fails, the next is executed.
· sequential_dependent—each message in the batch is executed one at a time, in order; if one message operation fails, execution is stopped, and all transactions are rolled back.
· concurrent_independent—each message in the batch is executed at the same time; if any message operation fails, the rest continue to execute.
· concurrent_dependent—each message in the batch is executed at the same time; if any message operation fails, execution is stopped, and all transactions are rolled back.
//

// Here your xml code. //

</perform_batch>

The complete code for you a an example.

<perform_batch>
<sequential_dependent/>
<hierarchy_select return_only_requested_attrs="true" max_rows="1" result_name="result01">
<primary_table>task_steps</primary_table>
<attrs>
<attr>task_steps.user_def_num1</attr>
<attr>task_steps.task_step_id</attr>
</attrs>
<from>
<table>task_steps</table>
</from>
<where>
<data_constraint>
<constraint>
<left_operand>task_steps.user_def2</left_operand>
<operator>eq</operator>
<right_operand>@request_id</right_operand>
</constraint>
<constraint>
<left_operand>task_steps.step_id</left_operand>
<operator>eq</operator>
<right_operand>66</right_operand>
</constraint>
<constraint>
<left_operand>task_steps.step_type</left_operand>
<operator>eq</operator>
<right_operand>PRODVAL</right_operand>
</constraint>
</data_constraint>
</where>
</hierarchy_select>
<perform_evaluate_expression result_name="result03">
<parameters>
<table_name>task_steps</table_name>
<keys>
<key_item>
<column_name>task_step_id</column_name>
<column_value xpath_node="//task_steps_hierarchy_select_result[@result_name='result01']/task_steps/task_step_id" />
</key_item>
</keys>
<expression>task_steps.user_def_num1 - 25</expression>
</parameters>
</perform_evaluate_expression>
<update_non_part_usage>
<non_part_usage>
<request_id>@request_id</request_id>
<task_id>@task_id</task_id>
<npu_id></npu_id>
<description>Auto Inserted by SEC CODE mapping BR</description>
<line_code>SEC3</line_code>
<line_code_type>SEC</line_code_type>
<quantity>1</quantity>
<insert is_initialized="False" />
</non_part_usage>
</update_non_part_usage>
<update_non_part_usage>
<non_part_usage>
<request_id>@request_id</request_id>
<task_id>@task_id</task_id>
<npu_id></npu_id>
<description>Auto Inserted by SEC CODE mapping BR</description>
<line_code>SEC4</line_code>
<line_code_type>SEC</line_code_type>
<quantity xpath_node="//perform_evaluate_expression_result[@result_name='result03']/response" />
<insert is_initialized="False" />
</non_part_usage>
</update_non_part_usage>
</perform_batch>

 

Userlevel 5
Badge +17

Very nice solution!

Which table triggers this business process?  You may want to consider adding an index on task_steps.user_def2 to avoid table scans of task_steps.

I am really surprised this is not being triggered on an update to the task_steps record itself.  Have you considered doing that for performance?  The task_steps table can get pretty big.

Userlevel 5
Badge +12

Thanks :relaxed:

The business process is triggered on task. The idea is that the (backoffice) user has to review task_steps of the type PRODVAL (values entered by production via mobile app) manually. When everything is reviewed (maybe the users does some changes) then the user has to set a parameter to true on task level and then press ‘Save’.

I am then always deleting all old automatically created values with a mass_update. After that BR I launch my non_part_usage creation BR's.

I have been thinking about launching on task_steps, but I have multiple different scenario's. If I would do this then I needed to define for every individual scenario a validation xml, an insert/update xml message and a delete alternate_xml. 

With the parameter on task level I keep it sort of ‘simple’. This way I am able to give a user instruction which launches my business rules. Always perform the delete rule (just 1 mass_update rule) and then perform my insert rules. I could do the same with a trigger on task_steps maybe, but then you are performing mass_updates on every task_step update which will not be beneficial for user experience.

 

Reply