From ee38c29ce3050ad73fb1a6981d21d4d7ca35ccb1 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 13 Jul 2024 11:43:16 -0500 Subject: [PATCH 01/16] feat: implement reconciliation jar summary. --- .../don_confiao/migrations/0012_payment.py | 23 ++++++++ .../0013_rename_mount_payment_amount.py | 18 +++++++ ...ciliationjar_payment_reconciliation_jar.py | 27 ++++++++++ .../0015_alter_payment_reconciliation_jar.py | 19 +++++++ tienda_ilusion/don_confiao/models.py | 52 +++++++++++++++++++ tienda_ilusion/don_confiao/test_billing.py | 38 ++++++++++++++ 6 files changed, 177 insertions(+) create mode 100644 tienda_ilusion/don_confiao/migrations/0012_payment.py create mode 100644 tienda_ilusion/don_confiao/migrations/0013_rename_mount_payment_amount.py create mode 100644 tienda_ilusion/don_confiao/migrations/0014_reconciliationjar_payment_reconciliation_jar.py create mode 100644 tienda_ilusion/don_confiao/migrations/0015_alter_payment_reconciliation_jar.py create mode 100644 tienda_ilusion/don_confiao/test_billing.py diff --git a/tienda_ilusion/don_confiao/migrations/0012_payment.py b/tienda_ilusion/don_confiao/migrations/0012_payment.py new file mode 100644 index 0000000..474ef16 --- /dev/null +++ b/tienda_ilusion/don_confiao/migrations/0012_payment.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.6 on 2024-07-13 14:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('don_confiao', '0011_alter_product_name'), + ] + + operations = [ + migrations.CreateModel( + name='Payment', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date_time', models.DateTimeField()), + ('type_payment', models.CharField(choices=[('CASH', 'Cash'), ('CONFIAR', 'Confiar'), ('BANCOLOMBIA', 'Bancolombia')], default='CASH', max_length=30)), + ('mount', models.DecimalField(decimal_places=2, max_digits=9)), + ('description', models.CharField(blank=True, max_length=255, null=True)), + ], + ), + ] diff --git a/tienda_ilusion/don_confiao/migrations/0013_rename_mount_payment_amount.py b/tienda_ilusion/don_confiao/migrations/0013_rename_mount_payment_amount.py new file mode 100644 index 0000000..c55facb --- /dev/null +++ b/tienda_ilusion/don_confiao/migrations/0013_rename_mount_payment_amount.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.6 on 2024-07-13 15:56 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('don_confiao', '0012_payment'), + ] + + operations = [ + migrations.RenameField( + model_name='payment', + old_name='mount', + new_name='amount', + ), + ] diff --git a/tienda_ilusion/don_confiao/migrations/0014_reconciliationjar_payment_reconciliation_jar.py b/tienda_ilusion/don_confiao/migrations/0014_reconciliationjar_payment_reconciliation_jar.py new file mode 100644 index 0000000..9ea211f --- /dev/null +++ b/tienda_ilusion/don_confiao/migrations/0014_reconciliationjar_payment_reconciliation_jar.py @@ -0,0 +1,27 @@ +# Generated by Django 5.0.6 on 2024-07-13 16:35 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('don_confiao', '0013_rename_mount_payment_amount'), + ] + + operations = [ + migrations.CreateModel( + name='ReconciliationJar', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date_time', models.DateTimeField()), + ('description', models.CharField(blank=True, max_length=255, null=True)), + ], + ), + migrations.AddField( + model_name='payment', + name='reconciliation_jar', + field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.RESTRICT, to='don_confiao.reconciliationjar'), + ), + ] diff --git a/tienda_ilusion/don_confiao/migrations/0015_alter_payment_reconciliation_jar.py b/tienda_ilusion/don_confiao/migrations/0015_alter_payment_reconciliation_jar.py new file mode 100644 index 0000000..55d21cb --- /dev/null +++ b/tienda_ilusion/don_confiao/migrations/0015_alter_payment_reconciliation_jar.py @@ -0,0 +1,19 @@ +# Generated by Django 5.0.6 on 2024-07-13 16:36 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('don_confiao', '0014_reconciliationjar_payment_reconciliation_jar'), + ] + + operations = [ + migrations.AlterField( + model_name='payment', + name='reconciliation_jar', + field=models.ForeignKey(default=None, null=True, on_delete=django.db.models.deletion.RESTRICT, to='don_confiao.reconciliationjar'), + ), + ] diff --git a/tienda_ilusion/don_confiao/models.py b/tienda_ilusion/don_confiao/models.py index 7d7ee0a..357e3e0 100644 --- a/tienda_ilusion/don_confiao/models.py +++ b/tienda_ilusion/don_confiao/models.py @@ -44,3 +44,55 @@ class Product(models.Model): def __str__(self): return self.name + +class PyamentMethods(models.TextChoices): + CASH = 'CASH', _('Cash') + CONFIAR = 'CONFIAR', _('Confiar') + BANCOLOMBIA = 'BANCOLOMBIA', _('Bancolombia') + +class ReconciliationJarSummary(): + def __init__(self, payments): + self._validate_payments(payments) + self._payments = payments + + def _validate_payments(self, payments): + pass + + @property + def total(self): + return sum([p.amount for p in self.payments]) + + @property + def payments(self): + return self._payments + + +class ReconciliationJar(models.Model): + date_time = models.DateTimeField() + description = models.CharField(max_length=255, null=True, blank=True) + + +class Payment(models.Model): + date_time = models.DateTimeField() + type_payment = models.CharField( + max_length=30, + choices=PyamentMethods.choices, + default=PyamentMethods.CASH + ) + amount = models.DecimalField(max_digits=9, decimal_places=2) + reconciliation_jar = models.ForeignKey( + ReconciliationJar, + null=True, + default=None, + on_delete=models.RESTRICT + ) + description = models.CharField(max_length=255, null=True, blank=True) + + @classmethod + def get_reconciliation_jar_summary(cls): + return ReconciliationJarSummary( + cls.objects.filter( + type_payment=PyamentMethods.CASH, + reconciliation_jar=None + ) + ) diff --git a/tienda_ilusion/don_confiao/test_billing.py b/tienda_ilusion/don_confiao/test_billing.py new file mode 100644 index 0000000..4e6f212 --- /dev/null +++ b/tienda_ilusion/don_confiao/test_billing.py @@ -0,0 +1,38 @@ +from django.test import Client, TestCase +from .models import Payment + + +class TestBilling(TestCase): + + def test_reconciliation_jar_summary(self): + cash_payment1 = Payment() + cash_payment1.date_time = '2024-07-07 12:00:00' + cash_payment1.type_payment = 'CASH' + cash_payment1.amount = 132000 + cash_payment1.description = 'Saldo en compra' + cash_payment1.save() + + cash_payment2 = Payment() + cash_payment2.date_time = '2024-07-07 13:05:00' + cash_payment2.type_payment = 'CASH' + cash_payment2.amount = 32000 + cash_payment2.save() + + confiar_payment = Payment() + confiar_payment.date_time = '2024-07-07 16:00:00' + confiar_payment.type_payment = 'CONFIAR' + confiar_payment.amount = 85000 + confiar_payment.save() + + bancolombia_payment = Payment() + bancolombia_payment.date_time = '2024-07-07 12:30:00' + bancolombia_payment.type_payment = 'BANCOLOMBIA' + bancolombia_payment.amount = 12000 + bancolombia_payment.save() + + jar_summary = Payment.get_reconciliation_jar_summary() + self.assertEqual(164000, jar_summary.total) + self.assertSetEqual( + {cash_payment1, cash_payment2}, + set(jar_summary.payments) + ) From a8f8820a55a35dc9648e074afa00552f18be537f Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 13 Jul 2024 17:13:17 -0500 Subject: [PATCH 02/16] feat: implementing form to reconciliation jar. --- tienda_ilusion/don_confiao/forms.py | 18 ++++- ...nciliationjar_cash_discrepancy_and_more.py | 37 +++++++++ .../0017_reconciliationjar_draft.py | 18 +++++ ...18_rename_draft_reconciliationjar_valid.py | 18 +++++ ...rename_valid_reconciliationjar_is_valid.py | 18 +++++ ...020_remove_reconciliationjar_cash_float.py | 17 ++++ tienda_ilusion/don_confiao/models.py | 22 ++++++ .../don_confiao/reconciliate_jar.html | 2 + tienda_ilusion/don_confiao/test_billing.py | 77 ++++++++++++++++--- .../test_reconciliation_jar_client.py | 34 ++++++++ tienda_ilusion/don_confiao/urls.py | 3 +- tienda_ilusion/don_confiao/views.py | 19 ++++- 12 files changed, 266 insertions(+), 17 deletions(-) create mode 100644 tienda_ilusion/don_confiao/migrations/0016_reconciliationjar_cash_discrepancy_and_more.py create mode 100644 tienda_ilusion/don_confiao/migrations/0017_reconciliationjar_draft.py create mode 100644 tienda_ilusion/don_confiao/migrations/0018_rename_draft_reconciliationjar_valid.py create mode 100644 tienda_ilusion/don_confiao/migrations/0019_rename_valid_reconciliationjar_is_valid.py create mode 100644 tienda_ilusion/don_confiao/migrations/0020_remove_reconciliationjar_cash_float.py create mode 100644 tienda_ilusion/don_confiao/templates/don_confiao/reconciliate_jar.html create mode 100644 tienda_ilusion/don_confiao/test_reconciliation_jar_client.py diff --git a/tienda_ilusion/don_confiao/forms.py b/tienda_ilusion/don_confiao/forms.py index 4db321a..5836c83 100644 --- a/tienda_ilusion/don_confiao/forms.py +++ b/tienda_ilusion/don_confiao/forms.py @@ -1,7 +1,7 @@ from django import forms -from django.forms.widgets import DateInput +from django.forms.widgets import DateInput, DateTimeInput -from .models import Sale, SaleLine +from .models import Sale, SaleLine, ReconciliationJar class ImportProductsForm(forms.Form): @@ -37,3 +37,17 @@ LineaFormSet = forms.models.inlineformset_factory( extra=2, fields='__all__' ) + +class ReconciliationJarForm(forms.ModelForm): + class Meta: + model = ReconciliationJar + fields = [ + 'date_time', + 'description', + 'reconciler', + 'cash_taken', + 'cash_discrepancy', + ] + # widgets = { + # 'date_time': DateTimeInput(attrs={'type': 'datetime-local'}) + # } diff --git a/tienda_ilusion/don_confiao/migrations/0016_reconciliationjar_cash_discrepancy_and_more.py b/tienda_ilusion/don_confiao/migrations/0016_reconciliationjar_cash_discrepancy_and_more.py new file mode 100644 index 0000000..8bb7bd2 --- /dev/null +++ b/tienda_ilusion/don_confiao/migrations/0016_reconciliationjar_cash_discrepancy_and_more.py @@ -0,0 +1,37 @@ +# Generated by Django 5.0.6 on 2024-07-13 18:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('don_confiao', '0015_alter_payment_reconciliation_jar'), + ] + + operations = [ + migrations.AddField( + model_name='reconciliationjar', + name='cash_discrepancy', + field=models.DecimalField(decimal_places=2, default=0, max_digits=9), + preserve_default=False, + ), + migrations.AddField( + model_name='reconciliationjar', + name='cash_float', + field=models.DecimalField(decimal_places=2, default=0, max_digits=9), + preserve_default=False, + ), + migrations.AddField( + model_name='reconciliationjar', + name='cash_taken', + field=models.DecimalField(decimal_places=2, default=0, max_digits=9), + preserve_default=False, + ), + migrations.AddField( + model_name='reconciliationjar', + name='reconciler', + field=models.CharField(default='Jorge', max_length=255), + preserve_default=False, + ), + ] diff --git a/tienda_ilusion/don_confiao/migrations/0017_reconciliationjar_draft.py b/tienda_ilusion/don_confiao/migrations/0017_reconciliationjar_draft.py new file mode 100644 index 0000000..13dc149 --- /dev/null +++ b/tienda_ilusion/don_confiao/migrations/0017_reconciliationjar_draft.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.6 on 2024-07-13 18:15 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('don_confiao', '0016_reconciliationjar_cash_discrepancy_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='reconciliationjar', + name='draft', + field=models.BooleanField(default=False), + ), + ] diff --git a/tienda_ilusion/don_confiao/migrations/0018_rename_draft_reconciliationjar_valid.py b/tienda_ilusion/don_confiao/migrations/0018_rename_draft_reconciliationjar_valid.py new file mode 100644 index 0000000..7228161 --- /dev/null +++ b/tienda_ilusion/don_confiao/migrations/0018_rename_draft_reconciliationjar_valid.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.6 on 2024-07-13 18:19 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('don_confiao', '0017_reconciliationjar_draft'), + ] + + operations = [ + migrations.RenameField( + model_name='reconciliationjar', + old_name='draft', + new_name='valid', + ), + ] diff --git a/tienda_ilusion/don_confiao/migrations/0019_rename_valid_reconciliationjar_is_valid.py b/tienda_ilusion/don_confiao/migrations/0019_rename_valid_reconciliationjar_is_valid.py new file mode 100644 index 0000000..a0d7a02 --- /dev/null +++ b/tienda_ilusion/don_confiao/migrations/0019_rename_valid_reconciliationjar_is_valid.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.6 on 2024-07-13 19:56 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('don_confiao', '0018_rename_draft_reconciliationjar_valid'), + ] + + operations = [ + migrations.RenameField( + model_name='reconciliationjar', + old_name='valid', + new_name='is_valid', + ), + ] diff --git a/tienda_ilusion/don_confiao/migrations/0020_remove_reconciliationjar_cash_float.py b/tienda_ilusion/don_confiao/migrations/0020_remove_reconciliationjar_cash_float.py new file mode 100644 index 0000000..dea5619 --- /dev/null +++ b/tienda_ilusion/don_confiao/migrations/0020_remove_reconciliationjar_cash_float.py @@ -0,0 +1,17 @@ +# Generated by Django 5.0.6 on 2024-07-13 20:13 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('don_confiao', '0019_rename_valid_reconciliationjar_is_valid'), + ] + + operations = [ + migrations.RemoveField( + model_name='reconciliationjar', + name='cash_float', + ), + ] diff --git a/tienda_ilusion/don_confiao/models.py b/tienda_ilusion/don_confiao/models.py index 357e3e0..579189f 100644 --- a/tienda_ilusion/don_confiao/models.py +++ b/tienda_ilusion/don_confiao/models.py @@ -1,5 +1,7 @@ from django.db import models from django.utils.translation import gettext_lazy as _ +from django.core.exceptions import ValidationError + class Sale(models.Model): @@ -23,15 +25,18 @@ class SaleLine(models.Model): def __str__(self): return f"{self.sale} - {self.product}" + class MeasuringUnits(models.TextChoices): UNIT = 'UNIT', _('Unit') + class ProductCategory(models.Model): name = models.CharField(max_length=100, unique=True) def __str__(self): return self.name + class Product(models.Model): name = models.CharField(max_length=100, unique=True) price = models.DecimalField(max_digits=9, decimal_places=2) @@ -45,11 +50,13 @@ class Product(models.Model): def __str__(self): return self.name + class PyamentMethods(models.TextChoices): CASH = 'CASH', _('Cash') CONFIAR = 'CONFIAR', _('Confiar') BANCOLOMBIA = 'BANCOLOMBIA', _('Bancolombia') + class ReconciliationJarSummary(): def __init__(self, payments): self._validate_payments(payments) @@ -68,9 +75,24 @@ class ReconciliationJarSummary(): class ReconciliationJar(models.Model): + is_valid = models.BooleanField(default=False) date_time = models.DateTimeField() description = models.CharField(max_length=255, null=True, blank=True) + reconciler = models.CharField(max_length=255, null=False, blank=False) + cash_taken = models.DecimalField(max_digits=9, decimal_places=2) + cash_discrepancy = models.DecimalField(max_digits=9, decimal_places=2) + def clean(self): + payments_amount = sum([p.amount for p in self.payment_set.all()]) + reconciliation_ammount = sum([ + self.cash_taken, + self.cash_discrepancy, + ]) + if reconciliation_ammount != payments_amount: + raise ValidationError( + {"cash_take": _("The taken ammount has discrepancy.")} + ) + self.is_valid = True class Payment(models.Model): date_time = models.DateTimeField() diff --git a/tienda_ilusion/don_confiao/templates/don_confiao/reconciliate_jar.html b/tienda_ilusion/don_confiao/templates/don_confiao/reconciliate_jar.html new file mode 100644 index 0000000..2da1ac5 --- /dev/null +++ b/tienda_ilusion/don_confiao/templates/don_confiao/reconciliate_jar.html @@ -0,0 +1,2 @@ + +{{ summary.total }} diff --git a/tienda_ilusion/don_confiao/test_billing.py b/tienda_ilusion/don_confiao/test_billing.py index 4e6f212..49f8e97 100644 --- a/tienda_ilusion/don_confiao/test_billing.py +++ b/tienda_ilusion/don_confiao/test_billing.py @@ -1,22 +1,21 @@ from django.test import Client, TestCase -from .models import Payment +from django.core.exceptions import ValidationError +from .models import Payment, ReconciliationJar class TestBilling(TestCase): def test_reconciliation_jar_summary(self): - cash_payment1 = Payment() - cash_payment1.date_time = '2024-07-07 12:00:00' - cash_payment1.type_payment = 'CASH' - cash_payment1.amount = 132000 - cash_payment1.description = 'Saldo en compra' - cash_payment1.save() + cash_payment1, cash_payment2 = self._create_two_cash_payments() + jar_summary = Payment.get_reconciliation_jar_summary() + self.assertEqual(164000, jar_summary.total) + self.assertSetEqual( + {cash_payment1, cash_payment2}, + set(jar_summary.payments) + ) - cash_payment2 = Payment() - cash_payment2.date_time = '2024-07-07 13:05:00' - cash_payment2.type_payment = 'CASH' - cash_payment2.amount = 32000 - cash_payment2.save() + def test_reconciliation_jar_summary_use_only_cash(self): + cash_payment1, cash_payment2 = self._create_two_cash_payments() confiar_payment = Payment() confiar_payment.date_time = '2024-07-07 16:00:00' @@ -36,3 +35,57 @@ class TestBilling(TestCase): {cash_payment1, cash_payment2}, set(jar_summary.payments) ) + + def test_fail_validate_reconciliation_jar_with_discrepancy_values(self): + cash_payment1, cash_payment2 = self._create_two_cash_payments() + + jar_summary = Payment.get_reconciliation_jar_summary() + + reconciliation_jar = ReconciliationJar() + reconciliation_jar.date_time = '2024-07-13 13:02:00' + reconciliation_jar.description = "test reconcialiation jar" + reconciliation_jar.reconcilier = 'Jorge' + reconciliation_jar.cash_float = 0 + reconciliation_jar.cash_taken = 0 + reconciliation_jar.cash_discrepancy = 0 + reconciliation_jar.save() + + for payment in jar_summary.payments: + reconciliation_jar.payment_set.add(payment) + with self.assertRaises(ValidationError): + reconciliation_jar.clean() + + def test_validate_reconciliation_jar_with_cash_float(self): + cash_payment1, cash_payment2 = self._create_two_cash_payments() + jar_summary = Payment.get_reconciliation_jar_summary() + + reconciliation_jar = ReconciliationJar() + reconciliation_jar.date_time = '2024-07-13 13:02:00' + reconciliation_jar.description = "test reconcialiation jar" + reconciliation_jar.reconcilier = 'Jorge' + reconciliation_jar.cash_float = 10000 + reconciliation_jar.cash_taken = jar_summary.total + reconciliation_jar.cash_discrepancy = 0 + reconciliation_jar.save() + + for payment in jar_summary.payments: + reconciliation_jar.payment_set.add(payment) + reconciliation_jar.clean() + reconciliation_jar.save() + self.assertTrue(reconciliation_jar.is_valid) + + def _create_two_cash_payments(self): + cash_payment1 = Payment() + cash_payment1.date_time = '2024-07-07 12:00:00' + cash_payment1.type_payment = 'CASH' + cash_payment1.amount = 132000 + cash_payment1.description = 'Saldo en compra' + cash_payment1.save() + + cash_payment2 = Payment() + cash_payment2.date_time = '2024-07-07 13:05:00' + cash_payment2.type_payment = 'CASH' + cash_payment2.amount = 32000 + cash_payment2.save() + + return [cash_payment1, cash_payment2] diff --git a/tienda_ilusion/don_confiao/test_reconciliation_jar_client.py b/tienda_ilusion/don_confiao/test_reconciliation_jar_client.py new file mode 100644 index 0000000..04ce878 --- /dev/null +++ b/tienda_ilusion/don_confiao/test_reconciliation_jar_client.py @@ -0,0 +1,34 @@ +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 +from .models import Payment + + +class TestReconciliationJarClient(TestCase): + def setUp(self): + self.client = Client() + + def test_get_summary_info_on_view(self): + self._generate_two_cash_payments() + response = self.client.get("/don_confiao/cuadrar_tarro") + self.assertEqual(response.status_code, 200) + # raise Exception(response.content.decode('utf-8')) + self.assertEqual(response.context["summary"].total, 160000) + self.assertIn('160000', response.content.decode('utf-8')) + + def _generate_two_cash_payments(self): + cash_payment1 = Payment() + cash_payment1.date_time = '2024-07-07 12:00:00' + cash_payment1.type_payment = 'CASH' + cash_payment1.amount = 130000 + cash_payment1.description = 'Saldo en compra' + cash_payment1.save() + # raise Exception (cash_payment1.id) + + cash_payment2 = Payment() + cash_payment2.date_time = '2024-07-07 13:05:00' + cash_payment2.type_payment = 'CASH' + cash_payment2.amount = 30000 + cash_payment2.save() diff --git a/tienda_ilusion/don_confiao/urls.py b/tienda_ilusion/don_confiao/urls.py index a9b716f..10f9518 100644 --- a/tienda_ilusion/don_confiao/urls.py +++ b/tienda_ilusion/don_confiao/urls.py @@ -8,5 +8,6 @@ urlpatterns = [ path("comprar", views.buy, name="buy"), path("compras", views.purchases, name="purchases"), path("productos", views.products, name="products"), - path("importar_productos", views.import_products, name="import_products") + path("importar_productos", views.import_products, name="import_products"), + path("cuadrar_tarro", views.reconciliate_jar, name="reconciliate_jar"), ] diff --git a/tienda_ilusion/don_confiao/views.py b/tienda_ilusion/don_confiao/views.py index 1904ab6..5d7e9e2 100644 --- a/tienda_ilusion/don_confiao/views.py +++ b/tienda_ilusion/don_confiao/views.py @@ -2,8 +2,8 @@ from django.shortcuts import render from django.http import HttpResponse, HttpResponseRedirect, JsonResponse from django.template import loader -from .models import Sale, Product, ProductCategory -from .forms import ImportProductsForm, PurchaseForm, LineaFormSet +from .models import Sale, Product, ProductCategory, Payment +from .forms import ImportProductsForm, PurchaseForm, LineaFormSet, ReconciliationJarForm import csv import io @@ -69,6 +69,21 @@ def import_products(request): {'form': form} ) + +def reconciliate_jar(request): + if request.method == 'POST': + return HttpResponseRedirect("cuadres") + + form = ReconciliationJarForm() + summary = Payment.get_reconciliation_jar_summary() + # raise Exception(Payment.get_reconciliation_jar_summary().payments) + return render( + request, + "don_confiao/reconciliate_jar.html", + {'summary': summary, 'form': form} + ) + + def _categories_from_csv_string(categories_string, separator="&"): categories = categories_string.split(separator) clean_categories = [c.strip() for c in categories] From 3570af7b60daaa8e7c5c1f55f49ac0d398b66888 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 13 Jul 2024 17:17:45 -0500 Subject: [PATCH 03/16] refactor: rename column. --- tienda_ilusion/don_confiao/forms.py | 2 +- ...reconciler_reconciliationjar_reconcilier.py | 18 ++++++++++++++++++ tienda_ilusion/don_confiao/models.py | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 tienda_ilusion/don_confiao/migrations/0021_rename_reconciler_reconciliationjar_reconcilier.py diff --git a/tienda_ilusion/don_confiao/forms.py b/tienda_ilusion/don_confiao/forms.py index 5836c83..8fc05c9 100644 --- a/tienda_ilusion/don_confiao/forms.py +++ b/tienda_ilusion/don_confiao/forms.py @@ -44,7 +44,7 @@ class ReconciliationJarForm(forms.ModelForm): fields = [ 'date_time', 'description', - 'reconciler', + 'reconcilier', 'cash_taken', 'cash_discrepancy', ] diff --git a/tienda_ilusion/don_confiao/migrations/0021_rename_reconciler_reconciliationjar_reconcilier.py b/tienda_ilusion/don_confiao/migrations/0021_rename_reconciler_reconciliationjar_reconcilier.py new file mode 100644 index 0000000..20e8f6e --- /dev/null +++ b/tienda_ilusion/don_confiao/migrations/0021_rename_reconciler_reconciliationjar_reconcilier.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.6 on 2024-07-13 22:16 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('don_confiao', '0020_remove_reconciliationjar_cash_float'), + ] + + operations = [ + migrations.RenameField( + model_name='reconciliationjar', + old_name='reconciler', + new_name='reconcilier', + ), + ] diff --git a/tienda_ilusion/don_confiao/models.py b/tienda_ilusion/don_confiao/models.py index 579189f..78c4746 100644 --- a/tienda_ilusion/don_confiao/models.py +++ b/tienda_ilusion/don_confiao/models.py @@ -78,7 +78,7 @@ class ReconciliationJar(models.Model): is_valid = models.BooleanField(default=False) date_time = models.DateTimeField() description = models.CharField(max_length=255, null=True, blank=True) - reconciler = models.CharField(max_length=255, null=False, blank=False) + reconcilier = models.CharField(max_length=255, null=False, blank=False) cash_taken = models.DecimalField(max_digits=9, decimal_places=2) cash_discrepancy = models.DecimalField(max_digits=9, decimal_places=2) From f9ee2ad9c29bdb696d169365c4bd59a3a1c3ff76 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 13 Jul 2024 17:38:12 -0500 Subject: [PATCH 04/16] view: improve reconciliate_jar template. --- .../don_confiao/reconciliate_jar.html | 28 ++++++++++++++++++- tienda_ilusion/don_confiao/views.py | 1 - 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/tienda_ilusion/don_confiao/templates/don_confiao/reconciliate_jar.html b/tienda_ilusion/don_confiao/templates/don_confiao/reconciliate_jar.html index 2da1ac5..ff0d778 100644 --- a/tienda_ilusion/don_confiao/templates/don_confiao/reconciliate_jar.html +++ b/tienda_ilusion/don_confiao/templates/don_confiao/reconciliate_jar.html @@ -1,2 +1,28 @@ -{{ summary.total }} +{% if summary.total %} +
+

