From 1a54426af6aa79c25c7732b64065261c1ef1cfd4 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 17 Aug 2024 12:49:43 -0500 Subject: [PATCH 1/9] style(models): minor fix. --- tienda_ilusion/don_confiao/models.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tienda_ilusion/don_confiao/models.py b/tienda_ilusion/don_confiao/models.py index 62d6fd6..5e48b3d 100644 --- a/tienda_ilusion/don_confiao/models.py +++ b/tienda_ilusion/don_confiao/models.py @@ -12,7 +12,6 @@ class Customer(models.Model): def __str__(self): return self.name - class MeasuringUnits(models.TextChoices): UNIT = 'UNIT', _('Unit') From 204bdbcb33b29e2f4b8b49fc667b7346d1bc8b29 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 17 Aug 2024 12:51:38 -0500 Subject: [PATCH 2/9] limit to CASH methods type in purchases. --- tienda_ilusion/don_confiao/forms.py | 3 +- .../tests/test_purchase_with_payment.py | 68 +++++++++++-------- 2 files changed, 40 insertions(+), 31 deletions(-) diff --git a/tienda_ilusion/don_confiao/forms.py b/tienda_ilusion/don_confiao/forms.py index 0e877ea..0142b04 100644 --- a/tienda_ilusion/don_confiao/forms.py +++ b/tienda_ilusion/don_confiao/forms.py @@ -50,8 +50,7 @@ class PurchaseSummaryForm(forms.Form): widget=readonly_number_widget ) payment_method = forms.ChoiceField( - choices=PaymentMethods.choices, - widget=forms.Select(attrs={'disabled': 'disabled'}) + choices=[(PaymentMethods.CASH, PaymentMethods.CASH)], ) diff --git a/tienda_ilusion/don_confiao/tests/test_purchase_with_payment.py b/tienda_ilusion/don_confiao/tests/test_purchase_with_payment.py index a27904c..bee9de2 100644 --- a/tienda_ilusion/don_confiao/tests/test_purchase_with_payment.py +++ b/tienda_ilusion/don_confiao/tests/test_purchase_with_payment.py @@ -1,37 +1,47 @@ from django.test import Client, TestCase -from ..models import Payment, Sale +from ..models import Payment, Sale, Product, Customer class TestPurchaseWithPayment(TestCase): def setUp(self): self.client = Client() + self.product = Product() + self.product.name = "Arroz" + self.product.price = 5000 + self.product.save() + customer = Customer() + customer.name = "Noelba Lopez" + customer.save() + self.customer = customer - # def test_generate_payment_when_it_has_payment(self): - # quantity = 2 - # unit_price = 2500 - # total = 5000 - # response = self.client.post( - # '/don_confiao/comprar', - # { - # "customer": "Noelba Lopez", - # "date": "2024-07-27", - # "phone": "3010101000", - # "description": "Venta de contado", - # "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": str(quantity), - # "saleline_set-0-unit_price": str(unit_price), - # "saleline_set-0-description": "Linea de Venta", - # "saleline_set-0-sale": "", - # "saleline_set-0-id": "", - # } - # ) - # purchases = Sale.objects.all() - # self.assertEqual(1, len(purchases)) - # payments = Payment.objects.all() - # self.assertEqual(1, len(payments)) - # self.assertEqual(total, payments[0].ammount) + def test_generate_payment_when_it_has_payment(self): + quantity = 2 + unit_price = 2500 + total = 5000 + response = self.client.post( + '/don_confiao/comprar', + { + "customer": str(self.customer.id), + "date": "2024-07-27", + "phone": "3010101000", + "description": "Venta de contado", + "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": str(self.product.id), + "saleline_set-0-quantity": str(quantity), + "saleline_set-0-unit_price": str(unit_price), + "saleline_set-0-description": "Linea de Venta", + "saleline_set-0-sale": "", + "saleline_set-0-id": "", + "quantity_lines": "1", + "quantity_products": str(quantity), + "ammount": str(quantity * unit_price), + "payment_method": "CASH", + } + ) + purchases = Sale.objects.all() + self.assertEqual(1, len(purchases)) + payments = Payment.objects.all() From 4c0c4737ac376a36bb3e79b46604792bb70e806e Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 17 Aug 2024 14:29:20 -0500 Subject: [PATCH 3/9] migration(Customer): default None. --- .../migrations/0029_alter_customer_name.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tienda_ilusion/don_confiao/migrations/0029_alter_customer_name.py diff --git a/tienda_ilusion/don_confiao/migrations/0029_alter_customer_name.py b/tienda_ilusion/don_confiao/migrations/0029_alter_customer_name.py new file mode 100644 index 0000000..dcbceb0 --- /dev/null +++ b/tienda_ilusion/don_confiao/migrations/0029_alter_customer_name.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.6 on 2024-08-17 19:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('don_confiao', '0028_alter_customer_address'), + ] + + operations = [ + migrations.AlterField( + model_name='customer', + name='name', + field=models.CharField(default=None, max_length=100), + ), + ] From 2a9a73c4305ee1ae5fea2d80198f09eeb0cfd568 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 17 Aug 2024 14:34:10 -0500 Subject: [PATCH 4/9] refactor(Forms): rename varible. --- tienda_ilusion/don_confiao/forms.py | 2 +- tienda_ilusion/don_confiao/views.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tienda_ilusion/don_confiao/forms.py b/tienda_ilusion/don_confiao/forms.py index 0142b04..241dac3 100644 --- a/tienda_ilusion/don_confiao/forms.py +++ b/tienda_ilusion/don_confiao/forms.py @@ -54,7 +54,7 @@ class PurchaseSummaryForm(forms.Form): ) -LineaFormSet = inlineformset_factory( +SaleLineFormSet = inlineformset_factory( Sale, SaleLine, extra=1, diff --git a/tienda_ilusion/don_confiao/views.py b/tienda_ilusion/don_confiao/views.py index 563a6a6..7152f8e 100644 --- a/tienda_ilusion/don_confiao/views.py +++ b/tienda_ilusion/don_confiao/views.py @@ -5,7 +5,7 @@ from django.core.exceptions import ValidationError from django.views.generic import ListView from .models import Sale, Product, ProductCategory, Payment -from .forms import ImportProductsForm, PurchaseForm, LineaFormSet, ReconciliationJarForm, PurchaseSummaryForm +from .forms import ImportProductsForm, PurchaseForm, SaleLineFormSet, ReconciliationJarForm, PurchaseSummaryForm import csv import io @@ -18,7 +18,7 @@ def index(request): def buy(request): if request.method == "POST": sale_form = PurchaseForm(request.POST) - sale_linea_form = LineaFormSet(request.POST) + sale_linea_form = SaleLineFormSet(request.POST) sale_summary_form = PurchaseSummaryForm(request.POST) if sale_form.is_valid() and sale_linea_form.is_valid(): sale = sale_form.save() @@ -29,7 +29,7 @@ def buy(request): return HttpResponseRedirect("compras") else: sale_form = PurchaseForm() - sale_linea_form = LineaFormSet() + sale_linea_form = SaleLineFormSet() sale_summary_form = PurchaseSummaryForm() return render( request, From a401029082c61bbab205a8f591875e21b0808ab7 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 17 Aug 2024 14:50:49 -0500 Subject: [PATCH 5/9] fix view(Buy): rewrite save process. --- tienda_ilusion/don_confiao/views.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tienda_ilusion/don_confiao/views.py b/tienda_ilusion/don_confiao/views.py index 7152f8e..f89f383 100644 --- a/tienda_ilusion/don_confiao/views.py +++ b/tienda_ilusion/don_confiao/views.py @@ -20,12 +20,10 @@ def buy(request): sale_form = PurchaseForm(request.POST) sale_linea_form = SaleLineFormSet(request.POST) sale_summary_form = PurchaseSummaryForm(request.POST) - if sale_form.is_valid() and sale_linea_form.is_valid(): + if sale_form.is_valid() and sale_linea_form.is_valid() and sale_summary_form.is_valid(): sale = sale_form.save() - lines = sale_linea_form.save(commit=False) - for line in lines: - line.sale = sale - line.save() + sale_linea_form.instance = sale + sale_linea_form.save() return HttpResponseRedirect("compras") else: sale_form = PurchaseForm() From 7eb8f40d7aa711b428596bc1f6be5f7b0b09932f Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 17 Aug 2024 14:57:46 -0500 Subject: [PATCH 6/9] style(views): minor fix. --- tienda_ilusion/don_confiao/views.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/tienda_ilusion/don_confiao/views.py b/tienda_ilusion/don_confiao/views.py index f89f383..0b5d969 100644 --- a/tienda_ilusion/don_confiao/views.py +++ b/tienda_ilusion/don_confiao/views.py @@ -18,23 +18,28 @@ def index(request): def buy(request): if request.method == "POST": sale_form = PurchaseForm(request.POST) - sale_linea_form = SaleLineFormSet(request.POST) + line_formset = SaleLineFormSet(request.POST) sale_summary_form = PurchaseSummaryForm(request.POST) - if sale_form.is_valid() and sale_linea_form.is_valid() and sale_summary_form.is_valid(): + forms_are_valid = all([ + sale_form.is_valid(), + line_formset.is_valid(), + sale_summary_form.is_valid() + ]) + if forms_are_valid: sale = sale_form.save() - sale_linea_form.instance = sale - sale_linea_form.save() + line_formset.instance = sale + line_formset.save() return HttpResponseRedirect("compras") else: sale_form = PurchaseForm() - sale_linea_form = SaleLineFormSet() + line_formset = SaleLineFormSet() sale_summary_form = PurchaseSummaryForm() return render( request, 'don_confiao/purchase.html', { 'sale_form': sale_form, - 'linea_formset': sale_linea_form, + 'linea_formset': line_formset, 'summary_form': sale_summary_form, } ) From 1f37e57e00092f68a0eaf9d2cd99166ebaabcf3a Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 17 Aug 2024 15:07:43 -0500 Subject: [PATCH 7/9] feat(Buy): add transaction on buy process. --- tienda_ilusion/don_confiao/views.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tienda_ilusion/don_confiao/views.py b/tienda_ilusion/don_confiao/views.py index 0b5d969..7c837bc 100644 --- a/tienda_ilusion/don_confiao/views.py +++ b/tienda_ilusion/don_confiao/views.py @@ -1,8 +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 django.views.generic import ListView +from django.db import transaction from .models import Sale, Product, ProductCategory, Payment from .forms import ImportProductsForm, PurchaseForm, SaleLineFormSet, ReconciliationJarForm, PurchaseSummaryForm @@ -26,9 +25,10 @@ def buy(request): sale_summary_form.is_valid() ]) if forms_are_valid: - sale = sale_form.save() - line_formset.instance = sale - line_formset.save() + with transaction.atomic(): + sale = sale_form.save() + line_formset.instance = sale + line_formset.save() return HttpResponseRedirect("compras") else: sale_form = PurchaseForm() From 0c95c216662fb5871e8392a9d85e7cd3b077becd Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 17 Aug 2024 16:39:29 -0500 Subject: [PATCH 8/9] feat(Payments): Generate cash payment with purchase. --- tienda_ilusion/don_confiao/models.py | 23 ++++++++++++++++++- .../tests/test_purchase_with_payment.py | 6 ++++- tienda_ilusion/don_confiao/views.py | 10 ++++++-- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/tienda_ilusion/don_confiao/models.py b/tienda_ilusion/don_confiao/models.py index 5e48b3d..71772d1 100644 --- a/tienda_ilusion/don_confiao/models.py +++ b/tienda_ilusion/don_confiao/models.py @@ -3,6 +3,7 @@ from django.utils.translation import gettext_lazy as _ from django.core.exceptions import ValidationError from decimal import Decimal +from datetime import datetime class Customer(models.Model): @@ -118,7 +119,7 @@ class ReconciliationJar(models.Model): self.payment_set.add(payment) self.is_valid = True - + class Payment(models.Model): date_time = models.DateTimeField() type_payment = models.CharField( @@ -144,3 +145,23 @@ class Payment(models.Model): reconciliation_jar=None ) ) + + @classmethod + def total_payment_from_sale(cls, payment_method, sale): + payment = cls() + payment.date_time = datetime.today() + payment.type_payment = payment_method + payment.amount = sale.get_total() + payment.clean() + payment.save() + + payment_sale = PaymentSale() + payment_sale.payment = payment + payment_sale.sale = sale + payment_sale.clean() + payment_sale.save() + + +class PaymentSale(models.Model): + payment = models.ForeignKey(Payment, on_delete=models.CASCADE) + sale = models.ForeignKey(Sale, on_delete=models.CASCADE) diff --git a/tienda_ilusion/don_confiao/tests/test_purchase_with_payment.py b/tienda_ilusion/don_confiao/tests/test_purchase_with_payment.py index bee9de2..962aaa2 100644 --- a/tienda_ilusion/don_confiao/tests/test_purchase_with_payment.py +++ b/tienda_ilusion/don_confiao/tests/test_purchase_with_payment.py @@ -19,7 +19,7 @@ class TestPurchaseWithPayment(TestCase): quantity = 2 unit_price = 2500 total = 5000 - response = self.client.post( + self.client.post( '/don_confiao/comprar', { "customer": str(self.customer.id), @@ -42,6 +42,10 @@ class TestPurchaseWithPayment(TestCase): "payment_method": "CASH", } ) + purchases = Sale.objects.all() self.assertEqual(1, len(purchases)) payments = Payment.objects.all() + self.assertEqual(1, len(payments)) + self.assertEqual(total, payments[0].amount) + self.assertEqual('CASH', payments[0].type_payment) diff --git a/tienda_ilusion/don_confiao/views.py b/tienda_ilusion/don_confiao/views.py index 7c837bc..63169c4 100644 --- a/tienda_ilusion/don_confiao/views.py +++ b/tienda_ilusion/don_confiao/views.py @@ -3,7 +3,7 @@ from django.http import HttpResponse, HttpResponseRedirect, JsonResponse from django.views.generic import ListView from django.db import transaction -from .models import Sale, Product, ProductCategory, Payment +from .models import Sale, Product, ProductCategory, Payment, PaymentMethods from .forms import ImportProductsForm, PurchaseForm, SaleLineFormSet, ReconciliationJarForm, PurchaseSummaryForm import csv @@ -13,7 +13,6 @@ import io def index(request): return render(request, 'don_confiao/index.html') - def buy(request): if request.method == "POST": sale_form = PurchaseForm(request.POST) @@ -24,11 +23,18 @@ def buy(request): line_formset.is_valid(), sale_summary_form.is_valid() ]) + payment_method = request.POST.get('payment_method') + valid_payment_methods = [PaymentMethods.CASH] + valid_payment_method = payment_method in valid_payment_methods if forms_are_valid: with transaction.atomic(): sale = sale_form.save() line_formset.instance = sale line_formset.save() + Payment.total_payment_from_sale( + payment_method, + sale + ) return HttpResponseRedirect("compras") else: sale_form = PurchaseForm() From f847a0e16a960a0c4c1f79353ab7175152262240 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 17 Aug 2024 16:40:13 -0500 Subject: [PATCH 9/9] migation. --- .../migrations/0030_paymentsale.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tienda_ilusion/don_confiao/migrations/0030_paymentsale.py diff --git a/tienda_ilusion/don_confiao/migrations/0030_paymentsale.py b/tienda_ilusion/don_confiao/migrations/0030_paymentsale.py new file mode 100644 index 0000000..77d4522 --- /dev/null +++ b/tienda_ilusion/don_confiao/migrations/0030_paymentsale.py @@ -0,0 +1,22 @@ +# Generated by Django 5.0.6 on 2024-08-17 21:00 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('don_confiao', '0029_alter_customer_name'), + ] + + operations = [ + migrations.CreateModel( + name='PaymentSale', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('payment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='don_confiao.payment')), + ('sale', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='don_confiao.sale')), + ], + ), + ]