fix: serve variant images via custom endpoint instead of product URL

Product image URL was serving placeholder because writing to image_1920
doesn't work for variants (computed field). New approach:
1. Store image in wizard line table (attachment=False, bytea column)
2. Serve directly via /woo/image/{line_id}/{filename} endpoint
3. WC downloads real image data from this URL
4. Also saves to image_variant_1920 for Odoo reference

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-04-01 21:53:41 -04:00
parent 88305a4ce0
commit 1a679a45c3
2 changed files with 30 additions and 18 deletions

View File

@@ -2,11 +2,12 @@
# Copyright 2026 Nexa Systems Inc. # Copyright 2026 Nexa Systems Inc.
# License OPL-1 (Odoo Proprietary License v1.0) # License OPL-1 (Odoo Proprietary License v1.0)
import base64
import logging import logging
from odoo import http from odoo import http
from odoo.exceptions import AccessDenied from odoo.exceptions import AccessDenied
from odoo.http import request from odoo.http import request, Response
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@@ -14,6 +15,28 @@ _logger = logging.getLogger(__name__)
class WooApiController(http.Controller): class WooApiController(http.Controller):
"""REST endpoints consumed by the WooCommerce WordPress plugin.""" """REST endpoints consumed by the WooCommerce WordPress plugin."""
@http.route('/woo/image/<int:line_id>/<string:filename>',
type='http', auth='none', csrf=False, methods=['GET'])
def serve_variant_image(self, line_id, filename, **kw):
"""Serve a variant image from the transient wizard line.
Used by WC to download images during variant push."""
try:
line = request.env['woo.variant.push.line'].sudo().browse(line_id)
if not line.exists() or not line.image:
return request.not_found()
img_data = line.image
if isinstance(img_data, str):
img_data = base64.b64decode(img_data)
elif isinstance(img_data, memoryview):
img_data = bytes(img_data)
content_type = 'image/png'
if filename.lower().endswith('.jpg') or filename.lower().endswith('.jpeg'):
content_type = 'image/jpeg'
return Response(img_data, content_type=content_type, status=200)
except Exception as e:
_logger.error("Failed to serve variant image %d: %s", line_id, e)
return request.not_found()
def _authenticate_instance(self): def _authenticate_instance(self):
""" """
Validate Bearer token from Authorization header against woo.instance.odoo_api_key. Validate Bearer token from Authorization header against woo.instance.odoo_api_key.

View File

@@ -248,33 +248,22 @@ class WooVariantPushWizard(models.TransientModel):
if wc_tax_class: if wc_tax_class:
var_data['tax_class'] = wc_tax_class var_data['tax_class'] = wc_tax_class
# Save wizard image to Odoo product, then pass URL to WC # Serve image directly from wizard line via custom endpoint
if line.image: if line.image:
img_data = line.image # Commit the line data so the image endpoint can read it
img_size = len(img_data) if img_data else 0 self.env.cr.commit()
_logger.info("Variant %d image data: type=%s size=%d", variant.id, type(img_data).__name__, img_size)
# Save the image from the wizard to the actual Odoo product
if img_size > 100: # Skip tiny placeholders
variant.sudo().write({'image_1920': img_data})
self.env.cr.commit() # Force commit so the image is available for download
_logger.info("Saved image to Odoo product %d (%d bytes)", variant.id, img_size)
else:
_logger.warning("Skipping tiny image for variant %d (%d bytes)", variant.id, img_size)
# Now build the public URL for WC to download
odoo_base = inst.env['ir.config_parameter'].sudo().get_param('web.base.url', '') odoo_base = inst.env['ir.config_parameter'].sudo().get_param('web.base.url', '')
if odoo_base: if odoo_base:
img_name = (line.sku or variant.default_code or 'variant') + '.png' img_name = (line.sku or variant.default_code or 'variant') + '.png'
# Add timestamp to bust WC cache img_url = f"{odoo_base}/woo/image/{line.id}/{img_name}"
import time
cache_bust = int(time.time())
img_url = f"{odoo_base}/web/image/product.product/{variant.id}/image_1920/{img_name}?t={cache_bust}"
var_data['image'] = { var_data['image'] = {
'src': img_url, 'src': img_url,
'name': img_name, 'name': img_name,
'alt': line.variant_name or '', 'alt': line.variant_name or '',
} }
_logger.info("Variant image URL: %s", img_url) _logger.info("Variant image URL: %s", img_url)
# Also save to Odoo product for future reference
variant.sudo().write({'image_variant_1920': line.image})
try: try:
client.update_product_variation(pm.woo_product_id, wc_var_id, var_data) client.update_product_variation(pm.woo_product_id, wc_var_id, var_data)