Pagos No reconciliados

+ + + Monto + {% for payment in summary.payments %} + + {% endfor %} + + {{ summary.total }} + + +
Fecha
payment.date_timepayment.amount
+ {% csrf_token %} + {{ form.as_table }} +
+
+ +{% else %} +
+

No hay pagos registrados.

+
+{% endif %} + + + diff --git a/tienda_ilusion/don_confiao/views.py b/tienda_ilusion/don_confiao/views.py index 5d7e9e2..8d2b34e 100644 --- a/tienda_ilusion/don_confiao/views.py +++ b/tienda_ilusion/don_confiao/views.py @@ -76,7 +76,6 @@ def reconciliate_jar(request): form = ReconciliationJarForm() summary = Payment.get_reconciliation_jar_summary() - # raise Exception(Payment.get_reconciliation_jar_summary().payments) return render( request, "don_confiao/reconciliate_jar.html", From 74d2e0d2345ea0d4d8e0052ab2b6dfad15fa4184 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 13 Jul 2024 17:38:33 -0500 Subject: [PATCH 05/16] admin: set Payment and reconciliatoJar in 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 0756544..fe34059 100644 --- a/tienda_ilusion/don_confiao/admin.py +++ b/tienda_ilusion/don_confiao/admin.py @@ -1,7 +1,9 @@ from django.contrib import admin -from .models import Sale, SaleLine, Product, ProductCategory +from .models import Sale, SaleLine, Product, ProductCategory, Payment, ReconciliationJar admin.site.register(Sale) admin.site.register(SaleLine) admin.site.register(Product) admin.site.register(ProductCategory) +admin.site.register(Payment) +admin.site.register(ReconciliationJar) From 08deb9d4ec346841da0bb3cbeadf3925d5e04fad Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 13 Jul 2024 17:48:57 -0500 Subject: [PATCH 06/16] view: improve reconciliate_jar. --- tienda_ilusion/don_confiao/forms.py | 6 +++--- .../0022_alter_payment_reconciliation_jar.py | 19 +++++++++++++++++ tienda_ilusion/don_confiao/models.py | 1 + .../don_confiao/reconciliate_jar.html | 21 ++++++++++++------- 4 files changed, 36 insertions(+), 11 deletions(-) create mode 100644 tienda_ilusion/don_confiao/migrations/0022_alter_payment_reconciliation_jar.py diff --git a/tienda_ilusion/don_confiao/forms.py b/tienda_ilusion/don_confiao/forms.py index 8fc05c9..758b119 100644 --- a/tienda_ilusion/don_confiao/forms.py +++ b/tienda_ilusion/don_confiao/forms.py @@ -48,6 +48,6 @@ class ReconciliationJarForm(forms.ModelForm): 'cash_taken', 'cash_discrepancy', ] - # widgets = { - # 'date_time': DateTimeInput(attrs={'type': 'datetime-local'}) - # } + widgets = { + 'date_time': DateTimeInput(attrs={'type': 'datetime-local'}) + } diff --git a/tienda_ilusion/don_confiao/migrations/0022_alter_payment_reconciliation_jar.py b/tienda_ilusion/don_confiao/migrations/0022_alter_payment_reconciliation_jar.py new file mode 100644 index 0000000..5956a97 --- /dev/null +++ b/tienda_ilusion/don_confiao/migrations/0022_alter_payment_reconciliation_jar.py @@ -0,0 +1,19 @@ +# Generated by Django 5.0.6 on 2024-07-13 22:39 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('don_confiao', '0021_rename_reconciler_reconciliationjar_reconcilier'), + ] + + operations = [ + migrations.AlterField( + model_name='payment', + name='reconciliation_jar', + field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.RESTRICT, to='don_confiao.reconciliationjar'), + ), + ] diff --git a/tienda_ilusion/don_confiao/models.py b/tienda_ilusion/don_confiao/models.py index 78c4746..2874dac 100644 --- a/tienda_ilusion/don_confiao/models.py +++ b/tienda_ilusion/don_confiao/models.py @@ -106,6 +106,7 @@ class Payment(models.Model): ReconciliationJar, null=True, default=None, + blank=True, on_delete=models.RESTRICT ) description = models.CharField(max_length=255, null=True, blank=True) diff --git a/tienda_ilusion/don_confiao/templates/don_confiao/reconciliate_jar.html b/tienda_ilusion/don_confiao/templates/don_confiao/reconciliate_jar.html index ff0d778..16fa5dc 100644 --- a/tienda_ilusion/don_confiao/templates/don_confiao/reconciliate_jar.html +++ b/tienda_ilusion/don_confiao/templates/don_confiao/reconciliate_jar.html @@ -1,22 +1,27 @@ {% if summary.total %} -
+

