import logging import secrets from odoo import api, fields, models from odoo.exceptions import UserError from ..lib.woo_api_client import WooApiClient _logger = logging.getLogger(__name__) class WooInstance(models.Model): _name = 'woo.instance' _description = 'WooCommerce Instance' _inherit = ['mail.thread'] name = fields.Char(required=True, tracking=True) url = fields.Char(required=True, tracking=True) consumer_key = fields.Char(groups='base.group_system') consumer_secret = fields.Char(groups='base.group_system') webhook_secret = fields.Char(groups='base.group_system') wc_api_version = fields.Char(default='wc/v3') odoo_api_key = fields.Char(groups='base.group_system') company_id = fields.Many2one( 'res.company', required=True, default=lambda self: self.env.company, ) sync_interval = fields.Selection( [('5', '5 Min'), ('15', '15 Min'), ('30', '30 Min'), ('60', '1 Hour')], default='15', ) sync_products = fields.Boolean(default=True) sync_orders = fields.Boolean(default=True) sync_invoices = fields.Boolean(default=True) sync_inventory = fields.Boolean(default=True) sync_customers = fields.Boolean(default=True) default_warehouse_id = fields.Many2one('stock.warehouse') notify_on_failure = fields.Boolean() notify_user_ids = fields.Many2many('res.users') state = fields.Selection( [('draft', 'Draft'), ('connected', 'Connected'), ('error', 'Error')], default='draft', tracking=True, ) last_sync = fields.Datetime(readonly=True) # Relational product_map_ids = fields.One2many('woo.product.map', 'instance_id') order_ids = fields.One2many('woo.order', 'instance_id') customer_ids = fields.One2many('woo.customer', 'instance_id') sync_log_ids = fields.One2many('woo.sync.log', 'instance_id') # Computed mapped_count = fields.Integer(compute='_compute_counts') unmapped_count = fields.Integer(compute='_compute_counts') error_count = fields.Integer(compute='_compute_counts') @api.depends('product_map_ids.state', 'sync_log_ids') def _compute_counts(self): for rec in self: rec.mapped_count = self.env['woo.product.map'].search_count([ ('instance_id', '=', rec.id), ('state', '=', 'mapped'), ]) rec.unmapped_count = self.env['woo.product.map'].search_count([ ('instance_id', '=', rec.id), ('state', '=', 'unmapped'), ]) yesterday = fields.Datetime.subtract(fields.Datetime.now(), hours=24) rec.error_count = self.env['woo.sync.log'].search_count([ ('instance_id', '=', rec.id), ('state', '=', 'failed'), ('create_date', '>=', yesterday), ]) def _get_client(self): """Return a WooApiClient instance for this WooCommerce connection.""" self.ensure_one() if not self.consumer_key or not self.consumer_secret: raise UserError("Consumer key and secret are required.") return WooApiClient( url=self.url, consumer_key=self.consumer_key, consumer_secret=self.consumer_secret, api_version=self.wc_api_version or 'wc/v3', ) def action_test_connection(self): """Test the WooCommerce connection and update state.""" self.ensure_one() try: client = self._get_client() success, info = client.test_connection() if success: self.state = 'connected' self.message_post(body=f"Connection successful. WooCommerce version: {info}") else: self.state = 'error' self.message_post(body=f"Connection failed: {info}") except Exception as exc: self.state = 'error' self.message_post(body=f"Connection error: {exc}") _logger.exception("WooCommerce connection test failed for %s", self.name) def action_generate_api_key(self): """Generate a random API key for the Odoo webhook endpoint.""" self.ensure_one() self.odoo_api_key = secrets.token_urlsafe(32) def _log_sync(self, sync_type, direction, record_ref, state, message=''): """Create a woo.sync.log record for this instance.""" self.ensure_one() self.env['woo.sync.log'].sudo().create({ 'instance_id': self.id, 'sync_type': sync_type, 'direction': direction, 'record_ref': record_ref, 'state': state, 'message': message, 'company_id': self.company_id.id, })