diff --git a/src/servala/core/odoo.py b/src/servala/core/odoo.py index 59635bd..d5a0ad6 100644 --- a/src/servala/core/odoo.py +++ b/src/servala/core/odoo.py @@ -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):