feat: implementing form to reconciliation jar.
This commit is contained in:
		@@ -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'})
 | 
			
		||||
        # }
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
@@ -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),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
@@ -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',
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
@@ -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',
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
@@ -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',
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
@@ -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()
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,2 @@
 | 
			
		||||
<!doctype html>
 | 
			
		||||
{{ summary.total }}
 | 
			
		||||
@@ -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]
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										34
									
								
								tienda_ilusion/don_confiao/test_reconciliation_jar_client.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								tienda_ilusion/don_confiao/test_reconciliation_jar_client.py
									
									
									
									
									
										Normal file
									
								
							@@ -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()
 | 
			
		||||
@@ -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"),
 | 
			
		||||
]
 | 
			
		||||
 
 | 
			
		||||
@@ -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]
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user