Pagos No reconciliados

- +
- Monto - {% for payment in summary.payments %} - - {% endfor %} + - {{ summary.total }} + + {% for payment in summary.payments %} + + {% endfor %} + + + + +
Fecha
payment.date_timepayment.amount
FechaMonto
{{ payment.date_time }}{{ payment.amount }}
Total{{ summary.total }}
{% csrf_token %} {{ form.as_table }}
-
+
{% else %}
From a3c8189d8cdbd8d643f7c292681027cb5d56e13e Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 20 Jul 2024 11:44:49 -0500 Subject: [PATCH 07/16] feat: create a correct reconciliation jar. --- tienda_ilusion/don_confiao/models.py | 2 +- tienda_ilusion/don_confiao/test_billing.py | 3 ++- .../test_reconciliation_jar_client.py | 16 +++++++++++-- tienda_ilusion/don_confiao/urls.py | 1 + tienda_ilusion/don_confiao/views.py | 23 +++++++++++++++---- 5 files changed, 37 insertions(+), 8 deletions(-) diff --git a/tienda_ilusion/don_confiao/models.py b/tienda_ilusion/don_confiao/models.py index 2874dac..fb429ec 100644 --- a/tienda_ilusion/don_confiao/models.py +++ b/tienda_ilusion/don_confiao/models.py @@ -82,7 +82,7 @@ class ReconciliationJar(models.Model): cash_taken = models.DecimalField(max_digits=9, decimal_places=2) cash_discrepancy = models.DecimalField(max_digits=9, decimal_places=2) - def clean(self): + def manual_clean(self): payments_amount = sum([p.amount for p in self.payment_set.all()]) reconciliation_ammount = sum([ self.cash_taken, diff --git a/tienda_ilusion/don_confiao/test_billing.py b/tienda_ilusion/don_confiao/test_billing.py index 49f8e97..ae9f6b0 100644 --- a/tienda_ilusion/don_confiao/test_billing.py +++ b/tienda_ilusion/don_confiao/test_billing.py @@ -53,7 +53,7 @@ class TestBilling(TestCase): for payment in jar_summary.payments: reconciliation_jar.payment_set.add(payment) with self.assertRaises(ValidationError): - reconciliation_jar.clean() + reconciliation_jar.manual_clean() def test_validate_reconciliation_jar_with_cash_float(self): cash_payment1, cash_payment2 = self._create_two_cash_payments() @@ -72,6 +72,7 @@ class TestBilling(TestCase): reconciliation_jar.payment_set.add(payment) reconciliation_jar.clean() reconciliation_jar.save() + reconciliation_jar.manual_clean() self.assertTrue(reconciliation_jar.is_valid) def _create_two_cash_payments(self): diff --git a/tienda_ilusion/don_confiao/test_reconciliation_jar_client.py b/tienda_ilusion/don_confiao/test_reconciliation_jar_client.py index 04ce878..fa008d8 100644 --- a/tienda_ilusion/don_confiao/test_reconciliation_jar_client.py +++ b/tienda_ilusion/don_confiao/test_reconciliation_jar_client.py @@ -14,10 +14,23 @@ class TestReconciliationJarClient(TestCase): self._generate_two_cash_payments() response = self.client.get("/don_confiao/cuadrar_tarro") self.assertEqual(response.status_code, 200) - # raise Exception(response.content.decode('utf-8')) self.assertEqual(response.context["summary"].total, 160000) self.assertIn('160000', response.content.decode('utf-8')) + def test_create_reconciliation_jar(self): + self._generate_two_cash_payments() + response = self.client.post( + "/don_confiao/cuadrar_tarro", + { + "date_time": "2024-07-20T00:00", + "description": "Cuadre de prueba", + "reconcilier": "Jorge", + "cash_taken": "100000", + "cash_discrepancy": "60000", + } + ) + self.assertRedirects(response, '/don_confiao/cuadres') + def _generate_two_cash_payments(self): cash_payment1 = Payment() cash_payment1.date_time = '2024-07-07 12:00:00' @@ -25,7 +38,6 @@ class TestReconciliationJarClient(TestCase): cash_payment1.amount = 130000 cash_payment1.description = 'Saldo en compra' cash_payment1.save() - # raise Exception (cash_payment1.id) cash_payment2 = Payment() cash_payment2.date_time = '2024-07-07 13:05:00' diff --git a/tienda_ilusion/don_confiao/urls.py b/tienda_ilusion/don_confiao/urls.py index 10f9518..bdea574 100644 --- a/tienda_ilusion/don_confiao/urls.py +++ b/tienda_ilusion/don_confiao/urls.py @@ -10,4 +10,5 @@ urlpatterns = [ path("productos", views.products, name="products"), path("importar_productos", views.import_products, name="import_products"), path("cuadrar_tarro", views.reconciliate_jar, name="reconciliate_jar"), + path("cuadres", views.reconciliate_jar, name="reconciliations"), ] diff --git a/tienda_ilusion/don_confiao/views.py b/tienda_ilusion/don_confiao/views.py index 8d2b34e..f981775 100644 --- a/tienda_ilusion/don_confiao/views.py +++ b/tienda_ilusion/don_confiao/views.py @@ -1,6 +1,7 @@ from django.shortcuts import render from django.http import HttpResponse, HttpResponseRedirect, JsonResponse from django.template import loader +from django.core.exceptions import ValidationError from .models import Sale, Product, ProductCategory, Payment from .forms import ImportProductsForm, PurchaseForm, LineaFormSet, ReconciliationJarForm @@ -71,17 +72,31 @@ def import_products(request): def reconciliate_jar(request): - if request.method == 'POST': - return HttpResponseRedirect("cuadres") - - form = ReconciliationJarForm() summary = Payment.get_reconciliation_jar_summary() + if request.method == 'POST': + form = ReconciliationJarForm(request.POST) + reconciliation = form.save() + try: + if form.is_valid(): + reconciliation.payment_set.set(summary.payments) + reconciliation.manual_clean() + form.save() + return HttpResponseRedirect('cuadres') + except Exception as e: + reconciliation.payment_set.set({}) + reconciliation.delete() + raise e + else: + form = ReconciliationJarForm() return render( request, "don_confiao/reconciliate_jar.html", {'summary': summary, 'form': form} ) +def reconciliations(request): + return HttpResponse('

Reconciliaciones

') + def _categories_from_csv_string(categories_string, separator="&"): categories = categories_string.split(separator) From 58792961325dc2343d0774de7f8dd6701f559d21 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 27 Jul 2024 12:37:31 -0500 Subject: [PATCH 08/16] fix: ReconciliationJar. --- tienda_ilusion/don_confiao/models.py | 24 ++++++++++++++++------ tienda_ilusion/don_confiao/test_billing.py | 13 +++++------- tienda_ilusion/don_confiao/views.py | 17 ++++++--------- 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/tienda_ilusion/don_confiao/models.py b/tienda_ilusion/don_confiao/models.py index fb429ec..91d1199 100644 --- a/tienda_ilusion/don_confiao/models.py +++ b/tienda_ilusion/don_confiao/models.py @@ -2,6 +2,7 @@ from django.db import models from django.utils.translation import gettext_lazy as _ from django.core.exceptions import ValidationError +from decimal import Decimal class Sale(models.Model): @@ -82,16 +83,27 @@ class ReconciliationJar(models.Model): cash_taken = models.DecimalField(max_digits=9, decimal_places=2) cash_discrepancy = models.DecimalField(max_digits=9, decimal_places=2) - def manual_clean(self): - payments_amount = sum([p.amount for p in self.payment_set.all()]) - reconciliation_ammount = sum([ + def clean(self): + if not self.is_valid: + payments = Payment.get_reconciliation_jar_summary().payments + else: + payments = self.payment_set.all() + + payments_amount = Decimal(sum([p.amount for p in payments])) + reconciliation_ammount = Decimal(sum([ self.cash_taken, self.cash_discrepancy, - ]) - if reconciliation_ammount != payments_amount: + ])) + + equal_ammounts = reconciliation_ammount.compare(payments_amount) == Decimal('0') + if not equal_ammounts: raise ValidationError( - {"cash_take": _("The taken ammount has discrepancy.")} + {"cash_taken": _("The taken ammount has discrepancy.")} ) + + def add_payments(self, payments): + for payment in payments: + self.payment_set.add(payment) self.is_valid = True class Payment(models.Model): diff --git a/tienda_ilusion/don_confiao/test_billing.py b/tienda_ilusion/don_confiao/test_billing.py index ae9f6b0..9b6372b 100644 --- a/tienda_ilusion/don_confiao/test_billing.py +++ b/tienda_ilusion/don_confiao/test_billing.py @@ -1,4 +1,4 @@ -from django.test import Client, TestCase +from django.test import TestCase from django.core.exceptions import ValidationError from .models import Payment, ReconciliationJar @@ -50,10 +50,10 @@ class TestBilling(TestCase): reconciliation_jar.cash_discrepancy = 0 reconciliation_jar.save() - for payment in jar_summary.payments: - reconciliation_jar.payment_set.add(payment) + reconciliation_jar.add_payments(jar_summary.payments) + with self.assertRaises(ValidationError): - reconciliation_jar.manual_clean() + reconciliation_jar.clean() def test_validate_reconciliation_jar_with_cash_float(self): cash_payment1, cash_payment2 = self._create_two_cash_payments() @@ -63,16 +63,13 @@ class TestBilling(TestCase): reconciliation_jar.date_time = '2024-07-13 13:02:00' reconciliation_jar.description = "test reconcialiation jar" reconciliation_jar.reconcilier = 'Jorge' - reconciliation_jar.cash_float = 10000 reconciliation_jar.cash_taken = jar_summary.total reconciliation_jar.cash_discrepancy = 0 reconciliation_jar.save() - for payment in jar_summary.payments: - reconciliation_jar.payment_set.add(payment) + reconciliation_jar.add_payments(jar_summary.payments) reconciliation_jar.clean() reconciliation_jar.save() - reconciliation_jar.manual_clean() self.assertTrue(reconciliation_jar.is_valid) def _create_two_cash_payments(self): diff --git a/tienda_ilusion/don_confiao/views.py b/tienda_ilusion/don_confiao/views.py index f981775..8d7222c 100644 --- a/tienda_ilusion/don_confiao/views.py +++ b/tienda_ilusion/don_confiao/views.py @@ -75,17 +75,12 @@ def reconciliate_jar(request): summary = Payment.get_reconciliation_jar_summary() if request.method == 'POST': form = ReconciliationJarForm(request.POST) - reconciliation = form.save() - try: - if form.is_valid(): - reconciliation.payment_set.set(summary.payments) - reconciliation.manual_clean() - form.save() - return HttpResponseRedirect('cuadres') - except Exception as e: - reconciliation.payment_set.set({}) - reconciliation.delete() - raise e + if form.is_valid(): + reconciliation = form.save() + reconciliation.add_payments(summary.payments) + reconciliation.clean() + reconciliation.save() + return HttpResponseRedirect('cuadres') else: form = ReconciliationJarForm() return render( From 02fba454ba1054b5eb9630e9c735a65bce3cf672 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 27 Jul 2024 13:19:37 -0500 Subject: [PATCH 09/16] Fix: Clean Home, Crear lineas de Venta --- tienda_ilusion/don_confiao/forms.py | 2 ++ tienda_ilusion/don_confiao/models.py | 1 + tienda_ilusion/don_confiao/tests/__init__.py | 1 + .../don_confiao/{ => tests}/test_products.py | 10 ++++----- .../don_confiao/{ => tests}/tests.py | 2 +- tienda_ilusion/don_confiao/views.py | 21 +++++++++++++------ 6 files changed, 24 insertions(+), 13 deletions(-) create mode 100644 tienda_ilusion/don_confiao/tests/__init__.py rename tienda_ilusion/don_confiao/{ => tests}/test_products.py (93%) rename tienda_ilusion/don_confiao/{ => tests}/tests.py (98%) diff --git a/tienda_ilusion/don_confiao/forms.py b/tienda_ilusion/don_confiao/forms.py index 758b119..85aeec0 100644 --- a/tienda_ilusion/don_confiao/forms.py +++ b/tienda_ilusion/don_confiao/forms.py @@ -7,6 +7,7 @@ from .models import Sale, SaleLine, ReconciliationJar class ImportProductsForm(forms.Form): csv_file = forms.FileField() + class PurchaseForm(forms.ModelForm): class Meta: model = Sale @@ -20,6 +21,7 @@ class PurchaseForm(forms.ModelForm): 'date': DateInput(attrs={'type': 'date'}) } + class PurchaseLineForm(forms.ModelForm): class Meta: model = SaleLine diff --git a/tienda_ilusion/don_confiao/models.py b/tienda_ilusion/don_confiao/models.py index 91d1199..36b48e9 100644 --- a/tienda_ilusion/don_confiao/models.py +++ b/tienda_ilusion/don_confiao/models.py @@ -4,6 +4,7 @@ from django.core.exceptions import ValidationError from decimal import Decimal + class Sale(models.Model): customer = models.CharField(max_length=100) diff --git a/tienda_ilusion/don_confiao/tests/__init__.py b/tienda_ilusion/don_confiao/tests/__init__.py new file mode 100644 index 0000000..e5a0d9b --- /dev/null +++ b/tienda_ilusion/don_confiao/tests/__init__.py @@ -0,0 +1 @@ +#!/usr/bin/env python3 diff --git a/tienda_ilusion/don_confiao/test_products.py b/tienda_ilusion/don_confiao/tests/test_products.py similarity index 93% rename from tienda_ilusion/don_confiao/test_products.py rename to tienda_ilusion/don_confiao/tests/test_products.py index 0b4e0dc..0c12f74 100644 --- a/tienda_ilusion/don_confiao/test_products.py +++ b/tienda_ilusion/don_confiao/tests/test_products.py @@ -1,13 +1,11 @@ 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 -from .models import ProductCategory, Product +from ..models import ProductCategory, Product import os import json + class TestProducts(TestCase): def setUp(self): self.client = Client() @@ -54,7 +52,8 @@ class TestProducts(TestCase): 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} + updated_categories = { + p["name"]: p["categories"] for p in updated_products} self.assertIn('Cafes', first_categories['Arroz']) self.assertNotIn('Granos', first_categories['Arroz']) @@ -62,7 +61,6 @@ class TestProducts(TestCase): 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/tests.py b/tienda_ilusion/don_confiao/tests/tests.py similarity index 98% rename from tienda_ilusion/don_confiao/tests.py rename to tienda_ilusion/don_confiao/tests/tests.py index 27b5d3e..771ec89 100644 --- a/tienda_ilusion/don_confiao/tests.py +++ b/tienda_ilusion/don_confiao/tests/tests.py @@ -1,5 +1,5 @@ from django.test import TestCase -from .models import Sale, SaleLine +from ..models import Sale, SaleLine class ConfiaoTest(TestCase): diff --git a/tienda_ilusion/don_confiao/views.py b/tienda_ilusion/don_confiao/views.py index 8d7222c..25a67da 100644 --- a/tienda_ilusion/don_confiao/views.py +++ b/tienda_ilusion/don_confiao/views.py @@ -1,6 +1,7 @@ from django.shortcuts import render + from django.http import HttpResponse, HttpResponseRedirect, JsonResponse -from django.template import loader +#from django.template import loader from django.core.exceptions import ValidationError from .models import Sale, Product, ProductCategory, Payment @@ -9,18 +10,22 @@ from .forms import ImportProductsForm, PurchaseForm, LineaFormSet, Reconciliatio import csv import io + def index(request): return render(request, 'don_confiao/index.html') + def buy(request): if request.method == "POST": sale_form = PurchaseForm(request.POST) sale_linea_form = LineaFormSet(request.POST) - if sale_form.is_valid(): - sale_form.save() - if sale_linea_form.is_valid(): - sale_linea_form.save() - return HttpResponseRedirect("productos") + if sale_form.is_valid() and sale_linea_form.is_valid(): + sale = sale_form.save() + lines = sale_linea_form.save(commit=False) + for line in lines: + line.sale = sale + line.save() + return HttpResponseRedirect("compras") else: sale_form = PurchaseForm() sale_linea_form = LineaFormSet() @@ -33,6 +38,7 @@ def buy(request): } ) + def purchases(request): purchases = Sale.objects.all() context = { @@ -89,6 +95,7 @@ def reconciliate_jar(request): {'summary': summary, 'form': form} ) + def reconciliations(request): return HttpResponse('

Reconciliaciones

') @@ -98,9 +105,11 @@ def _categories_from_csv_string(categories_string, 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='"') From b94c5a007043a1e05650cce07fc8aa26652d2478 Mon Sep 17 00:00:00 2001 From: sinergia Date: Fri, 12 Jul 2024 22:38:07 -0500 Subject: [PATCH 10/16] feat: Se agrega testform --- tienda_ilusion/don_confiao/forms.py | 2 +- .../don_confiao/tests/tests_purchase_form.py | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 tienda_ilusion/don_confiao/tests/tests_purchase_form.py diff --git a/tienda_ilusion/don_confiao/forms.py b/tienda_ilusion/don_confiao/forms.py index 85aeec0..1c739f1 100644 --- a/tienda_ilusion/don_confiao/forms.py +++ b/tienda_ilusion/don_confiao/forms.py @@ -36,7 +36,7 @@ class PurchaseLineForm(forms.ModelForm): LineaFormSet = forms.models.inlineformset_factory( Sale, SaleLine, - extra=2, + extra=1, fields='__all__' ) diff --git a/tienda_ilusion/don_confiao/tests/tests_purchase_form.py b/tienda_ilusion/don_confiao/tests/tests_purchase_form.py new file mode 100644 index 0000000..e50849b --- /dev/null +++ b/tienda_ilusion/don_confiao/tests/tests_purchase_form.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +from django.test import TestCase +from ..forms import PurchaseForm +# from ..models import Sale, SaleLine + +_csrf_token = \ + "bVjBevJRavxRPFOlVgAWiyh9ceuiwPlyEcmbPZprNuCGHjFZRKZrBeunJvKTRgOx" + + +class PurchaseFormTest(TestCase): + + def test_add_purchase(self): + form_data = { + "csrfmiddlewaretoken": _csrf_token, + "customer": "San Judas de Asis", + "date": "2024-07-12", + "phone": "3010101000", + "description": "Esta es una Venta", + "saleline_set-TOTAL_FORMS": "1", + "saleline_set-INITIAL_FORMS": "0", + "saleline_set-MIN_NUM_FORMS": "0", + "saleline_set-MAX_NUM_FORMS": "1000", + "saleline_set-0-product": "Papayita", + "saleline_set-0-quantity": "1", + "saleline_set-0-unit_price": "22030", + "saleline_set-0-description": "Linea de Venta", + "saleline_set-0-sale": "", + "saleline_set-0-id": "", + "form": "" + } + + purchase_form = PurchaseForm(data=form_data) + self.assertTrue(purchase_form.is_valid()) From cb84371f4bf460943f60fc38c4f4d28586db03a8 Mon Sep 17 00:00:00 2001 From: Rodia Date: Fri, 12 Jul 2024 23:40:43 -0500 Subject: [PATCH 11/16] =?UTF-8?q?Feat(ButtonAddLine):=20A=C3=B1adir=20line?= =?UTF-8?q?a=20de=20venta=20en=20formulario=20WIP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../don_confiao/static/js/add_line.js | 18 ++++++++++++++++ .../templates/don_confiao/purchase.html | 21 ++++++++++++------- 2 files changed, 32 insertions(+), 7 deletions(-) create mode 100644 tienda_ilusion/don_confiao/static/js/add_line.js diff --git a/tienda_ilusion/don_confiao/static/js/add_line.js b/tienda_ilusion/don_confiao/static/js/add_line.js new file mode 100644 index 0000000..aed4bec --- /dev/null +++ b/tienda_ilusion/don_confiao/static/js/add_line.js @@ -0,0 +1,18 @@ +document.addEventListener('DOMContentLoaded', function(){ + var button = document.getElementById('add_line'); + var formContainer = document.getElementById('formset-container'); + var totalForms = document.getElementById('id_form-TOTAL_FORMS'); + button.addEventListener('click', function(){ + // Clonar un formulario vacío + var newForm = formContainer.querySelector('.form-container').cloneNode(true); + // Obtener el número actual de formularios + var formCount = parseInt(totalForms.value); + // Actualizar los atributos de los nuevos campos del formulario + var regex = new RegExp('__prefix__', 'g'); + newForm.innerHTML = newForm.innerHTML.replace(regex, formCount); + // Añadir el nuevo formulario al contenedor + formContainer.appendChild(newForm); + // Incrementar el total de formularios + totalForms.value = formCount + 1; + }); +}); diff --git a/tienda_ilusion/don_confiao/templates/don_confiao/purchase.html b/tienda_ilusion/don_confiao/templates/don_confiao/purchase.html index 0d2c2f4..7f6c8d9 100644 --- a/tienda_ilusion/don_confiao/templates/don_confiao/purchase.html +++ b/tienda_ilusion/don_confiao/templates/don_confiao/purchase.html @@ -1,12 +1,19 @@ +{% load static %}
- {% csrf_token %} - {{ sale_form}} + {% csrf_token %} + {{ sale_form}} {{ linea_formset.management_form }} - {% for form in linea_formset %} - - {{ form.as_table }} -
+
+ {% for form in linea_formset %} +
+ + {{ form.as_table }} +
+
{% endfor %} -
+
+ +
+
From b70a0b73c32dd06469ae8a9f8a4658d11f4e7d4e Mon Sep 17 00:00:00 2001 From: Rodia Date: Sat, 13 Jul 2024 11:01:11 -0500 Subject: [PATCH 12/16] Feat(AddSaleLineButton): Sale Line Button --- tienda_ilusion/don_confiao/static/js/add_line.js | 2 +- tienda_ilusion/don_confiao/templates/don_confiao/purchase.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tienda_ilusion/don_confiao/static/js/add_line.js b/tienda_ilusion/don_confiao/static/js/add_line.js index aed4bec..bfb38ed 100644 --- a/tienda_ilusion/don_confiao/static/js/add_line.js +++ b/tienda_ilusion/don_confiao/static/js/add_line.js @@ -1,7 +1,7 @@ document.addEventListener('DOMContentLoaded', function(){ var button = document.getElementById('add_line'); var formContainer = document.getElementById('formset-container'); - var totalForms = document.getElementById('id_form-TOTAL_FORMS'); + var totalForms = document.getElementById('id_saleline_set-TOTAL_FORMS'); button.addEventListener('click', function(){ // Clonar un formulario vacío var newForm = formContainer.querySelector('.form-container').cloneNode(true); diff --git a/tienda_ilusion/don_confiao/templates/don_confiao/purchase.html b/tienda_ilusion/don_confiao/templates/don_confiao/purchase.html index 7f6c8d9..d174357 100644 --- a/tienda_ilusion/don_confiao/templates/don_confiao/purchase.html +++ b/tienda_ilusion/don_confiao/templates/don_confiao/purchase.html @@ -13,7 +13,7 @@
{% endfor %}
- +
From 9edbd1caef4547af7cdc3af0ebeacc9908675429 Mon Sep 17 00:00:00 2001 From: Rodia Date: Sat, 13 Jul 2024 11:25:12 -0500 Subject: [PATCH 13/16] Feat(ReplaceNameIdSaleLine) --- .../don_confiao/static/js/add_line.js | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/tienda_ilusion/don_confiao/static/js/add_line.js b/tienda_ilusion/don_confiao/static/js/add_line.js index bfb38ed..4f6bc25 100644 --- a/tienda_ilusion/don_confiao/static/js/add_line.js +++ b/tienda_ilusion/don_confiao/static/js/add_line.js @@ -3,16 +3,27 @@ document.addEventListener('DOMContentLoaded', function(){ var formContainer = document.getElementById('formset-container'); var totalForms = document.getElementById('id_saleline_set-TOTAL_FORMS'); button.addEventListener('click', function(){ - // Clonar un formulario vacío var newForm = formContainer.querySelector('.form-container').cloneNode(true); - // Obtener el número actual de formularios var formCount = parseInt(totalForms.value); - // Actualizar los atributos de los nuevos campos del formulario var regex = new RegExp('__prefix__', 'g'); newForm.innerHTML = newForm.innerHTML.replace(regex, formCount); - // Añadir el nuevo formulario al contenedor + + var fields = newForm.querySelectorAll('[id^="id_saleline_set-"], [name^="saleline_set-"]'); + fields.forEach(function(field) { + var oldId = field.id; + var oldName = field.name; + + if (oldId) { + var newId = oldId.replace(/-\d+-/, '-' + formCount + '-'); + field.id = newId; + } + if (oldName) { + var newName = oldName.replace(/-\d+-/, '-' + formCount + '-'); + field.name = newName; + } + }); + formContainer.appendChild(newForm); - // Incrementar el total de formularios totalForms.value = formCount + 1; }); }); From 675b4f059f0b0130279af81c7f2ce3fad10f2969 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 27 Jul 2024 13:30:14 -0500 Subject: [PATCH 14/16] feat: implementing form to reconciliation jar. --- .../don_confiao/templates/don_confiao/reconciliate_jar.html | 3 --- tienda_ilusion/don_confiao/test_billing.py | 1 - tienda_ilusion/don_confiao/test_reconciliation_jar_client.py | 1 + tienda_ilusion/don_confiao/views.py | 2 -- 4 files changed, 1 insertion(+), 6 deletions(-) diff --git a/tienda_ilusion/don_confiao/templates/don_confiao/reconciliate_jar.html b/tienda_ilusion/don_confiao/templates/don_confiao/reconciliate_jar.html index 16fa5dc..6771044 100644 --- a/tienda_ilusion/don_confiao/templates/don_confiao/reconciliate_jar.html +++ b/tienda_ilusion/don_confiao/templates/don_confiao/reconciliate_jar.html @@ -28,6 +28,3 @@

No hay pagos registrados.

{% endif %} - - - diff --git a/tienda_ilusion/don_confiao/test_billing.py b/tienda_ilusion/don_confiao/test_billing.py index 9b6372b..89a5a43 100644 --- a/tienda_ilusion/don_confiao/test_billing.py +++ b/tienda_ilusion/don_confiao/test_billing.py @@ -51,7 +51,6 @@ class TestBilling(TestCase): reconciliation_jar.save() reconciliation_jar.add_payments(jar_summary.payments) - with self.assertRaises(ValidationError): reconciliation_jar.clean() diff --git a/tienda_ilusion/don_confiao/test_reconciliation_jar_client.py b/tienda_ilusion/don_confiao/test_reconciliation_jar_client.py index fa008d8..ad58d0e 100644 --- a/tienda_ilusion/don_confiao/test_reconciliation_jar_client.py +++ b/tienda_ilusion/don_confiao/test_reconciliation_jar_client.py @@ -31,6 +31,7 @@ class TestReconciliationJarClient(TestCase): ) self.assertRedirects(response, '/don_confiao/cuadres') + def _generate_two_cash_payments(self): cash_payment1 = Payment() cash_payment1.date_time = '2024-07-07 12:00:00' diff --git a/tienda_ilusion/don_confiao/views.py b/tienda_ilusion/don_confiao/views.py index 25a67da..6e67f01 100644 --- a/tienda_ilusion/don_confiao/views.py +++ b/tienda_ilusion/don_confiao/views.py @@ -95,11 +95,9 @@ def reconciliate_jar(request): {'summary': summary, 'form': form} ) - def reconciliations(request): return HttpResponse('

Reconciliaciones

') - def _categories_from_csv_string(categories_string, separator="&"): categories = categories_string.split(separator) clean_categories = [c.strip() for c in categories] From 09f734f5cbea404ddd1084bd9f4fc43519f78cf4 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 27 Jul 2024 13:32:31 -0500 Subject: [PATCH 15/16] feat: create a correct reconciliation jar. --- tienda_ilusion/don_confiao/test_billing.py | 3 ++- tienda_ilusion/don_confiao/views.py | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tienda_ilusion/don_confiao/test_billing.py b/tienda_ilusion/don_confiao/test_billing.py index 89a5a43..79254e9 100644 --- a/tienda_ilusion/don_confiao/test_billing.py +++ b/tienda_ilusion/don_confiao/test_billing.py @@ -52,7 +52,7 @@ class TestBilling(TestCase): reconciliation_jar.add_payments(jar_summary.payments) with self.assertRaises(ValidationError): - reconciliation_jar.clean() + reconciliation_jar.manual_clean() def test_validate_reconciliation_jar_with_cash_float(self): cash_payment1, cash_payment2 = self._create_two_cash_payments() @@ -69,6 +69,7 @@ class TestBilling(TestCase): reconciliation_jar.add_payments(jar_summary.payments) reconciliation_jar.clean() reconciliation_jar.save() + reconciliation_jar.manual_clean() self.assertTrue(reconciliation_jar.is_valid) def _create_two_cash_payments(self): diff --git a/tienda_ilusion/don_confiao/views.py b/tienda_ilusion/don_confiao/views.py index 6e67f01..2041831 100644 --- a/tienda_ilusion/don_confiao/views.py +++ b/tienda_ilusion/don_confiao/views.py @@ -1,7 +1,7 @@ from django.shortcuts import render from django.http import HttpResponse, HttpResponseRedirect, JsonResponse -#from django.template import loader +from django.template import loader from django.core.exceptions import ValidationError from .models import Sale, Product, ProductCategory, Payment @@ -95,9 +95,11 @@ def reconciliate_jar(request): {'summary': summary, 'form': form} ) + def reconciliations(request): return HttpResponse('

Reconciliaciones

') + def _categories_from_csv_string(categories_string, separator="&"): categories = categories_string.split(separator) clean_categories = [c.strip() for c in categories] From 72bf284dfd9c6c036ef1363c7c412f8bbbde77c7 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 27 Jul 2024 13:41:01 -0500 Subject: [PATCH 16/16] fix merge error. --- tienda_ilusion/don_confiao/test_billing.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tienda_ilusion/don_confiao/test_billing.py b/tienda_ilusion/don_confiao/test_billing.py index 79254e9..89a5a43 100644 --- a/tienda_ilusion/don_confiao/test_billing.py +++ b/tienda_ilusion/don_confiao/test_billing.py @@ -52,7 +52,7 @@ class TestBilling(TestCase): reconciliation_jar.add_payments(jar_summary.payments) with self.assertRaises(ValidationError): - reconciliation_jar.manual_clean() + reconciliation_jar.clean() def test_validate_reconciliation_jar_with_cash_float(self): cash_payment1, cash_payment2 = self._create_two_cash_payments() @@ -69,7 +69,6 @@ class TestBilling(TestCase): reconciliation_jar.add_payments(jar_summary.payments) reconciliation_jar.clean() reconciliation_jar.save() - reconciliation_jar.manual_clean() self.assertTrue(reconciliation_jar.is_valid) def _create_two_cash_payments(self):