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", "phone",
"vat", "vat",
"company_type", "company_type",
"type",
] ]
def odoo_request(model, method, **kwargs): class OdooClient:
url = settings.ODOO["URL"] def __init__(self):
db = settings.ODOO["DB"] self.url = settings.ODOO["URL"]
username = settings.ODOO["USERNAME"] self.db = settings.ODOO["DB"]
password = settings.ODOO["PASSWORD"] self.username = settings.ODOO["USERNAME"]
self.password = settings.ODOO["PASSWORD"]
try: self.common_proxy = None
common = xmlrpc.client.ServerProxy(f"{url}/xmlrpc/2/common") self.models_proxy = None
uid = common.authenticate(db, username, password, {}) self.uid = None
if not uid: def _connect(self):
raise Exception("Authentication failed with Odoo.") """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 self.models_proxy = xmlrpc.client.ServerProxy(f"{self.url}/xmlrpc/2/object")
# 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': ...}
args_list = [] except xmlrpc.client.Fault as e:
kwargs_dict = {} 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": def execute(self, model, method, args_list, **kwargs):
# Extract domain and fields for positional arguments if present if not self.uid or not self.models_proxy:
domain = kwargs.pop("domain", []) self._connect()
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
breakpoint() try:
result = models.execute_kw( result = self.models_proxy.execute_kw(
db, uid, password, model, method, args_list, kwargs_dict self.db, self.uid, self.password, model, method, args_list, kwargs
) )
return result return result
except xmlrpc.client.Fault as e: except xmlrpc.client.Fault as e:
# Handle XML-RPC specific errors (e.g., Odoo operational errors) print(f"Fault! {e}")
raise Exception(f"Odoo XML-RPC Fault: {e.faultString}") from e raise Exception(f"Odoo XML-RPC Fault: {e.faultString}") from e
except ConnectionRefusedError as e: except ConnectionRefusedError as e:
raise Exception( raise Exception(
f"Could not connect to Odoo at {url}. Connection refused." f"Connection to Odoo at {self.url} lost or refused during operation."
) from e ) from e
except Exception as e: except Exception as e:
# General exception handling print(e)
raise Exception( raise Exception(
f"An error occurred while communicating with Odoo: {str(e)}" f"An error occurred while communicating with Odoo: {str(e)}"
) from 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): def get_invoice_addresses(user):