feat: implementing form to reconciliation jar.

This commit is contained in:
Mono Mono 2024-07-13 17:13:17 -05:00
parent ee38c29ce3
commit a8f8820a55
12 changed files with 266 additions and 17 deletions

View File

@ -1,7 +1,7 @@
from django import forms 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): class ImportProductsForm(forms.Form):
@ -37,3 +37,17 @@ LineaFormSet = forms.models.inlineformset_factory(
extra=2, extra=2,
fields='__all__' 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'})
# }

View File

@ -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,
),
]

View File

@ -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),
),
]

View File

@ -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',
),
]

View File

@ -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',
),
]

View File

@ -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',
),
]

View File

@ -1,5 +1,7 @@
from django.db import models from django.db import models
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ValidationError
class Sale(models.Model): class Sale(models.Model):
@ -23,15 +25,18 @@ class SaleLine(models.Model):
def __str__(self): def __str__(self):
return f"{self.sale} - {self.product}" return f"{self.sale} - {self.product}"
class MeasuringUnits(models.TextChoices): class MeasuringUnits(models.TextChoices):
UNIT = 'UNIT', _('Unit') UNIT = 'UNIT', _('Unit')
class ProductCategory(models.Model): class ProductCategory(models.Model):
name = models.CharField(max_length=100, unique=True) name = models.CharField(max_length=100, unique=True)
def __str__(self): def __str__(self):
return self.name return self.name
class Product(models.Model): class Product(models.Model):
name = models.CharField(max_length=100, unique=True) name = models.CharField(max_length=100, unique=True)
price = models.DecimalField(max_digits=9, decimal_places=2) price = models.DecimalField(max_digits=9, decimal_places=2)
@ -45,11 +50,13 @@ class Product(models.Model):
def __str__(self): def __str__(self):
return self.name return self.name
class PyamentMethods(models.TextChoices): class PyamentMethods(models.TextChoices):
CASH = 'CASH', _('Cash') CASH = 'CASH', _('Cash')
CONFIAR = 'CONFIAR', _('Confiar') CONFIAR = 'CONFIAR', _('Confiar')
BANCOLOMBIA = 'BANCOLOMBIA', _('Bancolombia') BANCOLOMBIA = 'BANCOLOMBIA', _('Bancolombia')
class ReconciliationJarSummary(): class ReconciliationJarSummary():
def __init__(self, payments): def __init__(self, payments):
self._validate_payments(payments) self._validate_payments(payments)
@ -68,9 +75,24 @@ class ReconciliationJarSummary():
class ReconciliationJar(models.Model): class ReconciliationJar(models.Model):
is_valid = models.BooleanField(default=False)
date_time = models.DateTimeField() date_time = models.DateTimeField()
description = models.CharField(max_length=255, null=True, blank=True) 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): class Payment(models.Model):
date_time = models.DateTimeField() date_time = models.DateTimeField()

View File

@ -0,0 +1,2 @@
<!doctype html>
{{ summary.total }}

View File

@ -1,22 +1,21 @@
from django.test import Client, TestCase from django.test import Client, TestCase
from .models import Payment from django.core.exceptions import ValidationError
from .models import Payment, ReconciliationJar
class TestBilling(TestCase): class TestBilling(TestCase):
def test_reconciliation_jar_summary(self): def test_reconciliation_jar_summary(self):
cash_payment1 = Payment() cash_payment1, cash_payment2 = self._create_two_cash_payments()
cash_payment1.date_time = '2024-07-07 12:00:00' jar_summary = Payment.get_reconciliation_jar_summary()
cash_payment1.type_payment = 'CASH' self.assertEqual(164000, jar_summary.total)
cash_payment1.amount = 132000 self.assertSetEqual(
cash_payment1.description = 'Saldo en compra' {cash_payment1, cash_payment2},
cash_payment1.save() set(jar_summary.payments)
)
cash_payment2 = Payment() def test_reconciliation_jar_summary_use_only_cash(self):
cash_payment2.date_time = '2024-07-07 13:05:00' cash_payment1, cash_payment2 = self._create_two_cash_payments()
cash_payment2.type_payment = 'CASH'
cash_payment2.amount = 32000
cash_payment2.save()
confiar_payment = Payment() confiar_payment = Payment()
confiar_payment.date_time = '2024-07-07 16:00:00' confiar_payment.date_time = '2024-07-07 16:00:00'
@ -36,3 +35,57 @@ class TestBilling(TestCase):
{cash_payment1, cash_payment2}, {cash_payment1, cash_payment2},
set(jar_summary.payments) 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]

View 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()

View File

@ -8,5 +8,6 @@ urlpatterns = [
path("comprar", views.buy, name="buy"), path("comprar", views.buy, name="buy"),
path("compras", views.purchases, name="purchases"), path("compras", views.purchases, name="purchases"),
path("productos", views.products, name="products"), 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"),
] ]

View File

@ -2,8 +2,8 @@ from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
from django.template import loader from django.template import loader
from .models import Sale, Product, ProductCategory from .models import Sale, Product, ProductCategory, Payment
from .forms import ImportProductsForm, PurchaseForm, LineaFormSet from .forms import ImportProductsForm, PurchaseForm, LineaFormSet, ReconciliationJarForm
import csv import csv
import io import io
@ -69,6 +69,21 @@ def import_products(request):
{'form': form} {'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="&"): def _categories_from_csv_string(categories_string, separator="&"):
categories = categories_string.split(separator) categories = categories_string.split(separator)
clean_categories = [c.strip() for c in categories] clean_categories = [c.strip() for c in categories]