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.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'})
# }

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

View File

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

View File

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

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("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"),
]

View File

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