Exportando ventas para tryton desde api #4

Merged
mono merged 4 commits from api_export_sales_for_tryton_#3 into main 2025-03-08 11:21:24 -05:00
5 changed files with 191 additions and 37 deletions

View File

@ -6,9 +6,11 @@ from rest_framework.pagination import PageNumberPagination
from .models import Sale, SaleLine, Customer, Product, ReconciliationJar, PaymentMethods, AdminCode from .models import Sale, SaleLine, Customer, Product, ReconciliationJar, PaymentMethods, AdminCode
from .serializers import SaleSerializer, ProductSerializer, CustomerSerializer, ReconciliationJarSerializer, PaymentMethodSerializer, SaleForRenconciliationSerializer, SaleSummarySerializer from .serializers import SaleSerializer, ProductSerializer, CustomerSerializer, ReconciliationJarSerializer, PaymentMethodSerializer, SaleForRenconciliationSerializer, SaleSummarySerializer
from .views import sales_to_tryton_csv
from decimal import Decimal from decimal import Decimal
import json import io
import csv
class Pagination(PageNumberPagination): class Pagination(PageNumberPagination):
@ -128,12 +130,14 @@ class SalesForReconciliationView(APIView):
return Response(grouped_sales) return Response(grouped_sales)
class SaleSummary(APIView): class SaleSummary(APIView):
def get(self, request, id): def get(self, request, id):
sale = Sale.objects.get(pk=id) sale = Sale.objects.get(pk=id)
serializer = SaleSummarySerializer(sale) serializer = SaleSummarySerializer(sale)
return Response(serializer.data) return Response(serializer.data)
class AdminCodeValidateView(APIView): class AdminCodeValidateView(APIView):
def get(self, request, code): def get(self, request, code):
codes = AdminCode.objects.filter(value=code) codes = AdminCode.objects.filter(value=code)
@ -144,3 +148,19 @@ class ReconciliateJarModelView(viewsets.ModelViewSet):
queryset = ReconciliationJar.objects.all().order_by('-date_time') queryset = ReconciliationJar.objects.all().order_by('-date_time')
pagination_class = Pagination pagination_class = Pagination
serializer_class = ReconciliationJarSerializer serializer_class = ReconciliationJarSerializer
class SalesForTrytonView(APIView):
def get(self, request):
sales = Sale.objects.all()
csv = self._generate_sales_CSV(sales)
return Response({'csv': csv})
def _generate_sales_CSV(self, sales):
output = io.StringIO()
writer = csv.writer(output)
csv_data = sales_to_tryton_csv(sales)
for row in csv_data:
writer.writerow(row)
return output.getvalue()

View File

@ -1,4 +1,7 @@
import json import json
import csv
import io
from django.urls import reverse from django.urls import reverse
from rest_framework import status from rest_framework import status
from rest_framework.test import APITestCase from rest_framework.test import APITestCase
@ -45,6 +48,58 @@ class TestAPI(APITestCase):
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(self.customer.name, json_response[0]['name']) self.assertEqual(self.customer.name, json_response[0]['name'])
def test_get_sales_for_tryton(self):
url = '/don_confiao/api/sales/for_tryton'
self._create_sale()
response = self.client.get(url)
json_response = json.loads(response.content.decode('utf-8'))
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertIn('csv', json_response)
self.assertGreater(len(json_response['csv']), 0)
def test_csv_structure_in_sales_for_tryton(self):
url = '/don_confiao/api/sales/for_tryton'
self._create_sale()
response = self.client.get(url)
json_response = json.loads(response.content.decode('utf-8'))
self.assertEqual(response.status_code, status.HTTP_200_OK)
csv_reader = csv.reader(io.StringIO(json_response['csv']))
expected_header = [
"Tercero",
"Dirección de facturación",
"Dirección de envío",
"Descripción",
"Referencia",
"Fecha venta",
"Plazo de pago",
"Almacén",
"Moneda",
"Líneas/Producto",
"Líneas/Cantidad",
"Líneas/Precio unitario",
"Líneas/Unidad",
"Empresa",
"Tienda",
"Terminal de venta",
"Autorecogida",
"Comentario"
]
self.assertEqual(next(csv_reader), expected_header)
expected_rows = [
[self.customer.name, self.customer.name, self.customer.name, "",
"", "2024-09-02 00:00:00+00:00", "Contado", "Almacén",
"Peso colombiano", self.product.name, "2", "3000.00", "Unidad",
"TIENDA LA ILUSIÓN", "Tienda La Ilusion", "La Ilusion", "True", ""
],
["", "", "", "", "", "", "", "", "", self.product.name, "3",
"5000.00", "Unidad", "", "", "", "", ""
],
]
rows = list(csv_reader)
self.assertEqual(rows, expected_rows)
def _create_sale(self): def _create_sale(self):
url = '/don_confiao/api/sales/' url = '/don_confiao/api/sales/'
data = { data = {

View File

@ -0,0 +1,73 @@
import csv
from django.test import TestCase, Client
from django.urls import reverse
from ..models import Sale, SaleLine, Product, Customer
class TestExportarVentasParaTryton(TestCase):
def setUp(self):
self.product = Product.objects.create(
name='Panela',
price=5000,
measuring_unit='UNIT'
)
self.customer = Customer.objects.create(
name='Camilo'
)
self.sale = Sale.objects.create(
customer=self.customer,
date='2024-09-02',
payment_method='CASH',
)
self.sale_line1 = SaleLine.objects.create(
product=self.product,
quantity=2,
unit_price=3000,
sale=self.sale
)
self.sale_line2 = SaleLine.objects.create(
product=self.product,
quantity=3,
unit_price=5000,
sale=self.sale
)
def test_exportar_ventas_para_tryton(self):
client = Client()
url = '/don_confiao/exportar_ventas_para_tryton'
response = client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response['Content-Type'], 'text/csv')
csv_content = response.content.decode('utf-8')
expected_header = [
"Tercero",
"Dirección de facturación",
"Dirección de envío",
"Descripción",
"Referencia",
"Fecha venta",
"Plazo de pago",
"Almacén",
"Moneda",
"Líneas/Producto",
"Líneas/Cantidad",
"Líneas/Precio unitario",
"Líneas/Unidad",
"Empresa",
"Tienda",
"Terminal de venta",
"Autorecogida",
"Comentario"
]
csv_reader = csv.reader(csv_content.splitlines())
self.assertEqual(next(csv_reader), expected_header)
expected_rows = [
["Camilo", "Camilo", "Camilo", "", "", "2024-09-02 00:00:00+00:00", "Contado", "Almacén", "Peso colombiano", "Panela", "2", "3000.00", "Unidad", "TIENDA LA ILUSIÓN", "Tienda La Ilusion", "La Ilusion", "True", ""],
["", "", "", "", "", "", "", "", "", "Panela", "3", "5000.00", "Unidad", "", "", "", "", ""],
]
csv_rows = list(csv_reader)
self.assertEqual(csv_rows[0], expected_rows[0])
self.assertEqual(csv_rows[1], expected_rows[1])

View File

@ -30,5 +30,6 @@ urlpatterns = [
path('purchases/for_reconciliation', api_views.SalesForReconciliationView.as_view(), name='sales_for_reconciliation'), path('purchases/for_reconciliation', api_views.SalesForReconciliationView.as_view(), name='sales_for_reconciliation'),
path('reconciliate_jar', api_views.ReconciliateJarView.as_view()), path('reconciliate_jar', api_views.ReconciliateJarView.as_view()),
path('api/admin_code/validate/<code>', api_views.AdminCodeValidateView.as_view()), path('api/admin_code/validate/<code>', api_views.AdminCodeValidateView.as_view()),
path('api/sales/for_tryton', api_views.SalesForTrytonView.as_view()),
path('api/', include(router.urls)), path('api/', include(router.urls)),
] ]

