Downloading PDF Files by REST API is it good decison?

I find the best way to download doctype’s pdf file on my local machine. Is exist any way to do it?

I have my part of code:

for item in items:
    url = "http://" + frappe.request.host + "/api/method/frappe.utils.print_format.download_pdf?doctype=Certificate&name=" + \
          item['name'] + \
          "&format=New Horizons Certificate&no_letterhead=0"
    doc = get_pdf(url)
    with open('file.pdf','wb') as file:
        file.write(doc)

When I opened my “file.pdf” as html page, I got error:
image

How I can download pdf file on my server? Is it correct way or what I make wrong?

1 Like

Good Day

I also looking for backend mine in php to download pdf and download to user pc.
Did you manage to get this working?

No, I wasn’t. I try to find the way right now

try below to download pdf :

frappe.local.response.filename = "test.pdf"
frappe.local.response.filecontent = get_pdf(html)
frappe.local.response.type = "pdf"

Thank You @sanjay.
@Artem i did it in PHP with Curl:

function erpnext_cmd($host,$array,$cookie){ $ch = curl_init();

$payload = json_encode($array);

curl_setopt( $ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_URL, ‘http://’.$host.‘/api/method’);
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie);
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie);
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, “POST”);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
‘Content-Type: application/json’,
'Content-Length: ’ . strlen($payload)
));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}


$download_array = array(‘cmd’ => ‘frappe.utils.print_format.download_pdf’,‘doctype’ => ‘Delivery Note’,‘name’ => $delivery_id, ‘format’ => ‘DN2’);

$download_data = erpnext_cmd($host ,$download_array,$cookie);

$pdfdata = base64_encode($download_data);

Javascript to download base64_pdf:

function download_pdf(base64Data,filename) { var arrBuffer = base64ToArrayBuffer(base64Data); var newBlob = new Blob([arrBuffer], { type: "application/pdf" });
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
    window.navigator.msSaveOrOpenBlob(newBlob);
    return;
}

var data = window.URL.createObjectURL(newBlob);
var link = document.createElement('a');
document.body.appendChild(link);
link.href = data;
link.download = filename + ".pdf";
link.click();
window.URL.revokeObjectURL(data);
link.remove();

}

function base64ToArrayBuffer(data) {
var binaryString = window.atob(data);
var binaryLen = binaryString.length;
var bytes = new Uint8Array(binaryLen);
for (var i = 0; i < binaryLen; i++) {
var ascii = binaryString.charCodeAt(i);
bytes[i] = ascii;
}
return bytes;
};

Hope This make sense.

I used this on a site that we hosted : https://www.standertonmills.co.za
gave more details of my dev here: PHP Company Website - #2 by trentmu

In Insomnia i used folowing:

http://your_url/api/method/frappe.utils.print_format.download_pdf?doctype=Sales%20Order&name=SO-00001&format=‘Sales%20Order2’&no_letterhead=0

Have a nice day

Albertus Geyser

2 Likes

Great work Mr. Albertus Geyser !!! Highly appreciate it :ok_hand::+1:

Hi,

What if we need to generate the PDF, save it temporarily on the ERPNext server to then send it to an external service ?

Basically, @Artem and I are trying to develop a Frappe app that will generate the PDF of a DocType and send it to a FTP server. This process will be triggered by the user (basically a button in the Web interface).
So, (we think) we should:

  1. Get the PDF from the selected DocType using the PDF generation URL
  2. Save the PDF to a temporary file
  3. Do our stuff (ie. send the file to an external service)

But for some reason, we get stuck at step 1, where the ERPNext says us we do not have permission to access the file (first message screenshot).

I think we need to pass the current user’s token to the get_pdf options (second argument), but how can we do that ?
How can we retrieve the authenticated user token and pass it to the python backend to download and save the PDF ?

Is user having report permission ?

@sanjay I’m not 100% sure what you mean by “report” permissions, but the user has the permissions to access the DocType and generate its PDF.

In terms of user process, it’s a little like how the user can send by email any DocType (ie. Frappe generates the PDF and adds it in attachment of the email).
In our case, we added a button in some DocTypes that should generate the PDF, save it on the backend and send it to an external service.

I want to share to you my (not perfect) solution of downloading pdf file automatically by sending get request to server:

generated_secret = frappe.utils.password.get_decrypted_password(
    "User", "Administrator", fieldname='api_secret'
)
api_key = frappe.db.get_value("User", "Administrator", "api_key")
header = {"Authorization": "token {}:{}".format(api_key, generated_secret)}
res = requests.get(url, headers=header, verify=False)
print(res)
with open('file.pdf', 'wb') as f:
    f.write(res.content)
return f
4 Likes

Can you share your code if you still have it?

1 Like
import requests

host = 'hostname or ip'
doctype='Item'
docname='item.name'
print_format ='Standard'
url = f"http://{host}/api/method/frappe.utils.print_format.download_pdf?doctype={doctype}&name={docname}&format={print_format}&no_letterhead=0"
api_key = 'api-key'
api_secret = 'api-secret'
header = {"Authorization": "token {}:{}".format(api_key, api_secret)}
res = requests.get(url, headers=header, verify=False)
print(res)
with open(f'{doctype}-{docname}-{print_format}.pdf', 'wb') as f:
    f.write(res.content)
1 Like