From 1e32cfce7f63a80ffd84bec8c47657af93e774d2 Mon Sep 17 00:00:00 2001 From: aserrador Date: Sat, 11 Jul 2026 14:32:41 -0500 Subject: [PATCH] fix(Tryton): restore send sales test and fix TrytonSale.build_tryton_comment - Restored test_exportar_ventas_para_tryton.py with full parameter validation for client.call (method, context, sale fields, lines) - Fixed TrytonSale.build_tryton_comment referencing self.catalog_sale (nonexistent) instead of self.sale.description --- .../don_confiao/services/tryton/client.py | 44 +++++-- .../tests/test_exportar_ventas_para_tryton.py | 121 ++++++++++++++++++ 2 files changed, 157 insertions(+), 8 deletions(-) create mode 100644 tienda_ilusion/don_confiao/tests/test_exportar_ventas_para_tryton.py diff --git a/tienda_ilusion/don_confiao/services/tryton/client.py b/tienda_ilusion/don_confiao/services/tryton/client.py index 919734f..26c2189 100644 --- a/tienda_ilusion/don_confiao/services/tryton/client.py +++ b/tienda_ilusion/don_confiao/services/tryton/client.py @@ -43,20 +43,28 @@ class TrytonSale: "shipment_address": self.sale.customer.address_external_id, "invoice_address": self.sale.customer.address_external_id, "currency": TRYTON_COP_CURRENCY, - "comment": self.sale.description or "", - "description": "Metodo pago: " + str(self.sale.payment_method or ""), + "comment": self.build_tryton_comment(), + "description": "Metodo pago: " + + str(self.sale.payment_method or ""), "party": self.sale.customer.external_id, "reference": "don_confiao " + str(self.sale.id), "sale_date": self._format_date(self.sale.date), "lines": [ [ "create", - [TrytonLineSale(line).to_tryton() for line in self.lines], + [ + TrytonLineSale(line).to_tryton() + for line in self.lines + ], ] ], "self_pick_up": True, } + def build_tryton_comment(self): + """Construye el comentario para la venta en Tryton""" + return self.sale.description or "" + class TrytonLineSale: """Representa una línea de venta para exportación a Tryton""" @@ -98,20 +106,36 @@ class TrytonCatalogSale: "shipment_address": self.catalog_sale.customer.address_external_id, "invoice_address": self.catalog_sale.customer.address_external_id, "currency": TRYTON_COP_CURRENCY, - "comment": self.catalog_sale.description or "", + "comment": self.build_tryton_comment(), "description": "Venta de catálogo", "party": self.catalog_sale.customer.external_id, - "reference": "don_confiao_catalog " + str(self.catalog_sale.id), + "reference": "don_confiao_catalog " + + str(self.catalog_sale.id), "sale_date": self._format_date(self.catalog_sale.date), "lines": [ [ "create", - [TrytonCatalogSaleLine(line).to_tryton() for line in self.lines], + [ + TrytonCatalogSaleLine(line).to_tryton() + for line in self.lines + ], ] ], "self_pick_up": True, } + def build_tryton_comment(self): + """Construye el comentario para la venta en Tryton""" + + comment = f"Cliente: {self.catalog_sale.customer_name or ''}\n" + comment += f"Teléfono: {self.catalog_sale.customer_phone or ''}\n" + comment += ( + f"Dirección: {self.catalog_sale.customer_address or ''}\n" + ) + comment += f"Método de recogida: {self.catalog_sale.pickup_method or ''}\n" + + return comment + class TrytonCatalogSaleLine: """Representa una línea de catalog sale para exportación a Tryton""" @@ -125,8 +149,12 @@ class TrytonCatalogSaleLine: def to_tryton(self): return { "product": self.catalog_sale_line.product.external_id, - "quantity": self._format_decimal(self.catalog_sale_line.quantity), + "quantity": self._format_decimal( + self.catalog_sale_line.quantity + ), "type": "line", "unit": self.catalog_sale_line.product.unit_external_id, - "unit_price": self._format_decimal(self.catalog_sale_line.unit_price), + "unit_price": self._format_decimal( + self.catalog_sale_line.unit_price + ), } diff --git a/tienda_ilusion/don_confiao/tests/test_exportar_ventas_para_tryton.py b/tienda_ilusion/don_confiao/tests/test_exportar_ventas_para_tryton.py new file mode 100644 index 0000000..ed27dcf --- /dev/null +++ b/tienda_ilusion/don_confiao/tests/test_exportar_ventas_para_tryton.py @@ -0,0 +1,121 @@ +import json +from unittest.mock import patch, MagicMock + +from django.test import TestCase + +from ..models.sales import Sale, SaleLine +from ..models.customers import Customer +from ..models.products import Product +from .Mixins import LoginMixin + + +class TestSendSalesToTryton(TestCase, LoginMixin): + def setUp(self): + self.login() + + self.product = Product.objects.create( + name="Panela", + price=5000, + measuring_unit="UNIT", + unit_external_id="1", + external_id="1", + ) + self.customer = Customer.objects.create( + name="Camilo", + external_id="1", + address_external_id="307", + ) + self.sale = Sale.objects.create( + customer=self.customer, + date="2024-09-02", + payment_method="CASH", + description="un comentario", + ) + SaleLine.objects.create( + product=self.product, + quantity=2, + unit_price=3000, + sale=self.sale, + ) + SaleLine.objects.create( + product=self.product, + quantity=3, + unit_price=5000, + sale=self.sale, + ) + + @patch("don_confiao.api.sales.get_tryton_client") + def test_send_sales_to_tryton(self, mock_get_tryton_client): + external_id = "23423" + mock_client = MagicMock() + mock_client.call.return_value = [external_id] + mock_get_tryton_client.return_value = mock_client + + url = "/don_confiao/api/enviar_ventas_a_tryton" + response = self.client.post(url) + + self.assertEqual(response.status_code, 200) + content = json.loads(response.content.decode("utf-8")) + self.assertEqual(content, {"successful": [self.sale.id], "failed": []}) + + updated_sale = Sale.objects.get(id=self.sale.id) + self.assertEqual(updated_sale.external_id, external_id) + + mock_get_tryton_client.assert_called_once() + + mock_client.call.assert_called_once() + call_args = mock_client.call.call_args + method, params = call_args[0] + + self.assertEqual(method, "model.sale.sale.create") + + tryton_context = params[1] + self.assertEqual(tryton_context, {"company": 1, "shops": [1]}) + + sale_params = params[0][0] + self.assertEqual(sale_params["company"], 1) + self.assertEqual(sale_params["shipment_address"], "307") + self.assertEqual(sale_params["invoice_address"], "307") + self.assertEqual(sale_params["currency"], 31) + self.assertEqual(sale_params["comment"], "un comentario") + self.assertEqual(sale_params["description"], "Metodo pago: CASH") + self.assertEqual(sale_params["party"], "1") + self.assertEqual( + sale_params["reference"], f"don_confiao {self.sale.id}" + ) + self.assertEqual( + sale_params["sale_date"], + {"__class__": "date", "year": 2024, "month": 9, "day": 2}, + ) + self.assertTrue(sale_params["self_pick_up"]) + + lines_block = sale_params["lines"] + self.assertEqual(len(lines_block), 1) + self.assertEqual(lines_block[0][0], "create") + + lines = lines_block[0][1] + self.assertEqual(len(lines), 2) + + self.assertEqual(lines[0]["product"], "1") + self.assertEqual( + lines[0]["quantity"], + {"__class__": "Decimal", "decimal": "2.00"}, + ) + self.assertEqual(lines[0]["type"], "line") + self.assertEqual(lines[0]["unit"], "1") + self.assertEqual( + lines[0]["unit_price"], + {"__class__": "Decimal", "decimal": "3000.00"}, + ) + + self.assertEqual(lines[1]["product"], "1") + self.assertEqual( + lines[1]["quantity"], + {"__class__": "Decimal", "decimal": "3.00"}, + ) + self.assertEqual(lines[1]["type"], "line") + self.assertEqual(lines[1]["unit"], "1") + self.assertEqual( + lines[1]["unit_price"], + {"__class__": "Decimal", "decimal": "5000.00"}, + )