From 603230beda5dccbbe3e390eb05b8c73af0a82cdf Mon Sep 17 00:00:00 2001 From: Rodia Date: Sat, 7 Sep 2024 08:07:35 -0500 Subject: [PATCH 1/2] Fix: Export Sale Line --- .../tests/Fixtures/sales_fixture.json | 36 +++++++++++++++++++ .../don_confiao/tests/test_export_sales.py | 16 +++++++++ 2 files changed, 52 insertions(+) create mode 100644 tienda_ilusion/don_confiao/tests/Fixtures/sales_fixture.json create mode 100644 tienda_ilusion/don_confiao/tests/test_export_sales.py diff --git a/tienda_ilusion/don_confiao/tests/Fixtures/sales_fixture.json b/tienda_ilusion/don_confiao/tests/Fixtures/sales_fixture.json new file mode 100644 index 0000000..e51b994 --- /dev/null +++ b/tienda_ilusion/don_confiao/tests/Fixtures/sales_fixture.json @@ -0,0 +1,36 @@ +[ + { + "model": "don_confiao.customer", + "pk": 1, + "fields": { + "name": "Alejandro Fernandez", + "address": "Avenida Siempre Viva" + } + }, + { + "model": "don_confiao.productcategory", + "pk": 1, + "fields": { + "name": "Unidad", + } + }, + { + "model": "don_confiao.product", + "pk": 1, + "fields": { + "name": "Papaya", + "price": 2500, + "measuring_unit": "Unidad", + } + }, + { + "model": "don_confiao.sale", + "pk": 1, + "fields": { + "customer": 1, + "date": "2024-08-31", + "phone": 312201103, + "description": "Primera Venta" + } + } +] diff --git a/tienda_ilusion/don_confiao/tests/test_export_sales.py b/tienda_ilusion/don_confiao/tests/test_export_sales.py new file mode 100644 index 0000000..450b23b --- /dev/null +++ b/tienda_ilusion/don_confiao/tests/test_export_sales.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +from django.test import TestCase +from ..models import Sale + + +class TestExportSales(TestCase): + + def setUp(self): + pass + + def test_export_sales(self): + sales = self._export_sales_csv() + self.assertEqual(len(sales), 1) + + def _export_sales_csv(self): + raise Exception(Sale.objects.all()) From a83cd970e60ef2ee05e4a3115b4a402ba8080ac3 Mon Sep 17 00:00:00 2001 From: sinergia Date: Sat, 7 Sep 2024 14:58:11 -0500 Subject: [PATCH 2/2] Feat: Export Ventas Para Tryton --- tienda_ilusion/don_confiao/export_csv.py | 1 + tienda_ilusion/don_confiao/models.py | 8 +- .../tests/Fixtures/sales_fixture.json | 17 +++- .../don_confiao/tests/test_export_sales.py | 46 +++++++++-- tienda_ilusion/don_confiao/urls.py | 3 + tienda_ilusion/don_confiao/views.py | 79 ++++++++++++++++++- tienda_ilusion/tienda_ilusion/settings.py | 2 + 7 files changed, 143 insertions(+), 13 deletions(-) create mode 100644 tienda_ilusion/don_confiao/export_csv.py diff --git a/tienda_ilusion/don_confiao/export_csv.py b/tienda_ilusion/don_confiao/export_csv.py new file mode 100644 index 0000000..e5a0d9b --- /dev/null +++ b/tienda_ilusion/don_confiao/export_csv.py @@ -0,0 +1 @@ +#!/usr/bin/env python3 diff --git a/tienda_ilusion/don_confiao/models.py b/tienda_ilusion/don_confiao/models.py index 1c50852..05b0c14 100644 --- a/tienda_ilusion/don_confiao/models.py +++ b/tienda_ilusion/don_confiao/models.py @@ -13,6 +13,7 @@ class Customer(models.Model): def __str__(self): return self.name + class MeasuringUnits(models.TextChoices): UNIT = 'UNIT', _('Unit') @@ -62,11 +63,16 @@ class Sale(models.Model): def __str__(self): return f"{self.date} {self.customer}" - def get_total(self): lines = self.saleline_set.all() return sum([l.quantity * l.unit_price for l in lines]) + @classmethod + def sale_header_csv(cls): + sale_header_csv = [field.name for field in cls._meta.fields] + + return sale_header_csv + class SaleLine(models.Model): diff --git a/tienda_ilusion/don_confiao/tests/Fixtures/sales_fixture.json b/tienda_ilusion/don_confiao/tests/Fixtures/sales_fixture.json index e51b994..788d336 100644 --- a/tienda_ilusion/don_confiao/tests/Fixtures/sales_fixture.json +++ b/tienda_ilusion/don_confiao/tests/Fixtures/sales_fixture.json @@ -11,7 +11,7 @@ "model": "don_confiao.productcategory", "pk": 1, "fields": { - "name": "Unidad", + "name": "Unidad" } }, { @@ -20,7 +20,7 @@ "fields": { "name": "Papaya", "price": 2500, - "measuring_unit": "Unidad", + "measuring_unit": "Unidad" } }, { @@ -32,5 +32,16 @@ "phone": 312201103, "description": "Primera Venta" } - } + }, + { + "model": "don_confiao.saleline", + "pk": 1, + "fields": { + "sale": 1, + "product": 1, + "quantity": 10, + "unit_price": 5000, + "description": "Primer Sale Line" + } + } ] diff --git a/tienda_ilusion/don_confiao/tests/test_export_sales.py b/tienda_ilusion/don_confiao/tests/test_export_sales.py index 450b23b..9dc050f 100644 --- a/tienda_ilusion/don_confiao/tests/test_export_sales.py +++ b/tienda_ilusion/don_confiao/tests/test_export_sales.py @@ -1,16 +1,50 @@ #!/usr/bin/env python3 -from django.test import TestCase -from ..models import Sale +from django.test import Client, TestCase +from io import StringIO +import csv class TestExportSales(TestCase): + fixtures = ['sales_fixture'] def setUp(self): - pass + self.client = Client() def test_export_sales(self): - sales = self._export_sales_csv() - self.assertEqual(len(sales), 1) + sales_response = self._export_sales_csv() + filename = sales_response.headers[ + 'Content-Disposition'].split('; ')[1].strip('filename=').strip("'") + content = sales_response.content + content_str = content.decode('utf-8') + csv_file = StringIO(content_str) + header = next(csv.reader(csv_file)) + + self.assertGreater(len(content), 0) + self.assertEqual(filename, 'sales.csv') + self.assertEqual(sales_response.headers['Content-Type'], 'text/csv') + self.assertEqual(header, self._tryton_sale_header()) def _export_sales_csv(self): - raise Exception(Sale.objects.all()) + return self.client.get("/don_confiao/exportar_ventas_para_tryton") + + def _tryton_sale_header(self): + return [ + "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" + ] diff --git a/tienda_ilusion/don_confiao/urls.py b/tienda_ilusion/don_confiao/urls.py index 7de794e..2d9f83a 100644 --- a/tienda_ilusion/don_confiao/urls.py +++ b/tienda_ilusion/don_confiao/urls.py @@ -10,6 +10,9 @@ urlpatterns = [ path("productos", views.products, name="products"), path("lista_productos", views.ProductListView.as_view(), name='product_list'), path("importar_productos", views.import_products, name="import_products"), + path("exportar_ventas_para_tryton", + views.exportar_ventas_para_tryton, + name="exportar_ventas_para_tryton"), path("cuadrar_tarro", views.reconciliate_jar, name="reconciliate_jar"), path("cuadres", views.reconciliate_jar, name="reconciliations"), path("resumen_compra/", views.purchase_summary, name="purchase_summary"), diff --git a/tienda_ilusion/don_confiao/views.py b/tienda_ilusion/don_confiao/views.py index 35b0e0d..2141a97 100644 --- a/tienda_ilusion/don_confiao/views.py +++ b/tienda_ilusion/don_confiao/views.py @@ -3,8 +3,14 @@ from django.http import HttpResponse, HttpResponseRedirect, JsonResponse from django.views.generic import ListView from django.db import transaction -from .models import Sale, Product, ProductCategory, Payment, PaymentMethods -from .forms import ImportProductsForm, PurchaseForm, SaleLineFormSet, ReconciliationJarForm, PurchaseSummaryForm +from .models import ( + Sale, SaleLine, Product, ProductCategory, Payment, PaymentMethods) +from .forms import ( + ImportProductsForm, + PurchaseForm, + SaleLineFormSet, + ReconciliationJarForm, + PurchaseSummaryForm) import csv import io @@ -18,9 +24,11 @@ class DecimalEncoder(json.JSONEncoder): return float(obj) return json.JSONEncoder.default(self, obj) + def index(request): return render(request, 'don_confiao/index.html') + def buy(request): if request.method == "POST": sale_form = PurchaseForm(request.POST) @@ -115,10 +123,11 @@ def purchase_summary(request, id): request, "don_confiao/purchase_summary.html", { - "purchase" : purchase + "purchase": purchase } ) + def _categories_from_csv_string(categories_string, separator="&"): categories = categories_string.split(separator) clean_categories = [c.strip() for c in categories] @@ -146,6 +155,70 @@ def handle_import_products_file(csv_file): product.categories.add(category) +def exportar_ventas_para_tryton(request): + tryton_sales_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" + ] + + if request.method == "GET": + response = HttpResponse(content_type='text/csv') + response['Content-Disposition'] = "attachment; filename=sales.csv" + writer = csv.writer(response) + writer.writerow(tryton_sales_header) + + sales = Sale.objects.all() + + 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, + "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 + + class ProductListView(ListView): model = Product template_model = 'don_confiao/product_list.html' diff --git a/tienda_ilusion/tienda_ilusion/settings.py b/tienda_ilusion/tienda_ilusion/settings.py index e50d393..b7924e9 100644 --- a/tienda_ilusion/tienda_ilusion/settings.py +++ b/tienda_ilusion/tienda_ilusion/settings.py @@ -123,3 +123,5 @@ STATIC_URL = 'static/' # https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +FIXTURE_DIRS = ['don_confiao/tests/Fixtures']