From ab16040eb4f5da13d4af0e9d694f08eca0fc03b6 Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Tue, 31 Mar 2026 22:28:35 -0400 Subject: [PATCH] fix: add missing action_fetch_products and action_sync methods Product mapping UI called these methods but they didn't exist on woo.instance. action_fetch_products fetches WC products via API, auto-matches by SKU, handles variations. action_sync runs all enabled sync types manually. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../fusion_woocommerce/models/woo_instance.py | 140 ++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/fusion-woo-odoo/fusion_woocommerce/models/woo_instance.py b/fusion-woo-odoo/fusion_woocommerce/models/woo_instance.py index 9415c466..8919a583 100644 --- a/fusion-woo-odoo/fusion_woocommerce/models/woo_instance.py +++ b/fusion-woo-odoo/fusion_woocommerce/models/woo_instance.py @@ -147,6 +147,146 @@ class WooInstance(models.Model): 'company_id': self.company_id.id, }) + # ------------------------------------------------------------------ + # UI actions (called from OWL product mapping + dashboard) + # ------------------------------------------------------------------ + + def action_fetch_products(self): + """Fetch products from WooCommerce and run auto-match.""" + self.ensure_one() + if self.state != 'connected': + raise UserError("Please test the connection first.") + client = self._get_client() + ProductMap = self.env['woo.product.map'] + page = 1 + total_fetched = 0 + auto_matched = 0 + + while True: + try: + products = client.get_products(page=page, per_page=100) + except Exception as e: + self._log_sync('product', 'woo_to_odoo', self.name, 'failed', str(e)) + raise UserError("Failed to fetch products: %s" % str(e)) + if not products: + break + + for wc_prod in products: + wc_id = wc_prod.get('id') + # Skip if already mapped + existing = ProductMap.search([ + ('instance_id', '=', self.id), + ('woo_product_id', '=', wc_id), + ], limit=1) + if existing: + continue + + wc_sku = wc_prod.get('sku', '') or '' + wc_name = wc_prod.get('name', '') + wc_type = wc_prod.get('type', 'simple') + + # Try SKU match + odoo_product = False + match_state = 'unmapped' + if wc_sku: + odoo_product = self.env['product.product'].search([ + ('default_code', '=', wc_sku), + ], limit=1) + if odoo_product: + match_state = 'mapped' + auto_matched += 1 + + ProductMap.create({ + 'instance_id': self.id, + 'product_id': odoo_product.id if odoo_product else False, + 'woo_product_id': wc_id, + 'woo_product_name': wc_name, + 'woo_sku': wc_sku, + 'woo_product_type': wc_type if wc_type in ('simple', 'variable', 'grouped', 'external') else 'simple', + 'state': match_state, + 'company_id': self.company_id.id, + }) + total_fetched += 1 + + # Fetch variations for variable products + if wc_type == 'variable': + try: + var_page = 1 + while True: + variations = client.get_product_variations(wc_id, page=var_page, per_page=100) + if not variations: + break + for var in variations: + var_id = var.get('id') + var_existing = ProductMap.search([ + ('instance_id', '=', self.id), + ('woo_product_id', '=', var_id), + ], limit=1) + if var_existing: + continue + + var_sku = var.get('sku', '') or '' + var_name = wc_name + ' - ' + ', '.join( + [a.get('option', '') for a in var.get('attributes', [])] + ) + var_product = False + var_state = 'unmapped' + if var_sku: + var_product = self.env['product.product'].search([ + ('default_code', '=', var_sku), + ], limit=1) + if var_product: + var_state = 'mapped' + auto_matched += 1 + + ProductMap.create({ + 'instance_id': self.id, + 'product_id': var_product.id if var_product else False, + 'woo_product_id': var_id, + 'woo_product_name': var_name, + 'woo_sku': var_sku, + 'woo_product_type': 'simple', + 'woo_parent_id': wc_id, + 'is_variation': True, + 'state': var_state, + 'company_id': self.company_id.id, + }) + total_fetched += 1 + var_page += 1 + if len(variations) < 100: + break + except Exception: + _logger.warning("Failed to fetch variations for product %s", wc_id) + + page += 1 + if len(products) < 100: + break + + self._log_sync('product', 'woo_to_odoo', self.name, 'success', + 'Fetched %d products, auto-matched %d by SKU' % (total_fetched, auto_matched)) + return True + + def action_sync(self): + """Manual sync trigger from the UI.""" + self.ensure_one() + if self.state != 'connected': + raise UserError("Instance is not connected.") + try: + if self.sync_products: + self._sync_products() + if self.sync_orders: + self._sync_orders() + if self.sync_inventory: + self._sync_inventory() + if self.sync_customers: + self._sync_customers() + self.last_sync = fields.Datetime.now() + except Exception as e: + _logger.error("Manual sync failed for %s: %s", self.name, str(e)) + self._log_sync('product', 'odoo_to_woo', self.name, 'failed', str(e)) + raise UserError("Sync failed: %s" % str(e)) + return True + # ------------------------------------------------------------------ # Cron entry points # ------------------------------------------------------------------