#69 feat(Reconciliation):get purchases for reconciliation endpoint.
This commit is contained in:
parent
b7984f7556
commit
a6b4c1c5b6
@ -0,0 +1,29 @@
|
|||||||
|
# Generated by Django 5.0.6 on 2024-11-18 03:16
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('don_confiao', '0033_sale_payment_method'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='sale',
|
||||||
|
name='reconciliation',
|
||||||
|
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.RESTRICT, related_name='Sales', to='don_confiao.reconciliationjar'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='payment',
|
||||||
|
name='type_payment',
|
||||||
|
field=models.CharField(choices=[('CASH', 'Efectivo'), ('CONFIAR', 'Confiar'), ('BANCOLOMBIA', 'Bancolombia')], default='CASH', max_length=30),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='sale',
|
||||||
|
name='payment_method',
|
||||||
|
field=models.CharField(choices=[('CASH', 'Efectivo'), ('CONFIAR', 'Confiar'), ('BANCOLOMBIA', 'Bancolombia')], default='CASH', max_length=30),
|
||||||
|
),
|
||||||
|
]
|
@ -62,6 +62,38 @@ class Product(models.Model):
|
|||||||
return products_list
|
return products_list
|
||||||
|
|
||||||
|
|
||||||
|
class ReconciliationJar(models.Model):
|
||||||
|
is_valid = models.BooleanField(default=False)
|
||||||
|
date_time = models.DateTimeField()
|
||||||
|
description = models.CharField(max_length=255, null=True, blank=True)
|
||||||
|
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)
|
||||||
|
|
||||||
|
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,
|
||||||
|
]))
|
||||||
|
|
||||||
|
equal_ammounts = reconciliation_ammount.compare(payments_amount) == Decimal('0')
|
||||||
|
if not equal_ammounts:
|
||||||
|
raise ValidationError(
|
||||||
|
{"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 Sale(models.Model):
|
class Sale(models.Model):
|
||||||
customer = models.ForeignKey(Customer, on_delete=models.PROTECT)
|
customer = models.ForeignKey(Customer, on_delete=models.PROTECT)
|
||||||
date = models.DateField("Date")
|
date = models.DateField("Date")
|
||||||
@ -74,6 +106,12 @@ class Sale(models.Model):
|
|||||||
blank=False,
|
blank=False,
|
||||||
null=False
|
null=False
|
||||||
)
|
)
|
||||||
|
reconciliation = models.ForeignKey(
|
||||||
|
ReconciliationJar,
|
||||||
|
on_delete=models.RESTRICT,
|
||||||
|
related_name='Sales',
|
||||||
|
null=True
|
||||||
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.date} {self.customer}"
|
return f"{self.date} {self.customer}"
|
||||||
@ -122,38 +160,6 @@ class ReconciliationJarSummary():
|
|||||||
return self._payments
|
return self._payments
|
||||||
|
|
||||||
|
|
||||||
class ReconciliationJar(models.Model):
|
|
||||||
is_valid = models.BooleanField(default=False)
|
|
||||||
date_time = models.DateTimeField()
|
|
||||||
description = models.CharField(max_length=255, null=True, blank=True)
|
|
||||||
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)
|
|
||||||
|
|
||||||
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,
|
|
||||||
]))
|
|
||||||
|
|
||||||
equal_ammounts = reconciliation_ammount.compare(payments_amount) == Decimal('0')
|
|
||||||
if not equal_ammounts:
|
|
||||||
raise ValidationError(
|
|
||||||
{"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):
|
class Payment(models.Model):
|
||||||
date_time = models.DateTimeField()
|
date_time = models.DateTimeField()
|
||||||
type_payment = models.CharField(
|
type_payment = models.CharField(
|
||||||
|
111
tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py
Normal file
111
tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
from django.test import TestCase, Client
|
||||||
|
from ..models import Sale, Product, SaleLine, Customer, ReconciliationJar
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
class TestJarReconcliation(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
customer = Customer()
|
||||||
|
customer.name = 'Alejo Mono'
|
||||||
|
customer.save()
|
||||||
|
|
||||||
|
self.client = Client()
|
||||||
|
|
||||||
|
purchase = Sale()
|
||||||
|
purchase.customer = customer
|
||||||
|
purchase.date = "2024-07-30"
|
||||||
|
purchase.payment_method = 'CASH'
|
||||||
|
purchase.clean()
|
||||||
|
purchase.save()
|
||||||
|
|
||||||
|
product = Product()
|
||||||
|
product.name = "cafe"
|
||||||
|
product.price = "72500"
|
||||||
|
product.save()
|
||||||
|
|
||||||
|
line = SaleLine()
|
||||||
|
line.sale = purchase
|
||||||
|
line.product = product
|
||||||
|
line.quantity = "11"
|
||||||
|
line.unit_price = "72500"
|
||||||
|
line.save()
|
||||||
|
self.purchase = purchase
|
||||||
|
|
||||||
|
purchase2 = Sale()
|
||||||
|
purchase2.customer = customer
|
||||||
|
purchase2.date = "2024-07-30"
|
||||||
|
purchase.payment_method = 'CASH'
|
||||||
|
purchase2.clean()
|
||||||
|
purchase2.save()
|
||||||
|
|
||||||
|
line2 = SaleLine()
|
||||||
|
line2.sale = purchase2
|
||||||
|
line2.product = product
|
||||||
|
line2.quantity = "27"
|
||||||
|
line2.unit_price = "72500"
|
||||||
|
line2.save()
|
||||||
|
self.purchase2 = purchase2
|
||||||
|
|
||||||
|
purchase3 = Sale()
|
||||||
|
purchase3.customer = customer
|
||||||
|
purchase3.date = "2024-07-30"
|
||||||
|
purchase3.payment_method = 'CASH'
|
||||||
|
purchase3.clean()
|
||||||
|
purchase3.save()
|
||||||
|
|
||||||
|
line3 = SaleLine()
|
||||||
|
line3.sale = purchase3
|
||||||
|
line3.product = product
|
||||||
|
line3.quantity = "37"
|
||||||
|
line3.unit_price = "72500"
|
||||||
|
line3.save()
|
||||||
|
self.purchase3 = purchase3
|
||||||
|
|
||||||
|
purchase4 = Sale()
|
||||||
|
purchase4.customer = customer
|
||||||
|
purchase4.date = "2024-07-30"
|
||||||
|
purchase4.payment_method = 'CONFIAR'
|
||||||
|
purchase4.clean()
|
||||||
|
purchase4.save()
|
||||||
|
|
||||||
|
line4 = SaleLine()
|
||||||
|
line4.sale = purchase4
|
||||||
|
line4.product = product
|
||||||
|
line4.quantity = "47"
|
||||||
|
line4.unit_price = "72500"
|
||||||
|
line4.save()
|
||||||
|
self.purchase4 = purchase4
|
||||||
|
|
||||||
|
def test_create_reconciliation_jar(self):
|
||||||
|
reconciliation = self._create_reconciliation()
|
||||||
|
self.assertTrue(isinstance(reconciliation, ReconciliationJar))
|
||||||
|
|
||||||
|
def test_get_purchases_for_reconciliation(self):
|
||||||
|
# link purchase to reconciliation to exclude from list
|
||||||
|
reconciliation = self._create_reconciliation()
|
||||||
|
self.purchase3.reconciliation = reconciliation
|
||||||
|
self.purchase3.clean()
|
||||||
|
self.purchase3.save()
|
||||||
|
|
||||||
|
url = '/don_confiao/purchases/for_reconciliation'
|
||||||
|
response = self.client.get(url)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
rawContent = response.content.decode('utf-8')
|
||||||
|
content = json.loads(rawContent)
|
||||||
|
|
||||||
|
self.assertIn('CASH', content.keys())
|
||||||
|
self.assertIn('CONFIAR', content.keys())
|
||||||
|
self.assertEqual(2, len(content.get('CASH')))
|
||||||
|
self.assertEqual(1, len(content.get('CONFIAR')))
|
||||||
|
self.assertNotIn(str(37*72500), rawContent)
|
||||||
|
self.assertIn(str(47*72500), rawContent)
|
||||||
|
|
||||||
|
def _create_reconciliation(self):
|
||||||
|
reconciliation = ReconciliationJar()
|
||||||
|
reconciliation.date_time = "2024-07-30"
|
||||||
|
reconciliation.cash_taken = 0
|
||||||
|
reconciliation.cash_discrepancy = 0
|
||||||
|
reconciliation.clean()
|
||||||
|
reconciliation.save()
|
||||||
|
return reconciliation
|
@ -28,5 +28,6 @@ urlpatterns = [
|
|||||||
path("resumen_compra/<int:id>", views.purchase_summary, name="purchase_summary"),
|
path("resumen_compra/<int:id>", views.purchase_summary, name="purchase_summary"),
|
||||||
path("resumen_compra_json/<int:id>", views.purchase_json_summary, name="purchase_json_summary"),
|
path("resumen_compra_json/<int:id>", views.purchase_json_summary, name="purchase_json_summary"),
|
||||||
path("payment_methods/all/select_format", views.payment_methods_to_select, name="payment_methods_to_select"),
|
path("payment_methods/all/select_format", views.payment_methods_to_select, name="payment_methods_to_select"),
|
||||||
|
path('purchases/for_reconciliation', views.sales_for_reconciliation, name='sales_for_reconciliation'),
|
||||||
path('api/', include(router.urls)),
|
path('api/', include(router.urls)),
|
||||||
]
|
]
|
||||||
|
@ -178,6 +178,24 @@ def payment_methods_to_select(request):
|
|||||||
return JsonResponse(methods, safe=False)
|
return JsonResponse(methods, safe=False)
|
||||||
|
|
||||||
|
|
||||||
|
def sales_for_reconciliation(request):
|
||||||
|
sales = Sale.objects.filter(reconciliation=None)
|
||||||
|
grouped_sales = {}
|
||||||
|
for sale in sales:
|
||||||
|
if sale.payment_method not in grouped_sales.keys():
|
||||||
|
grouped_sales[sale.payment_method] = []
|
||||||
|
grouped_sales[sale.payment_method].append({
|
||||||
|
'id': sale.id,
|
||||||
|
'date': sale.date,
|
||||||
|
'payment_method': sale.payment_method,
|
||||||
|
'customer': {
|
||||||
|
'id': sale.customer.id,
|
||||||
|
'name': sale.customer.name,
|
||||||
|
},
|
||||||
|
'total': sale.get_total(),
|
||||||
|
})
|
||||||
|
return JsonResponse(grouped_sales, safe=False)
|
||||||
|
|
||||||
def _mask_phone(phone):
|
def _mask_phone(phone):
|
||||||
digits = str(phone)[-3:] if phone else " " * 3
|
digits = str(phone)[-3:] if phone else " " * 3
|
||||||
return "X" * 7 + digits
|
return "X" * 7 + digits
|
||||||
|
Loading…
Reference in New Issue
Block a user