From ef0c0c52db2c31f01da6940a20603cc86f18e6d8 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 29 Jun 2024 14:29:22 -0500 Subject: [PATCH 1/9] Feat: importando productos desde csv. --- .../don_confiao/example_products.csv | 4 ++ tienda_ilusion/don_confiao/forms.py | 4 ++ .../0009_productcategory_product.py | 30 +++++++++ tienda_ilusion/don_confiao/models.py | 24 +++++++- .../don_confiao/import_products.html | 10 +++ .../templates/don_confiao/index.html | 1 + .../templates/don_confiao/products_index.html | 12 ++++ tienda_ilusion/don_confiao/test_products.py | 29 +++++++++ tienda_ilusion/don_confiao/urls.py | 3 + tienda_ilusion/don_confiao/views.py | 61 +++++++++++++------ 10 files changed, 160 insertions(+), 18 deletions(-) create mode 100644 tienda_ilusion/don_confiao/example_products.csv create mode 100644 tienda_ilusion/don_confiao/forms.py create mode 100644 tienda_ilusion/don_confiao/migrations/0009_productcategory_product.py create mode 100644 tienda_ilusion/don_confiao/templates/don_confiao/import_products.html create mode 100644 tienda_ilusion/don_confiao/templates/don_confiao/products_index.html create mode 100644 tienda_ilusion/don_confiao/test_products.py diff --git a/tienda_ilusion/don_confiao/example_products.csv b/tienda_ilusion/don_confiao/example_products.csv new file mode 100644 index 0000000..092a32f --- /dev/null +++ b/tienda_ilusion/don_confiao/example_products.csv @@ -0,0 +1,4 @@ +"producto","unidad","precio","categorias" +"Aceite de Coco Artesanal 500ml","Unidad", 50000,"Aceites&Alimentos" +"Café 500ml","Unidad", 14000,"Cafes&Alimentos" +"Café 250ml","Unidad", 7000,"Cafes&Alimentos" diff --git a/tienda_ilusion/don_confiao/forms.py b/tienda_ilusion/don_confiao/forms.py new file mode 100644 index 0000000..a9ef913 --- /dev/null +++ b/tienda_ilusion/don_confiao/forms.py @@ -0,0 +1,4 @@ +from django import forms + +class ImportProductsForm(forms.Form): + csv_file = forms.FileField() diff --git a/tienda_ilusion/don_confiao/migrations/0009_productcategory_product.py b/tienda_ilusion/don_confiao/migrations/0009_productcategory_product.py new file mode 100644 index 0000000..6c7e15f --- /dev/null +++ b/tienda_ilusion/don_confiao/migrations/0009_productcategory_product.py @@ -0,0 +1,30 @@ +# Generated by Django 5.0.6 on 2024-06-29 18:55 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('don_confiao', '0008_alter_sale_phone_alter_saleline_description'), + ] + + operations = [ + migrations.CreateModel( + name='ProductCategory', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100)), + ], + ), + migrations.CreateModel( + name='Product', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100)), + ('price', models.DecimalField(decimal_places=2, max_digits=9)), + ('measuring_unit', models.CharField(choices=[('UNIT', 'Unit')], default='UNIT', max_length=20)), + ('categories', models.ManyToManyField(to='don_confiao.productcategory')), + ], + ), + ] diff --git a/tienda_ilusion/don_confiao/models.py b/tienda_ilusion/don_confiao/models.py index afe69e5..cdd9bc7 100644 --- a/tienda_ilusion/don_confiao/models.py +++ b/tienda_ilusion/don_confiao/models.py @@ -1,5 +1,5 @@ from django.db import models - +from django.utils.translation import gettext_lazy as _ class Sale(models.Model): @@ -16,3 +16,25 @@ class SaleLine(models.Model): quantity = models.IntegerField(null=True) unit_price = models.DecimalField(max_digits=9, decimal_places=2) description = models.CharField(max_length=255, null=True, blank=True) + +class MeasuringUnits(models.TextChoices): + UNIT = 'UNIT', _('Unit') + +class ProductCategory(models.Model): + name = models.CharField(max_length=100) + + def __str__(self): + return self.name + +class Product(models.Model): + name = models.CharField(max_length=100) + price = models.DecimalField(max_digits=9, decimal_places=2) + measuring_unit = models.CharField( + max_length=20, + choices=MeasuringUnits.choices, + default=MeasuringUnits.UNIT + ) + categories = models.ManyToManyField(ProductCategory) + + def __str__(self): + return self.name diff --git a/tienda_ilusion/don_confiao/templates/don_confiao/import_products.html b/tienda_ilusion/don_confiao/templates/don_confiao/import_products.html new file mode 100644 index 0000000..376952d --- /dev/null +++ b/tienda_ilusion/don_confiao/templates/don_confiao/import_products.html @@ -0,0 +1,10 @@ +{% if form.is_multipart %} +
+{% else %} + +{% endif %} + +{% csrf_token %} +{{ form }} + +
diff --git a/tienda_ilusion/don_confiao/templates/don_confiao/index.html b/tienda_ilusion/don_confiao/templates/don_confiao/index.html index 2fbf6b4..7d22ce5 100644 --- a/tienda_ilusion/don_confiao/templates/don_confiao/index.html +++ b/tienda_ilusion/don_confiao/templates/don_confiao/index.html @@ -3,4 +3,5 @@ diff --git a/tienda_ilusion/don_confiao/templates/don_confiao/products_index.html b/tienda_ilusion/don_confiao/templates/don_confiao/products_index.html new file mode 100644 index 0000000..794e290 --- /dev/null +++ b/tienda_ilusion/don_confiao/templates/don_confiao/products_index.html @@ -0,0 +1,12 @@ +
+ {% csrf_token %} +
+

