Calling python function from script report html

I am trying to pull data from within the HTML file of a custom script report. The .html file works perfectly.

I have no problem pulling data on the script using my python file within the report folder. Same goes for the filters created using javascript.

The issue is when I try to call a specific function using Jinja from within the .html file. I understand that we are calling JavaScript functions defined in the JavaScript file.

Is there a way to call a whitelisted Python function directly from the print format html?

I tried using the frappe.call callback javascript function, and I can trigger the Python function perfectly, I can even return the string to console and a frappe.msgprint, however I cannot get a simple string inserted into the HTML, instead I can only return [object Object], and am having issues in structuring how to access the direct contents of said object: {message:”String I Need”}

On the Script Report HTML file called when Printing:

<html>
<h1>Printed Report Title</h1>
{%= js_function_that_gets_string() %}
</html>

On the Script Report directory javascript file:

function js_function_that_gets_string() {
    var string = '';
    return string
}

On the init.py python file for my custom app:

@frappe.whitelist()
def my_python_function_with_business_logic(argument1):
    # my awesome code using argument_1
    return python_result

In hooks.py I added this line:

jenv = {
    "methods": [
        python_name_avail_to_jinja:my_python_function_with_business_logic
]

:white_check_mark: If I call the python function from Jinja, in a Custom Print Format, it works great, I get the exact contents of python_result.
{{ python_name_avail_to_jinja() }}

When I try calling the Javascript function with a proper callback structure, I can get the message back, it displays perfectly well with a console.log()

But I cannot access the r.message value properly, all I get in the HTML is
[object Object]

My specific problem or issue is to how to return this value with the javascript function call from the HTML Jinja. I thought of assigning the value perfectly well as a string, to a variable in the javascript function, and return this result when called from Jinja in the HTML, but this is not the expected behavior.

So, I found a temporary hack on my own.

The def execute function for the report from Python can return more arguments than those required. Which means user can modify function to return a List. The fact that it is a list, and only a list is “the hack”, however, at least the Script report print format HTML can access the data direct from Python, and then the user can work with this list using Jinja directly.

The solution is as follows:

  1. Create your custom Script report or similar.

  2. Open your dev server directory in terminal or similar, you’ll find:
    [your_custom_report].py
    [your_custom_report].js
    [your_custom_report].json

  3. Create a boilerplate HTML file (this will be your printed report), name it exactly as above: [your_custom_report].html

Edit this HTML file, such that you place your headings, tables and data elements properly.

  1. Inside whichever HTML element you need to place your data, type in the following line of Jinja:

{%= report.raw_data.data_to_be_printed[0] %}

Notice that we are referring to a JavaScript array, and accessing by index, which is similar to what python does. This will be very clear in the next step.

  1. Open the [your_custom_report].py file, and you will find the execute() function. In the return statement there are only two items: columns, data. Modify this line of code so it looks like this:

return columns, data, [ ], [ ], data_to_be_printed

We are interested in adding a list or dictionary to data_to_be_printed either with a fixed assignment or by calling another function within the function execute(). Options are unlimited here!

Let’s create a simple hello world list within execute()

data_to_be_printed = [“My very important data”, “secondary data”]

You will have to define the columns as well, along with some dummy data for this example, such that the report can be run by ERPNext successfully. Save all files.

  1. Run your report on ERPNext, and then click on Menu > Print to bring the print report dialog. Since it is a custom report, do not select letter head, nor pick columns, and make sure the orientation is landscape. Click on Submit.

Your report will display your columns and data, and the html element you specified will show the contents of the list specified: My very important data

Options:
You can also use a dictionary assignment for data_to_be_printed, for example:

data_to_be_printed = {
    'title': 'My Report Title',
    'subtitle': 'My report subtitle'
}

And then in the HTML you call it with:

{%= report.raw_data.data_to_be_printed['title'] %}
Which prints: My Report Title

Personally, I prefer using a dictionary, since keys are more meaningful and useful for debugging.

You can also inject an HTML string, which will be properly interpreted, for example:

data_to_be_printed = {
    'title': 'My Report Title',
    'subtitle': 'My report subtitle',
    'blue_text_div':'<div style="color: blue;">My awesome blue text</div>
'
}

Which results in a blue colored text in the HTML.
My awesome blue text

4 Likes