#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

@@ -661,7 +661,7 @@ class TestProductsFromTryton(TestCase, LoginMixin):
@patch("sabatron_tryton_rpc_client.client.Client.call")
@patch("sabatron_tryton_rpc_client.client.Client.connect")
def test_import_assigns_categories_to_untouched_products(
def test_import_assigns_categories_marks_product_as_updated(
self, mock_connect, mock_call
):
mock_connect.return_value = None
@@ -724,12 +724,20 @@ class TestProductsFromTryton(TestCase, LoginMixin):
self.assertEqual(response.status_code, 200)
content = json.loads(response.content.decode("utf-8"))
self.assertEqual(content["untouched_products"], [])
self.assertEqual(
content["untouched_products"], [{"id": 2, "name": "Papa"}]
content["updated_products"],
[
{
"id": 2,
"name": "Papa",
"detail": "Categoría: +Tubérculos",
}
],
)
untouched_product = Product.objects.get(id=2)
categories = untouched_product.categories.all()
updated_product = Product.objects.get(id=2)
categories = updated_product.categories.all()
self.assertEqual(len(categories), 1)
self.assertEqual(categories[0].name, "Tubérculos")
self.assertEqual(categories[0].external_id, "9")
@@ -744,3 +752,104 @@ class TestProductsFromTryton(TestCase, LoginMixin):
}
],
)
@patch("sabatron_tryton_rpc_client.client.Client.call")
@patch("sabatron_tryton_rpc_client.client.Client.connect")
def test_category_change_marks_product_as_updated(
self, mock_connect, mock_call
):
mock_connect.return_value = None
local_abarrotes = ProductCategory.objects.create(
name="Abarrotes", external_id="5"
)
self.product2.categories.add(local_abarrotes)
def fake_call(*args, **kwargs):
product_search = "model.product.product.search"
search_args = [
[["salable", "=", True]],
0,
1000,
[["rec_name", "ASC"], ["id", None]],
{"company": 1},
]
if args == (product_search, search_args):
return [192]
product_read = "model.product.product.read"
product_args = (
[192],
[
"id",
"name",
"default_uom.id",
"default_uom.rec_name",
"list_price",
"template.categories",
],
{"company": 1},
)
if args == (product_read, product_args):
return [
{
"id": 192,
"list_price": Decimal("4500"),
"name": "Papa",
"default_uom.": {"id": 2, "rec_name": "Kilogram"},
"template.": {"id": 999, "categories": [8]},
},
]
category_read = "model.product.category.read"
category_args = (
[8],
["id", "name"],
{"company": 1},
)
if args == (category_read, category_args):
return [
{"id": 8, "name": "Bebidas"},
]
raise Exception(
f"Sorry, args non expected on this test: {args}"
)
mock_call.side_effect = fake_call
url = "/don_confiao/api/importar_productos_de_tryton"
response = self.client.post(url)
self.assertEqual(response.status_code, 200)
content = json.loads(response.content.decode("utf-8"))
self.assertEqual(content["untouched_products"], [])
self.assertEqual(content["failed_products"], [])
self.assertEqual(
content["updated_products"],
[
{
"id": self.product2.pk,
"name": "Papa",
"detail": "Categoría: +Bebidas, -Abarrotes",
}
],
)
self.assertEqual(
content["created_categories"],
[
{
"id": ProductCategory.objects.get(
external_id="8"
).pk,
"name": "Bebidas",
"external_id": "8",
}
],
)
refreshed_product = Product.objects.get(pk=self.product2.pk)
categories = list(refreshed_product.categories.all())
self.assertEqual(
[(c.external_id, c.name) for c in categories],
[("8", "Bebidas")],
)