Implementando api #32
							
								
								
									
										1
									
								
								tienda_ilusion/don_confiao/export_csv.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tienda_ilusion/don_confiao/export_csv.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env python3
 | 
				
			||||||
@@ -13,6 +13,7 @@ class Customer(models.Model):
 | 
				
			|||||||
    def __str__(self):
 | 
					    def __str__(self):
 | 
				
			||||||
        return self.name
 | 
					        return self.name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MeasuringUnits(models.TextChoices):
 | 
					class MeasuringUnits(models.TextChoices):
 | 
				
			||||||
    UNIT = 'UNIT', _('Unit')
 | 
					    UNIT = 'UNIT', _('Unit')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -62,11 +63,16 @@ class Sale(models.Model):
 | 
				
			|||||||
    def __str__(self):
 | 
					    def __str__(self):
 | 
				
			||||||
        return f"{self.date} {self.customer}"
 | 
					        return f"{self.date} {self.customer}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_total(self):
 | 
					    def get_total(self):
 | 
				
			||||||
        lines = self.saleline_set.all()
 | 
					        lines = self.saleline_set.all()
 | 
				
			||||||
        return sum([l.quantity * l.unit_price for l in lines])
 | 
					        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):
 | 
					class SaleLine(models.Model):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										47
									
								
								tienda_ilusion/don_confiao/tests/Fixtures/sales_fixture.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								tienda_ilusion/don_confiao/tests/Fixtures/sales_fixture.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					[
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "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"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        "model": "don_confiao.saleline",
 | 
				
			||||||
 | 
					        "pk": 1,
 | 
				
			||||||
 | 
					        "fields": {
 | 
				
			||||||
 | 
					            "sale": 1,
 | 
				
			||||||
 | 
					            "product": 1,
 | 
				
			||||||
 | 
					            "quantity": 10,
 | 
				
			||||||
 | 
					            "unit_price": 5000,
 | 
				
			||||||
 | 
					            "description": "Primer Sale Line"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
							
								
								
									
										50
									
								
								tienda_ilusion/don_confiao/tests/test_export_sales.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								tienda_ilusion/don_confiao/tests/test_export_sales.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env python3
 | 
				
			||||||
 | 
					from django.test import Client, TestCase
 | 
				
			||||||
 | 
					from io import StringIO
 | 
				
			||||||
 | 
					import csv
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestExportSales(TestCase):
 | 
				
			||||||
 | 
					    fixtures = ['sales_fixture']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        self.client = Client()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_export_sales(self):
 | 
				
			||||||
 | 
					        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):
 | 
				
			||||||
 | 
					        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"
 | 
				
			||||||
 | 
					                ]
 | 
				
			||||||
@@ -19,6 +19,9 @@ urlpatterns = [
 | 
				
			|||||||
    path("productos", views.products, name="products"),
 | 
					    path("productos", views.products, name="products"),
 | 
				
			||||||
    path("lista_productos", views.ProductListView.as_view(), name='product_list'),
 | 
					    path("lista_productos", views.ProductListView.as_view(), name='product_list'),
 | 
				
			||||||
    path("importar_productos", views.import_products, name="import_products"),
 | 
					    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("cuadrar_tarro", views.reconciliate_jar, name="reconciliate_jar"),
 | 
				
			||||||
    path("cuadres", views.reconciliate_jar, name="reconciliations"),
 | 
					    path("cuadres", views.reconciliate_jar, name="reconciliations"),
 | 
				
			||||||
    path("resumen_compra/<int:id>", views.purchase_summary, name="purchase_summary"),
 | 
					    path("resumen_compra/<int:id>", views.purchase_summary, name="purchase_summary"),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,8 +3,14 @@ from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
 | 
				
			|||||||
from django.views.generic import ListView
 | 
					from django.views.generic import ListView
 | 
				
			||||||
from django.db import transaction
 | 
					from django.db import transaction
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .models import Sale, Product, ProductCategory, Payment, PaymentMethods
 | 
					from .models import (
 | 
				
			||||||
from .forms import ImportProductsForm, PurchaseForm, SaleLineFormSet, ReconciliationJarForm, PurchaseSummaryForm
 | 
					    Sale, SaleLine, Product, ProductCategory, Payment, PaymentMethods)
 | 
				
			||||||
 | 
					from .forms import (
 | 
				
			||||||
 | 
					    ImportProductsForm,
 | 
				
			||||||
 | 
					    PurchaseForm,
 | 
				
			||||||
 | 
					    SaleLineFormSet,
 | 
				
			||||||
 | 
					    ReconciliationJarForm,
 | 
				
			||||||
 | 
					    PurchaseSummaryForm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import csv
 | 
					import csv
 | 
				
			||||||
import io
 | 
					import io
 | 
				
			||||||
@@ -18,9 +24,11 @@ class DecimalEncoder(json.JSONEncoder):
 | 
				
			|||||||
            return float(obj)
 | 
					            return float(obj)
 | 
				
			||||||
        return json.JSONEncoder.default(self, obj)
 | 
					        return json.JSONEncoder.default(self, obj)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def index(request):
 | 
					def index(request):
 | 
				
			||||||
    return render(request, 'don_confiao/index.html')
 | 
					    return render(request, 'don_confiao/index.html')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def buy(request):
 | 
					def buy(request):
 | 
				
			||||||
    if request.method == "POST":
 | 
					    if request.method == "POST":
 | 
				
			||||||
        sale_form = PurchaseForm(request.POST)
 | 
					        sale_form = PurchaseForm(request.POST)
 | 
				
			||||||
@@ -115,10 +123,11 @@ def purchase_summary(request, id):
 | 
				
			|||||||
        request,
 | 
					        request,
 | 
				
			||||||
        "don_confiao/purchase_summary.html",
 | 
					        "don_confiao/purchase_summary.html",
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            "purchase" : purchase
 | 
					            "purchase": purchase
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _categories_from_csv_string(categories_string, separator="&"):
 | 
					def _categories_from_csv_string(categories_string, separator="&"):
 | 
				
			||||||
    categories = categories_string.split(separator)
 | 
					    categories = categories_string.split(separator)
 | 
				
			||||||
    clean_categories = [c.strip() for c in categories]
 | 
					    clean_categories = [c.strip() for c in categories]
 | 
				
			||||||
@@ -146,6 +155,70 @@ def handle_import_products_file(csv_file):
 | 
				
			|||||||
            product.categories.add(category)
 | 
					            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):
 | 
					class ProductListView(ListView):
 | 
				
			||||||
    model = Product
 | 
					    model = Product
 | 
				
			||||||
    template_model = 'don_confiao/product_list.html'
 | 
					    template_model = 'don_confiao/product_list.html'
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -124,3 +124,5 @@ STATIC_URL = 'static/'
 | 
				
			|||||||
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field
 | 
					# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
 | 
					DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FIXTURE_DIRS = ['don_confiao/tests/Fixtures']
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user