Calculating total in print format

@rmehta any sample code related to setting value in doc variable in print format?

This is what I meant:

{% set doc.total_ctns = 0.0 %}

@rmehta I tried to create a variable total_ctns and then setting its value. However facing this issue
> self.handle_exception(exc_info, source_hint=source)

File “/home/erpnext/frappe-bench/env/local/lib/python2.7/site-packages/jinja2/environment.py”, line 742, in handle_exception
reraise(exc_type, exc_value, tb)
File “”, line 33, in template
TemplateSyntaxError: expected token ‘=’, got ‘.’

1 Like

mmm… I am not sure. Maybe you should do all calculations server side in custom fields and use the data in Jinja. Jinja is not optimized for processing.

@rmehta this are very small calculations and I think jinja is doing the job but not handling the scope of the variables correctly. Jinja is calculating the total_ctns but not able to retain the value of this varibale beyond the scope of for loop

Well let me try to find a way for it.

Its late for this post, but i also ran into same issue. For ref, i took the following approach.

Register a custom filter with jinja context in custom app by adding jenv_filter to hooks.py

jenv_filter = [
    'indent_refill_qty:flows.jinja_filters.indent_refill_qty',
    'indent_oneway_qty:flows.jinja_filters.indent_oneway_qty',
]

format for registering filter is filter_name:method_name

Use filters in template like following

{{ doc.indent| indent_refill_qty }}
5 Likes

Try this:
If the child table is called Items and you want the sum of ‘qty’ from Item rows:

{{ doc.items|sum(attribute='qty') }}

6 Likes

The path “flows.jinja_filters.indent_refill_qty”: can you describe what “flows”, “jinja_filters” and “indent_refill_qty” are? Is this a dotted.path.to_function syntax? I’m trying to repeat your steps in my own custom app without success.

1 Like

flows is my app name.
jinja_filters is the module/file in app.
indent_refill_qty is a function within the module/file.

you can also check this out Flows/jinja_filters.py at master · BhupeshGupta/Flows · GitHub

1 Like

Perfect! I knew that path was too long to point to a method in a doctype. Thank you!

So an update on this: I got it working with @BhupeshGupta’s instructions and example, but it required a bench migrate for the changes in hooks.py to get picked up in the Jinja environment. I doesn’t really make sense to me what that would need to be done since other changes to hooks.py are dynamic. I hope I save somebody some future frustration with that.

use array to maintain the value out of the looping scope

I tried to add my filter and linked it to hooks.py as you suggested in comment above. But it says: no filter named ‘’ while saving the template.

Any idea where i could have missed ?

Regards,

Parth Joshi

Haven’t faced this issue myself, but as per @tmatteson you need to do bench migrate. Try that.

bench migrate ??

Do we need to do bench migrate because of hooks.py or some other reasons ?

Regards,

Parth Joshi

i suggest create another field in sales invoice then used this custom script to compute the total number of cartons. and try this code

total_cartons → the field that calculates the number of cartons

frappe.ui.form.on(“Sales Invoice”, “refresh”, function(frm, cdt, cdn) {
total_cartons = 0;
$.each(frm.doc.items || [], function(i, d) {
total_cartons += flt(d.units_in_ctn);
});
frm.set_value(“total_cartons”, total_cartons);
});

Yes, I think so. Changes to hooks are picked up on restart as far as I can tell, so migrate probably isn’t as good as restart (in production) or a kill([CTRL-C]) and start in develop mode.

Yes @tmatteson and @BhupeshGupta, you are right. You dont need bench migrate. But bench restart or stopping and starting the process in developer mode will do the job.

The problem was something else.

I have 2 bench versions on my machine. One is frappe 10.1.35 and other is 10.1.29. I was trying on frappe 10.1.35 where this is not working. After switching to 10.1.29, the above worked. I digged at bit into frappe code and found this difference in jinja.py in both the versions of frappe:

In version 10.1.29 (where the filter works) :


...
def set_filters(jenv):
	import frappe
	from frappe.utils import global_date_format, cint, cstr, flt, markdown
	from frappe.website.utils import get_shade, abs_url
...
...
...
	# load jenv_filters from hooks.py
	for app in frappe.get_installed_apps():
		for jenv_filter in (frappe.get_hooks(app_name=app).jenv_filter or []):
			filter_name, filter_function = jenv_filter.split(":")
			jenv.filters[filter_name] = frappe.get_attr(filter_function)

And the one in version 10.1.35 is:

....
def set_filters(jenv):
	import frappe
	from frappe.utils import global_date_format, cint, cstr, flt, markdown
	from frappe.website.utils import get_shade, abs_url

...
...
...
	# load jenv_filters from hooks.py
	for app in frappe.get_installed_apps():
		for jenv_filter in frappe.get_hooks(app_name=app).get('jenv', {"filters": []})["filters"]:
			filter_name, filter_function = jenv_filter.split(":")
			jenv.filters[filter_name] = frappe.get_attr(filter_function)

You can clearly see the difference in the way the loop is pulling the filer and function name pair.

I have not tried in 10.1.35, but what I assume is that :

Following is best was to define filter in 10.1.29:

### hooks.py

jenv_filters = [
    filter_name1:function_name1, 
   ...
]

whereas this could be the way to try it out in 10.1.35:

### hooks.py
jenv = {
    filters : [
    filter_name1:function_name1, 
         ...
    ]
}

Seems @sharath_c has pushed the change in the for loop in /frappe/frappe/utils/jinja.py in 10.1.35 before 2 months which was written by Anand 4 years ago. Can @sharath_c or anyone from the foundation can suggest the change which has been done here? Can you validate the above ?

Regards,

Parth Joshi

1 Like

@joshiparthin: Please refer this PR.

The previous hooks only had support for custom filters in jinja environment. Support for custom methods was added and hence changes to hooks declaration was done to keep all jinja environment hooks under one head.

3 Likes

@sharath_c This makes sense to me and I think the argument for consistency is a strong one. Thanks for providing the context here.
@joshiparthin Nice sleuthing, Parth.

1 Like