From 3ea283247afab1e3db066774cd681bc50bd4c509 Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Tue, 31 Mar 2026 22:35:13 -0400 Subject: [PATCH] feat: add Refresh Prices button to pull WC prices for existing mappings Existing mapped products had no WC price since they were fetched before the woo_price field existed. action_refresh_prices fetches current prices from WC API for all mapped products. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../fusion_woocommerce/models/woo_instance.py | 28 +++++++++++++++++++ .../static/src/js/product_mapping.js | 23 +++++++++++++++ .../static/src/xml/product_mapping.xml | 4 +++ 3 files changed, 55 insertions(+) diff --git a/fusion-woo-odoo/fusion_woocommerce/models/woo_instance.py b/fusion-woo-odoo/fusion_woocommerce/models/woo_instance.py index bd0c8387..daeccd90 100644 --- a/fusion-woo-odoo/fusion_woocommerce/models/woo_instance.py +++ b/fusion-woo-odoo/fusion_woocommerce/models/woo_instance.py @@ -280,6 +280,34 @@ class WooInstance(models.Model): 'Fetched %d products, auto-matched %d by SKU' % (total_fetched, auto_matched)) return True + def action_refresh_prices(self): + """Refresh WC prices for all mapped products from WooCommerce API.""" + self.ensure_one() + if self.state != 'connected': + raise UserError("Instance is not connected.") + client = self._get_client() + maps = self.env['woo.product.map'].search([ + ('instance_id', '=', self.id), + ('woo_product_id', '>', 0), + ]) + updated = 0 + for m in maps: + try: + wc_prod = client.get_product(m.woo_product_id) + wc_price = 0.0 + try: + wc_price = float(wc_prod.get('regular_price') or wc_prod.get('price') or 0) + except (ValueError, TypeError): + pass + if wc_price != m.woo_price: + m.woo_price = wc_price + updated += 1 + except Exception as e: + _logger.warning("Failed to refresh price for WC#%s: %s", m.woo_product_id, e) + self._log_sync('product', 'woo_to_odoo', self.name, 'success', + 'Refreshed prices for %d products' % updated) + return True + def action_sync(self): """Manual sync trigger from the UI.""" self.ensure_one() diff --git a/fusion-woo-odoo/fusion_woocommerce/static/src/js/product_mapping.js b/fusion-woo-odoo/fusion_woocommerce/static/src/js/product_mapping.js index 789025fb..d11d7e97 100644 --- a/fusion-woo-odoo/fusion_woocommerce/static/src/js/product_mapping.js +++ b/fusion-woo-odoo/fusion_woocommerce/static/src/js/product_mapping.js @@ -426,6 +426,29 @@ export class ProductMapping extends Component { } } + async refreshPrices() { + if (!this.state.instanceId) { + this.notification.add("Please select an instance first.", { type: "warning" }); + return; + } + try { + this.state.loading = true; + await rpc("/web/dataset/call_kw", { + model: "woo.instance", + method: "action_refresh_prices", + args: [[this.state.instanceId]], + kwargs: {}, + }); + this.notification.add("Prices refreshed from WooCommerce.", { type: "success" }); + await this._refreshAll(); + } catch (err) { + console.error("[ProductMapping] refreshPrices error:", err); + this.notification.add("Failed to refresh prices.", { type: "danger" }); + } finally { + this.state.loading = false; + } + } + async syncNow() { if (!this.state.instanceId) { this.notification.add("Please select an instance first.", { type: "warning" }); diff --git a/fusion-woo-odoo/fusion_woocommerce/static/src/xml/product_mapping.xml b/fusion-woo-odoo/fusion_woocommerce/static/src/xml/product_mapping.xml index d8941005..212e5380 100644 --- a/fusion-woo-odoo/fusion_woocommerce/static/src/xml/product_mapping.xml +++ b/fusion-woo-odoo/fusion_woocommerce/static/src/xml/product_mapping.xml @@ -44,6 +44,10 @@ t-att-disabled="state.loading"> Sync Now +