Calculating total in print format

I am calculating “total carton” in my sales invoice print format based on the qty entered in sales invoice and units_in_ctn field fetched from Item master. Grid is showing correct data. However when I use a variable to calculate total then it always show 0.0

{% set total_ctns = 0.0 %}
{% for item in doc.entries %}
{% set item_doc = frappe.get_doc("Item", item.item_code) %}
{% set ctns = (item.qty+item.schm)/item_doc.units_in_ctn %}
{% set total_ctns = total_ctns + ctns %}
{%- endfor -%}

If I show this varible total_ctns in the for loop then it shows correct value, however after endfor it shows 0.00. Any help???

This is a Jinja scoping issue and does not allow sharing of variables in the scope.

try using doc.total_ctns

@rmehta means I have to create a new field in “Sales Invoice” doctype and then set the value of this field in print format? How can I set the value of this field in print format?

You can attach your variable to “doc” rather than declare it as global. It might fix the scope issue.

@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/”, 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

jenv_filter = [

format for registering filter is filter_name:method_name

Use filters in template like following

{{ doc.indent| indent_refill_qty }}

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

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


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

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 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 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 as you suggested in comment above. But it says: no filter named ‘’ while saving the template.

Any idea where i could have missed ?


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 or some other reasons ?


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);