Add Tryton synchronization for CatalogSale

- Add external_id field to CatalogSale model for tracking synced sales
- Create migration 0047 for external_id field
- Add TrytonCatalogSale and TrytonCatalogSaleLine classes for Tryton RPC format
- Add send_catalog_sales_to_tryton() method to SaleTrytonService
- Create CatalogSalesToTrytonView API endpoint (POST)
- Register endpoint at /don_confiao/api/enviar_catalog_sales_a_tryton
- Add test for external_id field functionality
- Catalog sales sync to same Tryton model as Sale (model.sale.sale.create)
- Differentiated by reference 'don_confiao_catalog X' and description 'Venta de catálogo'
- Filters only catalog sales without external_id to avoid duplicates
This commit is contained in:
2026-05-30 21:01:29 -05:00
parent d4a61b8340
commit 5e811c802a
8 changed files with 152 additions and 11 deletions

View File

@@ -24,7 +24,7 @@ def get_tryton_client():
class TrytonSale:
"""Representa una venta para exportación a Tryton"""
def __init__(self, sale, lines):
self.sale = sale
self.lines = lines
@@ -60,7 +60,7 @@ class TrytonSale:
class TrytonLineSale:
"""Representa una línea de venta para exportación a Tryton"""
def __init__(self, sale_line):
self.sale_line = sale_line
@@ -75,3 +75,58 @@ class TrytonLineSale:
"unit": self.sale_line.product.unit_external_id,
"unit_price": self._format_decimal(self.sale_line.unit_price),
}
class TrytonCatalogSale:
"""Representa una catalog sale para exportación a Tryton"""
def __init__(self, catalog_sale, lines):
self.catalog_sale = catalog_sale
self.lines = lines
def _format_date(self, _date):
return {
"__class__": "date",
"year": _date.year,
"month": _date.month,
"day": _date.day,
}
def to_tryton(self):
return {
"company": TRYTON_COMPANY_ID,
"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 "",
"description": "Venta de catálogo",
"party": self.catalog_sale.customer.external_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],
]
],
"self_pick_up": True,
}
class TrytonCatalogSaleLine:
"""Representa una línea de catalog sale para exportación a Tryton"""
def __init__(self, catalog_sale_line):
self.catalog_sale_line = catalog_sale_line
def _format_decimal(self, number):
return {"__class__": "Decimal", "decimal": str(number)}
def to_tryton(self):
return {
"product": self.catalog_sale_line.product.external_id,
"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),
}

View File

@@ -1,5 +1,5 @@
from ...models.sales import Sale, SaleLine
from .client import TrytonSale, TRYTON_COMPANY_ID, TRYTON_SHOPS
from ...models.sales import Sale, SaleLine, CatalogSale, CatalogSaleLine
from .client import TrytonSale, TrytonCatalogSale, TRYTON_COMPANY_ID, TRYTON_SHOPS
class SaleTrytonService:
@@ -39,3 +39,39 @@ class SaleTrytonService:
"""Convierte venta a parámetros para Tryton"""
sale_tryton = TrytonSale(sale, lines)
return [[sale_tryton.to_tryton()], tryton_context]
def send_catalog_sales_to_tryton(self):
"""Envía catalog sales sin external_id a Tryton"""
method = "model.sale.sale.create"
tryton_context = {
"company": TRYTON_COMPANY_ID,
"shops": TRYTON_SHOPS,
}
successful = []
failed = []
catalog_sales = CatalogSale.objects.filter(external_id=None)
for catalog_sale in catalog_sales:
try:
lines = CatalogSaleLine.objects.filter(catalog_sale=catalog_sale.id)
tryton_params = self._catalog_sale_to_tryton_params(
catalog_sale, lines, tryton_context
)
external_ids = self.client.call(method, tryton_params)
catalog_sale.external_id = external_ids[0]
catalog_sale.save()
successful.append(catalog_sale.id)
except Exception as e:
print(
f"Error al enviar catalog sale: {e}, catalog_sale_id: {catalog_sale.id}"
)
failed.append(catalog_sale.id)
continue
return {"successful": successful, "failed": failed}
def _catalog_sale_to_tryton_params(self, catalog_sale, lines, tryton_context):
"""Convierte catalog sale a parámetros para Tryton"""
sale_tryton = TrytonCatalogSale(catalog_sale, lines)
return [[sale_tryton.to_tryton()], tryton_context]