#51 fix: detectar cambios de categorias al sincronizar productos

Issue #51: discriminacion y administracion de categorias de productos.

- _need_update compara las categorias (external_id) local vs Tryton
- _describe_changes reporta categorias agregadas (+Nombre) y removidas (-Nombre)
- Actualiza test que asumia asignacion de categorias sin marcar update
This commit is contained in:
2026-10-10 16:33:18 -05:00
parent 570fec0532
commit c0dcb7901a
2 changed files with 166 additions and 4 deletions

View File

@@ -214,8 +214,50 @@ class ProductTrytonService:
changes.append(
f"Unidad: {product.measuring_unit} → {unit_name}"
)
category_changes = self._describe_category_changes(
product, tryton_product
)
if category_changes:
changes.append(category_changes)
return ", ".join(changes)
def _describe_category_changes(self, product, tryton_product):
"""Describe los cambios de categorías entre el producto local y Tryton"""
tryton_ids = set(
str(category_id)
for category_id in self._extract_category_ids(tryton_product)
)
local = {
external_id: name
for external_id, name in product.categories.values_list(
"external_id", "name"
)
if external_id
}
local_ids = set(local)
added = sorted(tryton_ids - local_ids)
removed = sorted(local_ids - tryton_ids)
if not added and not removed:
return ""
parts = []
if added:
names = {}
for external_id in added:
category = (
ProductCategory.objects.filter(
external_id=external_id
)
.values_list("name", flat=True)
.first()
)
names[external_id] = category or external_id
parts.append(", ".join(f"+{names[e]}" for e in added))
if removed:
parts.append(", ".join(f"-{local[e]}" for e in removed))
return f"Categoría: {', '.join(parts)}"
@staticmethod
def _format_price(value):
"""Formatea un precio sin ceros decimales innecesarios"""
@@ -269,6 +311,17 @@ class ProductTrytonService:
unit = tryton_product.get("default_uom.")
if not product.measuring_unit == unit.get("rec_name"):
return True
tryton_category_ids = set(
str(category_id)
for category_id in self._extract_category_ids(tryton_product)
)
local_category_ids = set(
product.categories.exclude(
external_id__isnull=True
).values_list("external_id", flat=True)
)
if tryton_category_ids != local_category_ids:
return True
return False
def _create_product(self, tryton_product):