Reputation: 55
I'm working on a Python Flask application where I need to download sales order invoices from Odoo 15 using either XML-RPC or JSON-RPC. However, due to security constraints, I cannot access the Odoo source code via SSH. The only data I have is the Odoo database name, username, password, and the ID of the invoice I want to download.
Is there a way to call an API or utilize XML-RPC/JSON-RPC methods to download the sales order invoice directly from Odoo 15 without accessing the source code? Any code snippets or guidance on how to achieve this within a Python Flask environment would be greatly appreciated.
import xmlrpc.client
import json
import base64
from urllib.request import urlopen
from flask import Flask, request, send_file
# Odoo Configuration
url = 'https://your_odoo_instance_url.com'
db = 'your_odoo_database'
username = 'your_odoo_username'
password = 'your_odoo_password'
# Core Invoice Fetching Logic
def fetch_and_download_invoice_xmlrpc(invoice_id):
"""Fetches and downloads a sales invoice using XML-RPC"""
common = xmlrpc.client.ServerProxy('{}/xmlrpc/2/common'.format(url))
uid = common.authenticate(db, username, password, {})
models = xmlrpc.client.ServerProxy('{}/xmlrpc/2/object'.format(url))
# Fetch the PDF content
pdf_content_encoded = models.execute_kw(
db, uid, password, 'ir.actions.report', 'render_qweb_pdf_inherit', [invoice_id]
)
pdf_data = base64.b64decode(pdf_content_encoded)
with open('invoice_{}.pdf'.format(invoice_id), 'wb') as f:
f.write(pdf_data)
def fetch_and_download_invoice_jsonrpc(invoice_id):
"""Fetches and downloads a sales invoice using JSON-RPC"""
aurl = f"{url}/jsonrpc"
headers = {'Content-type': 'application/json'}
# Authentication
auth_data = {
"jsonrpc": "2.0",
"method": "call",
"params": {"db": db, "login": username, "password": password},
"id": 1
}
auth_response = json.loads(urlopen(aurl, json.dumps(auth_data).encode()).read())
if auth_response.get('error'):
raise Exception(auth_response['error'])
uid = auth_response['result']
# Fetch and download invoice
data = {
"jsonrpc": "2.0",
"method": "call",
"params": {
"service": "object",
"method": "execute",
"args": [db, uid, password, 'ir.actions.report', 'render_qweb_pdf', [invoice_id]]
},
"id": 2
}
pdf_response = json.loads(urlopen(aurl, json.dumps(data).encode()).read())
pdf_data = base64.b64decode(pdf_response['result'])
with open('invoice_{}.pdf'.format(invoice_id), 'wb') as f:
f.write(pdf_data)
# Flask Application
app = Flask(__name__)
@app.route('/download_invoice', methods=['GET'])
def download_invoice():
invoice_id = request.args.get('invoice_id')
if not invoice_id:
return "Please provide an invoice ID", 400
try:
# Choose either XML-RPC or JSON-RPC
fetch_and_download_invoice_xmlrpc(int(invoice_id)) # Convert to integer
fetch_and_download_invoice_jsonrpc(int(invoice_id))
return send_file('invoice_{}.pdf'.format(invoice_id), as_attachment=True)
except Exception as e:
return str(e), 500
if __name__ == '__main__':
app.run(debug=True)
This is how I tried with both XML-RPC and JSON-RPC
Edit I've got the answer and this below code works
# 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: 0
Views: 255
Reputation: 484
Please try using the below code and let me know if it helps:
import xmlrpc.client
import json
import base64
from urllib.request import urlopen
from flask import Flask, request, send_file
# Odoo Configuration
url = 'https://your_odoo_instance_url.com'
db = 'your_odoo_database'
username = 'your_odoo_username'
password = 'your_odoo_password'
# Core Invoice Fetching Logic
def fetch_and_download_invoice(invoice_id, rpc_method):
"""Fetches and downloads a sales invoice using the specified RPC method"""
if rpc_method not in ['xmlrpc', 'jsonrpc']:
raise ValueError("Invalid RPC method")
if rpc_method == 'xmlrpc':
common = xmlrpc.client.ServerProxy('{}/xmlrpc/2/common'.format(url))
uid = common.authenticate(db, username, password, {})
models = xmlrpc.client.ServerProxy('{}/xmlrpc/2/object'.format(url))
else: # jsonrpc
aurl = f"{url}/jsonrpc"
auth_data = {"jsonrpc": "2.0", "method": "call", "params": {"db": db, "login": username, "password": password}, "id": 1}
auth_response = json.loads(urlopen(aurl, json.dumps(auth_data).encode()).read())
if auth_response.get('error'):
raise Exception(auth_response['error'])
uid = auth_response['result']
# Fetch and download invoice
data = {"jsonrpc": "2.0" if rpc_method == 'jsonrpc' else None,
"method": "call",
"params": {"service": "object", "method": "execute", "args": [db, uid, password, 'ir.actions.report', 'render_qweb_pdf', [invoice_id]]},
"id": 2 if rpc_method == 'jsonrpc' else None}
pdf_response = json.loads(urlopen(aurl, json.dumps(data).encode()).read()) if rpc_method == 'jsonrpc' else models.execute_kw(
db, uid, password, 'ir.actions.report', 'render_qweb_pdf_inherit', [invoice_id]
)
pdf_data = base64.b64decode(pdf_response['result'] if rpc_method == 'jsonrpc' else pdf_response)
with open(f'invoice_{invoice_id}.pdf', 'wb') as f:
f.write(pdf_data)
# Flask Application
app = Flask(__name__)
@app.route('/download_invoice', methods=['GET'])
def download_invoice():
invoice_id = request.args.get('invoice_id')
rpc_method = request.args.get('rpc_method', 'jsonrpc') # Default to JSON-RPC if not specified
if not invoice_id:
return "Please provide an invoice ID", 400
try:
fetch_and_download_invoice(int(invoice_id), rpc_method)
return send_file(f'invoice_{invoice_id}.pdf', as_attachment=True)
except Exception as e:
return str(e), 500
if __name__ == '__main__':
app.run(debug=True)
This code consolidates the logic for both XML-RPC and JSON-RPC into a single fetch_and_download_invoice
function, which allows you to choose the RPC method dynamically based on the rpc_method
parameter.
Upvotes: 1