FIX: Prevent duplicate inventory deductions in Shopify exchanges by removing grouping by product title. Group strictly by SKU or Variant ID to ensure size variants are handled accurately.

This commit is contained in:
2026-07-02 15:27:23 -06:00
parent d7350aaa8b
commit a2908167e6
@@ -2908,9 +2908,7 @@ class ShopifyConfig(models.Model):
if not product: if not product:
variant_id = str(item.get('variant_id') or '') variant_id = str(item.get('variant_id') or '')
product = self.env['product.product'].search([('shopify_variant_id', '=', variant_id)], limit=1) product = self.env['product.product'].search([('shopify_variant_id', '=', variant_id)], limit=1)
if not product:
item_title = item.get('title')
product = self.env['product.product'].search([('name', 'ilike', item_title)], limit=1) if item_title else False
# ── ALERTA 3: Producto no encontrado en Odoo ── # ── ALERTA 3: Producto no encontrado en Odoo ──
if not product: if not product:
@@ -2959,23 +2957,36 @@ class ShopifyConfig(models.Model):
except Exception as e: except Exception as e:
_logger.error("[Shopify BOPIS] Error al crear traspaso interno automático para artículo de cambio en '%s': %s", existing.name, str(e)) _logger.error("[Shopify BOPIS] Error al crear traspaso interno automático para artículo de cambio en '%s': %s", existing.name, str(e))
else: else:
# Si ya existe el artículo, validamos si cambió la cantidad en Shopify para actualizarla (Estilo Conectores Pro) # Si ya existe el artículo, validamos si cambió la cantidad total en Shopify para actualizarla.
qty = float(item.get('quantity', 1)) # BUGFIX: Shopify manda líneas separadas para cambios (exchanges) del mismo producto.
# Sumamos la cantidad total de este producto en todo el payload de Shopify.
total_shopify_qty = 0
for si in s_order.get('line_items', []):
si_sku = si.get('sku')
si_vid = str(si.get('variant_id') or '')
if (si_sku and si_sku == product.default_code) or \
(si_vid and si_vid == product.shopify_variant_id):
total_shopify_qty += float(si.get('quantity', 1))
total_odoo_qty = sum(existing_line.mapped('product_uom_qty'))
# Solo actualizamos si la cantidad difiere y el pedido en Odoo no está en estado borrador (draft) donde se sobreescribiría de todos modos # Solo actualizamos si la cantidad difiere y el pedido en Odoo no está en estado borrador (draft) donde se sobreescribiría de todos modos
if existing_line.product_uom_qty != qty: if total_odoo_qty != total_shopify_qty:
old_qty = existing_line.product_uom_qty old_qty = total_odoo_qty
_logger.info( _logger.info(
"[Shopify Edit] Detectada actualización de cantidad para %s en Shopify %s: %s%s. " "[Shopify Edit] Detectada actualización de cantidad para %s en Shopify %s: %s%s. "
"Actualizando en Odoo %s.", "Actualizando en Odoo %s.",
product.name, order_name, old_qty, qty, existing.name product.name, order_name, old_qty, total_shopify_qty, existing.name
) )
existing_line.write({'product_uom_qty': qty}) # Absorbemos la diferencia en la primera línea encontrada
new_line_qty = existing_line[0].product_uom_qty + (total_shopify_qty - total_odoo_qty)
existing_line[0].write({'product_uom_qty': new_line_qty})
# ── Actualizar traslado interno (BOPIS) si es pedido de retiro ── # ── Actualizar traslado interno (BOPIS) si es pedido de retiro ──
ship_title_update = (existing.shopify_shipping_title or '').upper() ship_title_update = (existing.shopify_shipping_title or '').upper()
if any(x in ship_title_update for x in ['OFICINA', 'RETIRO', 'PICKUP', 'SUCURSAL', 'TIENDA']): if any(x in ship_title_update for x in ['OFICINA', 'RETIRO', 'PICKUP', 'SUCURSAL', 'TIENDA']):
try: try:
existing._update_pickup_internal_transfer_qty(product, old_qty, qty) existing._update_pickup_internal_transfer_qty(product, old_qty, total_shopify_qty)
except Exception as e: except Exception as e:
_logger.error( _logger.error(
"[Shopify BOPIS Qty] Error al actualizar traslado interno para '%s' producto %s: %s", "[Shopify BOPIS Qty] Error al actualizar traslado interno para '%s' producto %s: %s",