Importar Productos

+
+ {% if error_message %}

{{ error_message }}

{% endif %} +
+ +
+ +
+
diff --git a/tienda_ilusion/don_confiao/test_products.py b/tienda_ilusion/don_confiao/test_products.py new file mode 100644 index 0000000..3713a38 --- /dev/null +++ b/tienda_ilusion/don_confiao/test_products.py @@ -0,0 +1,29 @@ +from django.test import Client, TestCase +from django.contrib.auth.models import AnonymousUser, User +from django.conf import settings + +from .views import import_products, products + +import os +import json + +class TestProducts(TestCase): + def setUp(self): + self.client = Client() + + def test_import_products(self): + app_name = "don_confiao" + app_dir = os.path.join(settings.BASE_DIR, app_name) + example_csv = os.path.join(app_dir, 'example_products.csv') + products_in_example = 3 + with open(example_csv, 'rb') as csv: + response = self.client.post( + "/don_confiao/importar_productos", + {"csv_file": csv} + ) + products_response = self.client.get("/don_confiao/productos") + products = json.loads(products_response.content.decode('utf-8')) + self.assertEqual( + len(products), + products_in_example + ) diff --git a/tienda_ilusion/don_confiao/urls.py b/tienda_ilusion/don_confiao/urls.py index bb2e394..17dc62b 100644 --- a/tienda_ilusion/don_confiao/urls.py +++ b/tienda_ilusion/don_confiao/urls.py @@ -2,9 +2,12 @@ from django.urls import path from . import views +app_name = 'don_confiao' urlpatterns = [ path("", views.index, name="wellcome"), path("comprar", views.buy, name="buy"), path("compras", views.purchases, name="purchases"), path("productos", views.products, name="products"), + path("productos_index", views.products_index, name="products_index"), + path("importar_productos", views.import_products, name="import_products") ] diff --git a/tienda_ilusion/don_confiao/views.py b/tienda_ilusion/don_confiao/views.py index 8a8af33..253eb70 100644 --- a/tienda_ilusion/don_confiao/views.py +++ b/tienda_ilusion/don_confiao/views.py @@ -1,9 +1,12 @@ from django.shortcuts import render -from django.http import HttpResponse, JsonResponse +from django.http import HttpResponse, HttpResponseRedirect, JsonResponse from django.template import loader -from .models import Sale +from .models import Sale, Product +from .forms import ImportProductsForm +import csv +import io def index(request): return render(request, 'don_confiao/index.html') @@ -22,18 +25,42 @@ def purchases(request): def products(request): - products = [ - { - "name": "Aceite de Coco Artesanal 500ml", - "price_list": 50000, - "uom": "Unit", - "category": "Aceites" - }, - { - "name": "Cafe 500ml", - "price_list": 14000, - "uom": "Unit", - "category": "Cafes" - }, - ] - return JsonResponse(products, safe=False) \ No newline at end of file + rproducts = [] + products = Product.objects.all() + for product in products: + rproduct = { + "name": product.name, + "price_list": product.price, + "uom": product.measuring_unit, + "category": ""#.join('&', [c for c in product.categories]) + } + rproducts.append(rproduct) + + return JsonResponse(rproducts, safe=False) + +def products_index(request): + return render(request, 'don_confiao/products_index.html') + +def import_products(request): + if request.method == "POST": + form = ImportProductsForm(request.POST, request.FILES) + if form.is_valid(): + handle_import_products_file(request.FILES["csv_file"]) + return HttpResponseRedirect("productos_index") + else: + form = ImportProductsForm() + return render( + request, + "don_confiao/import_products.html", + {'form': form} + ) + +def handle_import_products_file(csv_file): + data = io.StringIO(csv_file.read().decode('utf-8')) + reader = csv.DictReader(data, quotechar='"') + for row in reader: + product = Product() + product.name = row['producto'] + product.price = row['precio'] + product.measuring_unit = row['unidad'] + product.save() From 252720b3248b98432b908d06711ce3e10e0ea594 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 29 Jun 2024 15:45:05 -0500 Subject: [PATCH 2/9] Feat: enviando las categorias en la lista de productos. --- tienda_ilusion/don_confiao/test_products.py | 15 ++++++++------- tienda_ilusion/don_confiao/views.py | 11 +++++++++-- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/tienda_ilusion/don_confiao/test_products.py b/tienda_ilusion/don_confiao/test_products.py index 3713a38..6743a5e 100644 --- a/tienda_ilusion/don_confiao/test_products.py +++ b/tienda_ilusion/don_confiao/test_products.py @@ -17,13 +17,14 @@ class TestProducts(TestCase): example_csv = os.path.join(app_dir, 'example_products.csv') products_in_example = 3 with open(example_csv, 'rb') as csv: - response = self.client.post( + self.client.post( "/don_confiao/importar_productos", {"csv_file": csv} ) - products_response = self.client.get("/don_confiao/productos") - products = json.loads(products_response.content.decode('utf-8')) - self.assertEqual( - len(products), - products_in_example - ) + products_response = self.client.get("/don_confiao/productos") + all_products = json.loads(products_response.content.decode('utf-8')) + self.assertEqual( + len(all_products), + products_in_example + ) + self.assertIn("Aceites", all_products[0]["categories"]) diff --git a/tienda_ilusion/don_confiao/views.py b/tienda_ilusion/don_confiao/views.py index 253eb70..bca21a5 100644 --- a/tienda_ilusion/don_confiao/views.py +++ b/tienda_ilusion/don_confiao/views.py @@ -2,7 +2,7 @@ from django.shortcuts import render from django.http import HttpResponse, HttpResponseRedirect, JsonResponse from django.template import loader -from .models import Sale, Product +from .models import Sale, Product, ProductCategory from .forms import ImportProductsForm import csv @@ -32,7 +32,7 @@ def products(request): "name": product.name, "price_list": product.price, "uom": product.measuring_unit, - "category": ""#.join('&', [c for c in product.categories]) + "categories": [c.name for c in product.categories.all()] } rproducts.append(rproduct) @@ -64,3 +64,10 @@ def handle_import_products_file(csv_file): product.price = row['precio'] product.measuring_unit = row['unidad'] product.save() + + categories = [n.strip for n in row["categorias"].split("&")] + for category in categories: + category_model, _ = ProductCategory.objects.get_or_create( + name=category + ) + product.categories.add(category_model) From ed5d3f447ac6c4d5f554f46b2dd823e9cf865529 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 29 Jun 2024 16:23:47 -0500 Subject: [PATCH 3/9] fix: creacion repetida de categoria de productos. --- .../0010_alter_productcategory_name.py | 18 ++++++++++ tienda_ilusion/don_confiao/models.py | 2 +- tienda_ilusion/don_confiao/test_products.py | 35 ++++++++++++++----- tienda_ilusion/don_confiao/views.py | 4 ++- 4 files changed, 49 insertions(+), 10 deletions(-) create mode 100644 tienda_ilusion/don_confiao/migrations/0010_alter_productcategory_name.py diff --git a/tienda_ilusion/don_confiao/migrations/0010_alter_productcategory_name.py b/tienda_ilusion/don_confiao/migrations/0010_alter_productcategory_name.py new file mode 100644 index 0000000..c400651 --- /dev/null +++ b/tienda_ilusion/don_confiao/migrations/0010_alter_productcategory_name.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.6 on 2024-06-29 21:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('don_confiao', '0009_productcategory_product'), + ] + + operations = [ + migrations.AlterField( + model_name='productcategory', + name='name', + field=models.CharField(max_length=100, unique=True), + ), + ] diff --git a/tienda_ilusion/don_confiao/models.py b/tienda_ilusion/don_confiao/models.py index cdd9bc7..dc51642 100644 --- a/tienda_ilusion/don_confiao/models.py +++ b/tienda_ilusion/don_confiao/models.py @@ -21,7 +21,7 @@ class MeasuringUnits(models.TextChoices): UNIT = 'UNIT', _('Unit') class ProductCategory(models.Model): - name = models.CharField(max_length=100) + name = models.CharField(max_length=100, unique=True) def __str__(self): return self.name diff --git a/tienda_ilusion/don_confiao/test_products.py b/tienda_ilusion/don_confiao/test_products.py index 6743a5e..89dc1e4 100644 --- a/tienda_ilusion/don_confiao/test_products.py +++ b/tienda_ilusion/don_confiao/test_products.py @@ -3,6 +3,7 @@ from django.contrib.auth.models import AnonymousUser, User from django.conf import settings from .views import import_products, products +from .models import ProductCategory import os import json @@ -12,19 +13,37 @@ class TestProducts(TestCase): self.client = Client() def test_import_products(self): + self._import_csv() + all_products = self._get_products() + self.assertEqual( + len(all_products), + 3 + ) + + def test_import_products_with_categories(self): + self._import_csv() + all_products = self._get_products() + self.assertIn("Aceites", all_products[0]["categories"]) + + def test_don_repeat_categories_on_import(self): + self._import_csv() + categories_on_csv = ["Cafes", "Alimentos", "Aceites"] + categories = ProductCategory.objects.all() + self.assertCountEqual( + [c.name for c in categories], + categories_on_csv + ) + + def _get_products(self): + products_response = self.client.get("/don_confiao/productos") + return json.loads(products_response.content.decode('utf-8')) + + def _import_csv(self, csv_file='example_products.csv'): app_name = "don_confiao" app_dir = os.path.join(settings.BASE_DIR, app_name) example_csv = os.path.join(app_dir, 'example_products.csv') - products_in_example = 3 with open(example_csv, 'rb') as csv: self.client.post( "/don_confiao/importar_productos", {"csv_file": csv} ) - products_response = self.client.get("/don_confiao/productos") - all_products = json.loads(products_response.content.decode('utf-8')) - self.assertEqual( - len(all_products), - products_in_example - ) - self.assertIn("Aceites", all_products[0]["categories"]) diff --git a/tienda_ilusion/don_confiao/views.py b/tienda_ilusion/don_confiao/views.py index bca21a5..a542a51 100644 --- a/tienda_ilusion/don_confiao/views.py +++ b/tienda_ilusion/don_confiao/views.py @@ -65,9 +65,11 @@ def handle_import_products_file(csv_file): product.measuring_unit = row['unidad'] product.save() - categories = [n.strip for n in row["categorias"].split("&")] + categories = [n.strip() for n in row["categorias"].split("&")] for category in categories: category_model, _ = ProductCategory.objects.get_or_create( name=category ) + category_model.save() product.categories.add(category_model) + product.save() From 84c295e7de4009728704037f1510a7ca8003aef0 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 29 Jun 2024 16:24:07 -0500 Subject: [PATCH 4/9] admin: registrando productos y categoria de productos en admin. --- tienda_ilusion/don_confiao/admin.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tienda_ilusion/don_confiao/admin.py b/tienda_ilusion/don_confiao/admin.py index 659a321..0756544 100644 --- a/tienda_ilusion/don_confiao/admin.py +++ b/tienda_ilusion/don_confiao/admin.py @@ -1,5 +1,7 @@ from django.contrib import admin -from .models import Sale, SaleLine +from .models import Sale, SaleLine, Product, ProductCategory admin.site.register(Sale) admin.site.register(SaleLine) +admin.site.register(Product) +admin.site.register(ProductCategory) From 64a9b75ad789f2374f924e16deac249e09c1f8b0 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 29 Jun 2024 16:57:50 -0500 Subject: [PATCH 5/9] fix: evitando duplicado de productos en la importacion. --- .../don_confiao/example_products.csv | 6 +++--- .../don_confiao/example_products2.csv | 4 ++++ .../migrations/0011_alter_product_name.py | 18 ++++++++++++++++++ tienda_ilusion/don_confiao/models.py | 2 +- tienda_ilusion/don_confiao/test_products.py | 7 +++++++ tienda_ilusion/don_confiao/views.py | 6 ++++-- 6 files changed, 37 insertions(+), 6 deletions(-) create mode 100644 tienda_ilusion/don_confiao/example_products2.csv create mode 100644 tienda_ilusion/don_confiao/migrations/0011_alter_product_name.py diff --git a/tienda_ilusion/don_confiao/example_products.csv b/tienda_ilusion/don_confiao/example_products.csv index 092a32f..46228a7 100644 --- a/tienda_ilusion/don_confiao/example_products.csv +++ b/tienda_ilusion/don_confiao/example_products.csv @@ -1,4 +1,4 @@ "producto","unidad","precio","categorias" -"Aceite de Coco Artesanal 500ml","Unidad", 50000,"Aceites&Alimentos" -"Café 500ml","Unidad", 14000,"Cafes&Alimentos" -"Café 250ml","Unidad", 7000,"Cafes&Alimentos" +"Aceite","Unidad", 50000,"Aceites&Alimentos" +"Café","Unidad", 14000,"Cafes&Alimentos" +"Arroz","Unidad", 7000,"Cafes&Alimentos" diff --git a/tienda_ilusion/don_confiao/example_products2.csv b/tienda_ilusion/don_confiao/example_products2.csv new file mode 100644 index 0000000..f46428b --- /dev/null +++ b/tienda_ilusion/don_confiao/example_products2.csv @@ -0,0 +1,4 @@ +"producto","unidad","precio","categorias" +"Aceite","Unidad", 50000,"Aceites&Alimentos" +"Café","Unidad", 15000,"Cafes&Alimentos" +"Arroz","Unidad", 6000,"Cafes&Alimentos" diff --git a/tienda_ilusion/don_confiao/migrations/0011_alter_product_name.py b/tienda_ilusion/don_confiao/migrations/0011_alter_product_name.py new file mode 100644 index 0000000..9a6a092 --- /dev/null +++ b/tienda_ilusion/don_confiao/migrations/0011_alter_product_name.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.6 on 2024-06-29 21:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('don_confiao', '0010_alter_productcategory_name'), + ] + + operations = [ + migrations.AlterField( + model_name='product', + name='name', + field=models.CharField(max_length=100, unique=True), + ), + ] diff --git a/tienda_ilusion/don_confiao/models.py b/tienda_ilusion/don_confiao/models.py index dc51642..6d40cac 100644 --- a/tienda_ilusion/don_confiao/models.py +++ b/tienda_ilusion/don_confiao/models.py @@ -27,7 +27,7 @@ class ProductCategory(models.Model): return self.name class Product(models.Model): - name = models.CharField(max_length=100) + name = models.CharField(max_length=100, unique=True) price = models.DecimalField(max_digits=9, decimal_places=2) measuring_unit = models.CharField( max_length=20, diff --git a/tienda_ilusion/don_confiao/test_products.py b/tienda_ilusion/don_confiao/test_products.py index 89dc1e4..a522b28 100644 --- a/tienda_ilusion/don_confiao/test_products.py +++ b/tienda_ilusion/don_confiao/test_products.py @@ -34,6 +34,13 @@ class TestProducts(TestCase): categories_on_csv ) + def test_update_products(self): + self._import_csv() + first_products = self._get_products() + self._import_csv('example_products2.csv') + seconds_products = self._get_products() + self.assertCountEqual(first_products, seconds_products) + def _get_products(self): products_response = self.client.get("/don_confiao/productos") return json.loads(products_response.content.decode('utf-8')) diff --git a/tienda_ilusion/don_confiao/views.py b/tienda_ilusion/don_confiao/views.py index a542a51..9daaf49 100644 --- a/tienda_ilusion/don_confiao/views.py +++ b/tienda_ilusion/don_confiao/views.py @@ -59,8 +59,10 @@ def handle_import_products_file(csv_file): data = io.StringIO(csv_file.read().decode('utf-8')) reader = csv.DictReader(data, quotechar='"') for row in reader: - product = Product() - product.name = row['producto'] + product, _ = Product.objects.get_or_create( + name=row['producto'], + defaults={'price': row['precio']} + ) product.price = row['precio'] product.measuring_unit = row['unidad'] product.save() From 524626aea352beeb0cea56386efbaf1e341a2ea9 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 29 Jun 2024 17:20:01 -0500 Subject: [PATCH 6/9] fix: actualizando precios al importar productos. --- tienda_ilusion/don_confiao/test_products.py | 32 +++++++++++++++++++-- tienda_ilusion/don_confiao/views.py | 10 +++---- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/tienda_ilusion/don_confiao/test_products.py b/tienda_ilusion/don_confiao/test_products.py index a522b28..6f2ea86 100644 --- a/tienda_ilusion/don_confiao/test_products.py +++ b/tienda_ilusion/don_confiao/test_products.py @@ -39,7 +39,35 @@ class TestProducts(TestCase): first_products = self._get_products() self._import_csv('example_products2.csv') seconds_products = self._get_products() - self.assertCountEqual(first_products, seconds_products) + self.assertEqual(len(first_products), len(seconds_products)) + + def test_update_price(self): + self._import_csv() + first_products = self._get_products() + first_prices = {p["name"]: p["price_list"] for p in first_products} + expected_first_prices = { + "Aceite": '50000.00', + "Café": '14000.00', + "Arroz": '7000.00' + } + self.assertDictEqual( + expected_first_prices, + first_prices + ) + + self._import_csv('example_products2.csv') + updated_products = self._get_products() + updated_prices = {p["name"]: p["price_list"] for p in updated_products} + expected_updated_prices = { + "Aceite": '50000.00', + "Café": '15000.00', + "Arroz": '6000.00' + } + + self.assertDictEqual( + expected_updated_prices, + updated_prices + ) def _get_products(self): products_response = self.client.get("/don_confiao/productos") @@ -48,7 +76,7 @@ class TestProducts(TestCase): def _import_csv(self, csv_file='example_products.csv'): app_name = "don_confiao" app_dir = os.path.join(settings.BASE_DIR, app_name) - example_csv = os.path.join(app_dir, 'example_products.csv') + example_csv = os.path.join(app_dir, csv_file) with open(example_csv, 'rb') as csv: self.client.post( "/don_confiao/importar_productos", diff --git a/tienda_ilusion/don_confiao/views.py b/tienda_ilusion/don_confiao/views.py index 9daaf49..8f04092 100644 --- a/tienda_ilusion/don_confiao/views.py +++ b/tienda_ilusion/don_confiao/views.py @@ -59,13 +59,13 @@ def handle_import_products_file(csv_file): data = io.StringIO(csv_file.read().decode('utf-8')) reader = csv.DictReader(data, quotechar='"') for row in reader: - product, _ = Product.objects.get_or_create( + product, created = Product.objects.update_or_create( name=row['producto'], - defaults={'price': row['precio']} + defaults={ + 'price': row['precio'], + 'measuring_unit': row['unidad'], + } ) - product.price = row['precio'] - product.measuring_unit = row['unidad'] - product.save() categories = [n.strip() for n in row["categorias"].split("&")] for category in categories: From f807137a8ec97f66a79b242ade6982f81ab78fa3 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 29 Jun 2024 17:28:14 -0500 Subject: [PATCH 7/9] test: verificando que se preserve el id del producto en importaciones. --- tienda_ilusion/don_confiao/test_products.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tienda_ilusion/don_confiao/test_products.py b/tienda_ilusion/don_confiao/test_products.py index 6f2ea86..94870a6 100644 --- a/tienda_ilusion/don_confiao/test_products.py +++ b/tienda_ilusion/don_confiao/test_products.py @@ -3,7 +3,7 @@ from django.contrib.auth.models import AnonymousUser, User from django.conf import settings from .views import import_products, products -from .models import ProductCategory +from .models import ProductCategory, Product import os import json @@ -41,6 +41,13 @@ class TestProducts(TestCase): seconds_products = self._get_products() self.assertEqual(len(first_products), len(seconds_products)) + def test_preserve_id_on_import(self): + self._import_csv() + id_aceite = Product.objects.get(name='Aceite').id + self._import_csv('example_products2.csv') + id_post_updated = Product.objects.get(name='Aceite').id + self.assertEqual(id_aceite, id_post_updated) + def test_update_price(self): self._import_csv() first_products = self._get_products() From 47098c48af0b66ed0f9cde50225aca2ed36d5330 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 29 Jun 2024 18:12:25 -0500 Subject: [PATCH 8/9] fix: actualizacion de categorias en la importacion de productos. --- .../don_confiao/example_products2.csv | 2 +- tienda_ilusion/don_confiao/test_products.py | 15 +++++++++++++ tienda_ilusion/don_confiao/views.py | 21 +++++++++++-------- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/tienda_ilusion/don_confiao/example_products2.csv b/tienda_ilusion/don_confiao/example_products2.csv index f46428b..787e48d 100644 --- a/tienda_ilusion/don_confiao/example_products2.csv +++ b/tienda_ilusion/don_confiao/example_products2.csv @@ -1,4 +1,4 @@ "producto","unidad","precio","categorias" "Aceite","Unidad", 50000,"Aceites&Alimentos" "Café","Unidad", 15000,"Cafes&Alimentos" -"Arroz","Unidad", 6000,"Cafes&Alimentos" +"Arroz","Unidad", 6000,"Alimentos&Granos" diff --git a/tienda_ilusion/don_confiao/test_products.py b/tienda_ilusion/don_confiao/test_products.py index 94870a6..0b4e0dc 100644 --- a/tienda_ilusion/don_confiao/test_products.py +++ b/tienda_ilusion/don_confiao/test_products.py @@ -48,6 +48,21 @@ class TestProducts(TestCase): id_post_updated = Product.objects.get(name='Aceite').id self.assertEqual(id_aceite, id_post_updated) + def test_update_categories_on_import(self): + self._import_csv() + first_products = self._get_products() + first_categories = {p["name"]: p["categories"] for p in first_products} + self._import_csv('example_products2.csv') + updated_products = self._get_products() + updated_categories = {p["name"]: p["categories"] for p in updated_products} + + self.assertIn('Cafes', first_categories['Arroz']) + self.assertNotIn('Granos', first_categories['Arroz']) + + self.assertIn('Granos', updated_categories['Arroz']) + self.assertNotIn('Cafes', updated_categories['Arroz']) + + def test_update_price(self): self._import_csv() first_products = self._get_products() diff --git a/tienda_ilusion/don_confiao/views.py b/tienda_ilusion/don_confiao/views.py index 8f04092..257b779 100644 --- a/tienda_ilusion/don_confiao/views.py +++ b/tienda_ilusion/don_confiao/views.py @@ -55,6 +55,14 @@ def import_products(request): {'form': form} ) +def _categories_from_csv_string(categories_string, separator="&"): + categories = categories_string.split(separator) + clean_categories = [c.strip() for c in categories] + return [_category_from_name(category) for category in clean_categories] + +def _category_from_name(name): + return ProductCategory.objects.get_or_create(name=name)[0] + def handle_import_products_file(csv_file): data = io.StringIO(csv_file.read().decode('utf-8')) reader = csv.DictReader(data, quotechar='"') @@ -63,15 +71,10 @@ def handle_import_products_file(csv_file): name=row['producto'], defaults={ 'price': row['precio'], - 'measuring_unit': row['unidad'], + 'measuring_unit': row['unidad'] } ) - - categories = [n.strip() for n in row["categorias"].split("&")] + categories = _categories_from_csv_string(row["categorias"]) + product.categories.clear() for category in categories: - category_model, _ = ProductCategory.objects.get_or_create( - name=category - ) - category_model.save() - product.categories.add(category_model) - product.save() + product.categories.add(category) From 8ed13347d410baa498ca4559d74bff39112c8e77 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 29 Jun 2024 18:23:32 -0500 Subject: [PATCH 9/9] fix: eliminando vista que no se usa. --- .../don_confiao/templates/don_confiao/index.html | 4 ++-- .../templates/don_confiao/products_index.html | 12 ------------ tienda_ilusion/don_confiao/urls.py | 1 - tienda_ilusion/don_confiao/views.py | 5 +---- 4 files changed, 3 insertions(+), 19 deletions(-) delete mode 100644 tienda_ilusion/don_confiao/templates/don_confiao/products_index.html diff --git a/tienda_ilusion/don_confiao/templates/don_confiao/index.html b/tienda_ilusion/don_confiao/templates/don_confiao/index.html index 7d22ce5..7b791c0 100644 --- a/tienda_ilusion/don_confiao/templates/don_confiao/index.html +++ b/tienda_ilusion/don_confiao/templates/don_confiao/index.html @@ -2,6 +2,6 @@

Don Confiao

diff --git a/tienda_ilusion/don_confiao/templates/don_confiao/products_index.html b/tienda_ilusion/don_confiao/templates/don_confiao/products_index.html deleted file mode 100644 index 794e290..0000000 --- a/tienda_ilusion/don_confiao/templates/don_confiao/products_index.html +++ /dev/null @@ -1,12 +0,0 @@ -
- {% csrf_token %} -
-

Importar Productos

-
- {% if error_message %}

{{ error_message }}

{% endif %} -
- -
- -
-
diff --git a/tienda_ilusion/don_confiao/urls.py b/tienda_ilusion/don_confiao/urls.py index 17dc62b..a9b716f 100644 --- a/tienda_ilusion/don_confiao/urls.py +++ b/tienda_ilusion/don_confiao/urls.py @@ -8,6 +8,5 @@ urlpatterns = [ path("comprar", views.buy, name="buy"), path("compras", views.purchases, name="purchases"), path("productos", views.products, name="products"), - path("productos_index", views.products_index, name="products_index"), path("importar_productos", views.import_products, name="import_products") ] diff --git a/tienda_ilusion/don_confiao/views.py b/tienda_ilusion/don_confiao/views.py index 257b779..c4b7a5b 100644 --- a/tienda_ilusion/don_confiao/views.py +++ b/tienda_ilusion/don_confiao/views.py @@ -38,15 +38,12 @@ def products(request): return JsonResponse(rproducts, safe=False) -def products_index(request): - return render(request, 'don_confiao/products_index.html') - def import_products(request): if request.method == "POST": form = ImportProductsForm(request.POST, request.FILES) if form.is_valid(): handle_import_products_file(request.FILES["csv_file"]) - return HttpResponseRedirect("productos_index") + return HttpResponseRedirect("productos") else: form = ImportProductsForm() return render(