Use class-based odoo client for connection reuse

This commit is contained in:
Tobias Kunze 2025-05-26 13:06:31 +02:00
parent 6ce13126d5
commit 8f75db5325

View file

@ -15,69 +15,77 @@ ADDRESS_FIELDS = [
"phone",
"vat",
"company_type",
"type",
]
def odoo_request(model, method, **kwargs):
url = settings.ODOO["URL"]
db = settings.ODOO["DB"]
username = settings.ODOO["USERNAME"]
password = settings.ODOO["PASSWORD"]
class OdooClient:
def __init__(self):
self.url = settings.ODOO["URL"]
self.db = settings.ODOO["DB"]
self.username = settings.ODOO["USERNAME"]
self.password = settings.ODOO["PASSWORD"]
try:
common = xmlrpc.client.ServerProxy(f"{url}/xmlrpc/2/common")
uid = common.authenticate(db, username, password, {})
self.common_proxy = None
self.models_proxy = None
self.uid = None
if not uid:
raise Exception("Authentication failed with Odoo.")
def _connect(self):
"""This method is called on the first client request, not on instantiation,
so that we can instantiate the client on startup and reuse it across the entire
application."""
try:
self.common_proxy = xmlrpc.client.ServerProxy(f"{self.url}/xmlrpc/2/common")
self.uid = self.common_proxy.authenticate(
self.db, self.username, self.password, {}
)
models = xmlrpc.client.ServerProxy(f"{url}/xmlrpc/2/object")
if not self.uid:
raise Exception("Authentication failed with Odoo: No UID returned.")
# Prepare arguments for execute_kw
# Odoo's execute_kw expects: db, uid, password, model, method, args_list, kwargs_dict
# For 'search_read', args_list typically contains [domain, fields]
# and kwargs_dict contains {'limit': ..., 'offset': ..., 'order': ...}
self.models_proxy = xmlrpc.client.ServerProxy(f"{self.url}/xmlrpc/2/object")
args_list = []
kwargs_dict = {}
except xmlrpc.client.Fault as e:
raise Exception(
f"Odoo XML-RPC Fault during connection: {e.faultString}"
) from e
except ConnectionRefusedError as e:
raise Exception(
f"Could not connect to Odoo at {self.url}. Connection refused."
) from e
except Exception as e:
raise Exception(
f"An error occurred while connecting to Odoo: {str(e)}"
) from e
if method == "search_read":
# Extract domain and fields for positional arguments if present
domain = kwargs.pop("domain", [])
fields = kwargs.pop("fields", [])
args_list = [domain, fields]
# Remaining kwargs are passed as the options dictionary
kwargs_dict = kwargs
else:
# For other methods, we might need a more generic way or specific handling.
# For now, assume kwargs can be passed directly if method is not 'search_read',
# or that they are passed as a list of arguments.
# This part might need refinement based on other Odoo methods used.
# A common pattern is to pass a list of IDs as the first arg for methods like 'read', 'write'.
# If 'args' is explicitly passed in kwargs, use it.
if "args" in kwargs:
args_list = kwargs.pop("args")
# Remaining kwargs are passed as the options dictionary
kwargs_dict = kwargs
def execute(self, model, method, args_list, **kwargs):
if not self.uid or not self.models_proxy:
self._connect()
breakpoint()
result = models.execute_kw(
db, uid, password, model, method, args_list, kwargs_dict
)
return result
try:
result = self.models_proxy.execute_kw(
self.db, self.uid, self.password, model, method, args_list, kwargs
)
return result
except xmlrpc.client.Fault as e:
# Handle XML-RPC specific errors (e.g., Odoo operational errors)
raise Exception(f"Odoo XML-RPC Fault: {e.faultString}") from e
except ConnectionRefusedError as e:
raise Exception(
f"Could not connect to Odoo at {url}. Connection refused."
) from e
except Exception as e:
# General exception handling
raise Exception(
f"An error occurred while communicating with Odoo: {str(e)}"
) from e
except xmlrpc.client.Fault as e:
print(f"Fault! {e}")
raise Exception(f"Odoo XML-RPC Fault: {e.faultString}") from e
except ConnectionRefusedError as e:
raise Exception(
f"Connection to Odoo at {self.url} lost or refused during operation."
) from e
except Exception as e:
print(e)
raise Exception(
f"An error occurred while communicating with Odoo: {str(e)}"
) from e
def search_read(self, model, domain, fields, **kwargs):
return self.execute(model, "search_read", args_list=[domain, fields], **kwargs)
CLIENT = OdooClient()
def get_invoice_addresses(user):