View File

@ -163,8 +163,7 @@ def handle_import_customers_file(csv_file):
} }
) )
def sales_to_tryton_csv(sales):
def exportar_ventas_para_tryton(request):
tryton_sales_header = [ tryton_sales_header = [
"Tercero", "Tercero",
"Dirección de facturación", "Dirección de facturación",
@ -186,44 +185,50 @@ def exportar_ventas_para_tryton(request):
"Comentario" "Comentario"
] ]
csv_data = [tryton_sales_header]
for sale in sales:
sale_lines = SaleLine.objects.filter(sale=sale.id)
if not sale_lines:
continue
lines = []
first_sale_line = sale_lines[0]
customer_info = [sale.customer.name] * 3 + [sale.description] * 2
first_line = customer_info + [
sale.date,
"Contado",
"Almacén",
"Peso colombiano",
first_sale_line.product.name,
first_sale_line.quantity,
first_sale_line.unit_price,
"Unidad",
"TIENDA LA ILUSIÓN",
"Tienda La Ilusion",
"La Ilusion",
True,
sale.description]
lines.append(first_line)
for line in sale_lines[1:]:
lines.append([""]*9+[
line.product.name,
line.quantity,
line.unit_price,
"Unidad"]+[""]*5)
for row in lines:
csv_data.append(row)
return csv_data
def exportar_ventas_para_tryton(request):
if request.method == "GET": if request.method == "GET":
response = HttpResponse(content_type='text/csv') response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = "attachment; filename=sales.csv" response['Content-Disposition'] = "attachment; filename=sales.csv"
writer = csv.writer(response)
writer.writerow(tryton_sales_header)
sales = Sale.objects.all() sales = Sale.objects.all()
csv_data = sales_to_tryton_csv(sales)
for sale in sales: writer = csv.writer(response)
sale_lines = SaleLine.objects.filter(sale=sale.id) for row in csv_data:
if not sale_lines: writer.writerow(row)
continue
lines = []
first_sale_line = sale_lines[0]
customer_info = [sale.customer.name] * 3 + [sale.description] * 2
first_line = customer_info + [
sale.date,
"Contado",
"Almacén",
"Peso colombiano",
first_sale_line.product.name,
first_sale_line.quantity,
"Unidad",
first_sale_line.unit_price,
"TIENDA LA ILUSIÓN",
"Tienda La Ilusion",
"La Ilusion",
True,
sale.description]
lines.append(first_line)
for line in sale_lines[1:]:
lines.append([""]*9+[
line.product.name,
line.quantity,
line.unit_price,
"Unidad"]+[""]*5)
for row in lines:
writer.writerow(row)
return response return response