Reputation: 2034
I struggle currently a bit to download an invoice as PDF from Odoo 13 with xml rpc.
The closest that I could get is this:
model_name = 'ir.actions.report'
model_method = 'render_qweb_pdf'
report_id = 282
invoice_id = 4
args = [[report_id]]
kwargs = {'res_ids': [invoice_id]}
models = ServerProxy('{}/xmlrpc/2/object'.format(url))
return models.execute_kw(db, uid, password,
model_name, method_name,
args, kwargs)
Yet I always end up with this error:
...py", line 46, in execute_kw
args, kwargs)
File "/usr/lib/python3.6/xmlrpc/client.py", line 1112, in __call__
return self.__send(self.__name, args)
File "/usr/lib/python3.6/xmlrpc/client.py", line 1452, in __request
verbose=self.__verbose
File "/usr/lib/python3.6/xmlrpc/client.py", line 1154, in request
return self.single_request(host, handler, request_body, verbose)
File "/usr/lib/python3.6/xmlrpc/client.py", line 1170, in single_request
return self.parse_response(resp)
File "/usr/lib/python3.6/xmlrpc/client.py", line 1336, in parse_response
p.feed(data)
File "/usr/lib/python3.6/xmlrpc/client.py", line 439, in feed
self._parser.Parse(data, 0)
xml.parsers.expat.ExpatError: not well-formed (invalid token): line 64, column 9
The data that its trying to parse there in this self._parser.Parse(data, 0)
-line is
b"<?xml version='1.0'?>\n<methodResponse>\n<params>\n<param>\n<value><array><data>\n<value><string>%PDF-1.3\n1 0 obj\n<<\n/Type /Pages\n/Count 0\n/Kids [ ]\n>>\nendobj\n2 0 obj\n<<\n/Producer (PyPDF2)\n>>\nendobj\n3 0 obj\n<<\n/Type /Catalog\n/Pages 4 0 R\n/Outlines 23 0 R\n/PageMode /UseOutlines\n/Dests 25 0 R\n/Names <<\n/EmbeddedFiles <<\n/Names [ (factur\\055x\\056xml) <<\n/Type /Filespec\n/F (factur\\055x\\056xml)\n/EF <<\n/F 27 0 R\n>>\n>> ]\n>>\n>>\n>>\nendobj\n4 0 obj\n<<\n/Type /Pages\n/Kids [ 5 0 R ]\n/Count 1\n/ProcSet [ /PDF /Text /ImageB /ImageC ]\n>>\nendobj\n5 0 obj\n<<\n/Type /Page\n/Parent 4 0 R\n/Contents 6 0 R\n/Resources 7 0 R\n/Annots 22 0 R\n/MediaBox [ 0 0 595 842 ]\n>>\nendobj\n6 0 obj\n<<\n/Filter /FlateDecode\n/Length 2705\n>>\nstream\nx\xc2\x9c\xc3\xad]K\xc2\x8f\xc3\xa4\xc2\xb8\r\xc2\xbe\xc3\x97\xc2\xaf\xc3\xb09@\xc2\xbb\xc2\xad\xc2\xb7\x0c\x04\x0bL\xc2\xbf\xc2\x82\xc3\xa4\x10`0\r\xc3\xac!\xc3\x88!\xc2\x98\xc3\x9dM\xc2\xb0\xc2\x98\xc3\x9ed\xc2\xb2\xc2\x87\xc3\xbc\xc3\xbdH\xc2\xb2\xc3\xbc\xc2\x92\xc3\xab\xc2\x93m\xc2\xb5\xc3\xad\xc2\xb2\xc2\xabk\x1a\xc2\x98z\xc2\xb0$Q\x14I\xc2\x91\x14)\xc3\x9f\xc3\xbf\xc3\xa9\xc3\x8b?\xc2\xb2\x7f\xc3\xbe\xc2\x9e\xc3\x9d?~\xc3\xb9O\xc3\xb6\xc3\x95\xc2\xbf>~9\x15\xc2\xb9.\xc3\xbc\xc2\xbf\xc3\x8c\xc3\xbe\xc3\x9d\xc3\xb5\xc2\xbfP\xc2\x84\xc3\xa7\xc2\xaa\xc2\xb4\xc3\xbf\xc2\xb2\xc2\xafo\xc2\xa7\xc3\xaf\xc3\x99\xc3\xb7\xc3\x93\xc3\xa7\xc3\x93g\xc3\xb3\xc2\xbf}\xc3\xbd~\xc2\xaa;"
So it actually looks quite good and so promising ... :(
Is there a better approach in Odoo 13 now? I checked and all the info for Odoo 12 and so on seems outdated as models / reports / functions / xrpc calls ... all don't exist anymore...
Upvotes: 3
Views: 1864
Reputation: 55
I've tried this in Odoo 17 (SAAS). Posting this answer so that someone can get help. Below is the code.
Step By Step explanation of how this code works Step 1: Import all required packages
from flask import Flask, request, jsonify,send_file
import xmlrpc.client
import requests
Step 2: Initialize your Odoo connection details like URL, Database name, Username and Password. (Replace these with your own Odoo connection details)
url = 'https://your_odoo_instance_url.com'
db = 'your_odoo_database'
username = 'your_odoo_username'
password = 'your_odoo_password'
Step 3: This Python code sends a login request to a web service using JSON-RPC, passing the database name, username, and password for authentication, and retrieves the session ID from the server's response cookies.
session_url = f'{url}web/session/authenticate'
data = {
'jsonrpc': '2.0',
'method': 'call',
'params': {
"service": "common",
"method": "login",
'db': db,
'login': username,
'password': password,
}
}
session_response = requests.post(session_url, json=data)
session_data = session_response.json()
session_id = session_response.cookies['session_id']
Step 4: The below Python code establishes connections to an XML-RPC server for authentication and object manipulation, retrieving the user ID after authentication.
common = xmlrpc.client.ServerProxy('{}/xmlrpc/2/common'.format(url))
uid = common.authenticate(db, username, password, {})
models = xmlrpc.client.ServerProxy('{}/xmlrpc/2/object'.format(url))
Step 5: Initialize the Invoice ID which you want to download.
invoice_id = 21566
Step 6:
In the below code invoice
gets the name of the Invoice so that we can name the PDF file. pdf_file_url
outputs the URL extension where you can download the PDF file.
invoice = models.execute_kw(db, uid, password, 'account.move', 'read', [invoice_id], {'fields': ['name']})
pdf_file_url = models.execute_kw(db, uid, password, 'account.move.send', 'action_send_and_print', [4,[invoice_id]])
Step 7:
In the below code we call the URL to download the PDF file and for that we have to give Cookie in headers and for Odoo the cookie value should look solrthing like this session_id=xxxxxxxxxxxxxxxxxx
and we already got our session ID from session_id
above, so we are going to use that here. The pdf_content
variable will have the binary value of the file.
headers = {'Cookie': f'session_id={session_id}'}
download_url = f'{url}{pdf_file_url["url"]}'
response = requests.get(download_url, headers=headers)
pdf_content = response.content
Step 8: Now save the file to your desired location (For me I'm saving in the same directory of the file)
filename = '{}.pdf'.format(invoice[0]['name'])
with open(filename, 'wb') as f:
f.write(pdf_content)
Complete Code
# Import necessary modules from Flask framework and other libraries
from flask import Flask, request, jsonify, send_file
import xmlrpc.client
import requests
# Set up credentials and URL for Odoo instance
url = 'https://your_odoo_instance_url.com'
db = 'your_odoo_database'
username = 'your_odoo_username'
password = 'your_odoo_password'
# Authenticate and get session ID from Odoo
session_url = f'{url}web/session/authenticate'
data = {
'jsonrpc': '2.0',
'method': 'call',
'params': {
"service": "common",
"method": "login",
'db': db,
'login': username,
'password': password,
}
}
session_response = requests.post(session_url, json=data)
session_data = session_response.json()
session_id = session_response.cookies['session_id']
# Set up XML-RPC connection to Odoo
common = xmlrpc.client.ServerProxy('{}/xmlrpc/2/common'.format(url))
uid = common.authenticate(db, username, password, {})
models = xmlrpc.client.ServerProxy('{}/xmlrpc/2/object'.format(url))
# Specify the ID of the invoice to retrieve
invoice_id = 21566
# Retrieve information about the specified invoice from Odoo
invoice = models.execute_kw(db, uid, password, 'account.move', 'read', [invoice_id], {'fields': ['name']})
# Trigger the action to send and print the invoice, and retrieve the URL of the generated PDF
pdf_file_url = models.execute_kw(db, uid, password, 'account.move.send', 'action_send_and_print', [4, [invoice_id]])
# Set up headers with the session ID for downloading the PDF
headers = {'Cookie': f'session_id={session_id}'}
download_url = f'{url}{pdf_file_url["url"]}'
# Download the PDF content of the invoice
response = requests.get(download_url, headers=headers)
pdf_content = response.content
# Specify the filename for the downloaded PDF based on the invoice name
filename = '{}.pdf'.format(invoice[0]['name'])
# Save the PDF content to a file
with open(filename, 'wb') as f:
f.write(pdf_content)
Upvotes: 1
Reputation: 11
Thanks for your answer!
I have found the following solution which works with XML RPC:
Code in Odoo 16:
class InvoiceXMLRPC(models.Model):
_inherit = "ir.actions.report"
def render_qweb_pdf_inherit(self, report_ref, res_ids=None, data=None):
pdf_content = self._render_qweb_pdf(report_ref, res_ids=res_ids, data=data)
pdf_content_encoded = base64.b64encode(pdf_content[0]) # needs to be encoded to be able to access with xmlrpc
return pdf_content_encoded
Code on the Raspberry Pi:
result = models.execute_kw(db, uid, password,
'ir.actions.report', 'render_qweb_pdf_inherit',[REPORT_ID, REPORT_ID],{'res_ids': invoice_ids})
invoice_content = base64.b64decode(result)
with open('/home/pi/InvoicePrintO16/invoices.pdf', 'wb') as report_file:
report_file.write(invoice_content)
os.system('lp invoices.pdf')
Upvotes: 1
Reputation: 2034
After discovering jsonrpc I was finally able to download the invoice ... Hope this helps someone in the absence of a solution with xmlrpc. (I am still looking for an xml rpc solution.)
import urllib.request
import json
import random
model_name = 'ir.actions.report'
method_name = 'render_qweb_pdf'
report_id = 282
invoice_id = 4
method = "call"
params = {
"service": "object",
"method": "execute",
"args": [db, uid, password, model_name, method_name, report_id, invoice_id],
}
data = {
"jsonrpc": "2.0",
"method": method,
"params": params,
"id": random.randint(0, 1000000000),
}
req = urllib.request.Request(url=f"{self.url}/jsonrpc", data=json.dumps(data).encode(), headers={
"Content-Type": "application/json",
})
reply = json.loads(urllib.request.urlopen(req).read().decode('UTF-8'))
if reply.get("error"):
raise Exception(reply["error"])
return reply["result"]
Upvotes: 2