feat: clickable WooCommerce product links in mapping UI

Product names in the mapped table are now links that open the WC product
page in a new tab. Added woo_permalink field, stored during fetch,
returned by search endpoint.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-03-31 23:06:27 -04:00
parent 0e84b97c89
commit b1e4ed5ec8
5 changed files with 32 additions and 1 deletions

View File

@@ -153,6 +153,7 @@ class WooProductSearchController(http.Controller):
'woo_product_name': m.woo_product_name or '', 'woo_product_name': m.woo_product_name or '',
'woo_sku': m.woo_sku or '', 'woo_sku': m.woo_sku or '',
'woo_product_type': m.woo_product_type or '', 'woo_product_type': m.woo_product_type or '',
'woo_permalink': m.woo_permalink or '',
'odoo_product_id': m.product_id.id if m.product_id else False, 'odoo_product_id': m.product_id.id if m.product_id else False,
'odoo_product_name': m.product_id.name if m.product_id else '', 'odoo_product_name': m.product_id.name if m.product_id else '',
'odoo_default_code': m.product_id.default_code or '' if m.product_id else '', 'odoo_default_code': m.product_id.default_code or '' if m.product_id else '',

View File

@@ -202,6 +202,8 @@ class WooInstance(models.Model):
except (ValueError, TypeError): except (ValueError, TypeError):
pass pass
wc_permalink = wc_prod.get('permalink', '')
ProductMap.create({ ProductMap.create({
'instance_id': self.id, 'instance_id': self.id,
'product_id': odoo_product.id if odoo_product else False, 'product_id': odoo_product.id if odoo_product else False,
@@ -209,6 +211,7 @@ class WooInstance(models.Model):
'woo_product_name': wc_name, 'woo_product_name': wc_name,
'woo_sku': wc_sku, 'woo_sku': wc_sku,
'woo_price': wc_price, 'woo_price': wc_price,
'woo_permalink': wc_permalink,
'woo_product_type': wc_type if wc_type in ('simple', 'variable', 'grouped', 'external') else 'simple', 'woo_product_type': wc_type if wc_type in ('simple', 'variable', 'grouped', 'external') else 'simple',
'state': match_state, 'state': match_state,
'company_id': self.company_id.id, 'company_id': self.company_id.id,

View File

@@ -26,6 +26,7 @@ class WooProductMap(models.Model):
('external', 'External'), ('external', 'External'),
]) ])
woo_price = fields.Float(string='WC Price', digits='Product Price') woo_price = fields.Float(string='WC Price', digits='Product Price')
woo_permalink = fields.Char(string='WC Product URL')
woo_parent_id = fields.Integer() woo_parent_id = fields.Integer()
is_variation = fields.Boolean() is_variation = fields.Boolean()
sync_price = fields.Boolean(default=True) sync_price = fields.Boolean(default=True)

View File

@@ -587,6 +587,24 @@ html[style*="color-scheme: dark"] {
color: var(--woo-accent); color: var(--woo-accent);
background: var(--woo-bg-hover); background: var(--woo-bg-hover);
} }
/* Product link to WooCommerce */
.woo-product-link {
color: var(--woo-accent);
text-decoration: none;
transition: color 0.15s;
}
.woo-product-link:hover {
color: var(--woo-accent-hover);
text-decoration: underline;
}
.woo-external-icon {
font-size: 0.7rem;
opacity: 0.5;
}
.woo-product-link:hover .woo-external-icon {
opacity: 1;
}
.woo-price-sync-col { .woo-price-sync-col {
width: 60px; width: 60px;
white-space: nowrap; white-space: nowrap;

View File

@@ -156,7 +156,15 @@
t-att-checked="isMappedSelected(p.id)" t-att-checked="isMappedSelected(p.id)"
t-on-change="() => this.toggleSelectMapped(p.id)"/> t-on-change="() => this.toggleSelectMapped(p.id)"/>
</td> </td>
<td><t t-esc="p.woo_product_name"/></td> <td>
<t t-if="p.woo_permalink">
<a t-att-href="p.woo_permalink" target="_blank" class="woo-product-link">
<t t-esc="p.woo_product_name"/>
<i class="fa fa-external-link ms-1 woo-external-icon"/>
</a>
</t>
<t t-else=""><t t-esc="p.woo_product_name"/></t>
</td>
<td><span class="woo-code"><t t-esc="p.woo_sku"/></span></td> <td><span class="woo-code"><t t-esc="p.woo_sku"/></span></td>
<td><t t-esc="p.odoo_product_name"/></td> <td><t t-esc="p.odoo_product_name"/></td>
<td class="text-end" t-esc="this.formatPrice(p.woo_price)"/> <td class="text-end" t-esc="this.formatPrice(p.woo_price)"/>