Just this week I was working on a customization where I was heavily depending on triggers to run some calculations upon the user entering data in a form. In my particular example, Sales Invoice and Sales Invoice Item had a custom trigger added that would recalculate some taxes upon changing the purchase of unit of measure. The calculation depends on the erpnext field stock_qty
and a pair of custom fields: custom_field_excise_tax
and custom_field_excise_tax_amt_this_line
The formula is simple: (stock_qty * custom_field_excise_tax)
The results are then assigned to custom_field_excise_tax_amt_this_line
like this:
frm.doc.items[index].custom_field_excise_tax_amt_this_line = (stock_qty * custom_field_excise_tax)
Thus:
(Note: index here is a parameter from a forEach function that selects the correct row (the current one) in a child table)
Thus, when updating the purchase uom
field on Sales Invoice Item Frappe automatically recalculates the stock_qty
, but my function, which runs correctly and calculates correctly otherwise, will run before frappe recalculates. This creates an error for my calculation function because it takes the values of stock_qty
that were previously available.
Thanks to some outside help, I was able to use the workaround trigger to run this: before_save
, and the calculation now picks the frappe-calculated values and yields the expected results. This workaround will have frappe running its code to update the stock_qty
field upon changing the uom
, and my function calculating improperly the first time, but when the view refreshes after save, the results now show correctly.
My function now runs from a separate trigger, like this:
frappe.ui.form.on("Sales Invoice", "before_save", function(frm) {
frm.doc.items.forEach((item) => {
my_calculation_function(frm, "Sales Invoice Item", item.name);
});
});
So, although the problem is currently resolved, the user has to be forced to Save the Sales Invoice, and I would really prefer to give the user the ability to see the results of his changes immediately as he or she is entering data in a form. This helps speed up multiple entries and makes data calculations on the fly.
So, I would like to know if there exists, or if we need to code it into the core, a program control feature that allows prioritization of calculations to be declared on the trigger directly, so that one can fine tune when your custom script is run. How can I tell frappe client-side the run order for functions? Or is this inexistent in the code?
If this already exists, it would be great to know how to use it. I will continue investigating the code.
If it doesn’t, I propose (and will eventually code and send a Pull request) some parameter passed into the trigger as a parameter with a hierarchical integer, which would allow for complex computations. Here’s an example of what I have in mind:
uom: function(frm, cdt, cdn, run_order=3) {
frm.doc.items.forEach((item) => {
my_calculation_function(frm, "Sales Invoice Item", item.name);
});
},
In this case: run_order= and its integer would tell which order to run this. For example, frappe has a run order of 1. erpnext has a run order of 2. Your custom script then can be run as #3 (after frappe and erpnext) or if you want to run it before, run it as run order 1