From 6aca2007e0a54a8f46210d698ca0ff41fe2d5efa Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Fri, 15 Nov 2024 17:44:30 -0500 Subject: [PATCH 01/25] #69 feat(View): add reconciliation jar components. --- .../frontend/don-confiao/src/components/NavBar.vue | 1 + .../don-confiao/src/components/ReconciliationJar.vue | 7 +++++++ .../frontend/don-confiao/src/pages/cuadrar_tarro.vue | 7 +++++++ 3 files changed, 15 insertions(+) create mode 100644 tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue create mode 100644 tienda_ilusion/don_confiao/frontend/don-confiao/src/pages/cuadrar_tarro.vue diff --git a/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/NavBar.vue b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/NavBar.vue index b30c914..3c25a2a 100644 --- a/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/NavBar.vue +++ b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/NavBar.vue @@ -29,6 +29,7 @@ menuItems: [ { title: 'Inicio', route: '/'}, { title: 'Comprar', route:'/comprar'}, + { title: 'Cuadrar tarro', route: '/cuadrar_tarro'} ], }), watch: { diff --git a/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue new file mode 100644 index 0000000..6b2472c --- /dev/null +++ b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue @@ -0,0 +1,7 @@ + diff --git a/tienda_ilusion/don_confiao/frontend/don-confiao/src/pages/cuadrar_tarro.vue b/tienda_ilusion/don_confiao/frontend/don-confiao/src/pages/cuadrar_tarro.vue new file mode 100644 index 0000000..4578345 --- /dev/null +++ b/tienda_ilusion/don_confiao/frontend/don-confiao/src/pages/cuadrar_tarro.vue @@ -0,0 +1,7 @@ + + + From c709dad36e3b47790ff0c3562d5f4ed991173839 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 16 Nov 2024 16:48:07 -0500 Subject: [PATCH 02/25] #69 base ReconciliationJar. --- .../src/components/ReconciliationJar.vue | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue index 6b2472c..13ce8c2 100644 --- a/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue +++ b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue @@ -3,5 +3,98 @@ Cuadre del Tarro + + + + + + + + + + + + + {{ payment_method }} {{ totalByMethod(payment_method) }} + + + + + + + + From 746686afccdea1d6caea5aba380d1be475b466e1 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 16 Nov 2024 20:36:38 -0500 Subject: [PATCH 03/25] #69 style(Reconciliation): cards to tabs. --- .../src/components/ReconciliationJar.vue | 42 ++++++++++++------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue index 13ce8c2..c31b9a0 100644 --- a/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue +++ b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue @@ -3,8 +3,7 @@ Cuadre del Tarro - - + - - - - {{ payment_method }} {{ totalByMethod(payment_method) }} - - - - + + + {{ payment_method }} {{ totalByMethod(payment_method) }} + + - + + + + + + + + + + diff --git a/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue index c31b9a0..e42f5c7 100644 --- a/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue +++ b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue @@ -22,16 +22,23 @@ v-model="reconciliation.total_cash_purchases" label="Total Ventas en efectivo" :rules="[rules.required]" + prefix="$" + type="number" + readonly > @@ -41,7 +48,7 @@ :key="payment_method" :value="payment_method" > - {{ payment_method }} {{ totalByMethod(payment_method) }} + {{ payment_method }}  @@ -65,6 +72,7 @@ From bd6d4221b2aeb87869838ff4bbb38eb34055b196 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 16 Nov 2024 23:10:43 -0500 Subject: [PATCH 05/25] #69 feat(Reconciliation): improve datetime on form. --- .../src/components/ReconciliationJar.vue | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue index e42f5c7..0250d3d 100644 --- a/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue +++ b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue @@ -8,9 +8,10 @@ From ef1a520838a3394e74b58f9d483339a3e2812149 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sun, 17 Nov 2024 00:02:08 -0500 Subject: [PATCH 06/25] #69 feat(Reconciliation): show summary on modal. --- .../src/components/ReconciliationJar.vue | 14 +++++++++ .../src/components/SummaryPurchaseModal.vue | 30 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 tienda_ilusion/don_confiao/frontend/don-confiao/src/components/SummaryPurchaseModal.vue diff --git a/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue index 0250d3d..6e8fea5 100644 --- a/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue +++ b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue @@ -65,8 +65,12 @@ :headers="summary.headers" :items="summary.purchases[payment_method]" > + + @@ -74,13 +78,19 @@ diff --git a/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/SummaryPurchaseModal.vue b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/SummaryPurchaseModal.vue new file mode 100644 index 0000000..0079d0f --- /dev/null +++ b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/SummaryPurchaseModal.vue @@ -0,0 +1,30 @@ + + + From b7984f75561c330ac517e8e0ade50580059404b6 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sun, 17 Nov 2024 00:07:18 -0500 Subject: [PATCH 07/25] #69 style(Reconciliation): format total on sales. --- .../frontend/don-confiao/src/components/CurrencyText.vue | 1 - .../frontend/don-confiao/src/components/ReconciliationJar.vue | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/CurrencyText.vue b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/CurrencyText.vue index 29ec815..924572f 100644 --- a/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/CurrencyText.vue +++ b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/CurrencyText.vue @@ -20,7 +20,6 @@ computed: { formattedValue() { return new Intl.NumberFormat(this.locale, { style: 'currency', currency: this.currency }).format(this.value); - /* return Intl.NumberFormat(this.value, this.locale, this.currency).toString(); */ }, }, } diff --git a/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue index 6e8fea5..92c2d09 100644 --- a/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue +++ b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue @@ -68,6 +68,9 @@ + From a6b4c1c5b63881241ee79b57c68f58c08fd801e5 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sun, 17 Nov 2024 23:15:21 -0500 Subject: [PATCH 08/25] #69 feat(Reconciliation):get purchases for reconciliation endpoint. --- ...ion_alter_payment_type_payment_and_more.py | 29 +++++ tienda_ilusion/don_confiao/models.py | 70 ++++++----- .../tests/test_jar_reconciliation.py | 111 ++++++++++++++++++ tienda_ilusion/don_confiao/urls.py | 1 + tienda_ilusion/don_confiao/views.py | 18 +++ 5 files changed, 197 insertions(+), 32 deletions(-) create mode 100644 tienda_ilusion/don_confiao/migrations/0034_sale_reconciliation_alter_payment_type_payment_and_more.py create mode 100644 tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py diff --git a/tienda_ilusion/don_confiao/migrations/0034_sale_reconciliation_alter_payment_type_payment_and_more.py b/tienda_ilusion/don_confiao/migrations/0034_sale_reconciliation_alter_payment_type_payment_and_more.py new file mode 100644 index 0000000..46d27ac --- /dev/null +++ b/tienda_ilusion/don_confiao/migrations/0034_sale_reconciliation_alter_payment_type_payment_and_more.py @@ -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), + ), + ] diff --git a/tienda_ilusion/don_confiao/models.py b/tienda_ilusion/don_confiao/models.py index ff21a72..911f943 100644 --- a/tienda_ilusion/don_confiao/models.py +++ b/tienda_ilusion/don_confiao/models.py @@ -62,6 +62,38 @@ class Product(models.Model): 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): customer = models.ForeignKey(Customer, on_delete=models.PROTECT) date = models.DateField("Date") @@ -74,6 +106,12 @@ class Sale(models.Model): blank=False, null=False ) + reconciliation = models.ForeignKey( + ReconciliationJar, + on_delete=models.RESTRICT, + related_name='Sales', + null=True + ) def __str__(self): return f"{self.date} {self.customer}" @@ -122,38 +160,6 @@ class ReconciliationJarSummary(): 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): date_time = models.DateTimeField() type_payment = models.CharField( diff --git a/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py b/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py new file mode 100644 index 0000000..708a6ee --- /dev/null +++ b/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py @@ -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 diff --git a/tienda_ilusion/don_confiao/urls.py b/tienda_ilusion/don_confiao/urls.py index 0f7dc41..997f3f0 100644 --- a/tienda_ilusion/don_confiao/urls.py +++ b/tienda_ilusion/don_confiao/urls.py @@ -28,5 +28,6 @@ urlpatterns = [ path("resumen_compra/", views.purchase_summary, name="purchase_summary"), path("resumen_compra_json/", 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('purchases/for_reconciliation', views.sales_for_reconciliation, name='sales_for_reconciliation'), path('api/', include(router.urls)), ] diff --git a/tienda_ilusion/don_confiao/views.py b/tienda_ilusion/don_confiao/views.py index d332065..ca494f6 100644 --- a/tienda_ilusion/don_confiao/views.py +++ b/tienda_ilusion/don_confiao/views.py @@ -178,6 +178,24 @@ def payment_methods_to_select(request): 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): digits = str(phone)[-3:] if phone else " " * 3 return "X" * 7 + digits From 9a20212b270ea4a106053926bfaaba9bedaeee35 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sun, 17 Nov 2024 23:55:54 -0500 Subject: [PATCH 09/25] #69 feat(Reconciliation):get purchases from backend. --- .../src/components/ReconciliationJar.vue | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue index 92c2d09..201cb97 100644 --- a/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue +++ b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue @@ -69,7 +69,7 @@ {{ item.id }} @@ -94,7 +94,7 @@ data () { return { selectedPurchaseId: null, - selectedTab: null, + selectedTab: 'CASH', reconciliation: { datetime: '', total_cash_purchases: 0, @@ -112,14 +112,7 @@ {title: 'Cliente', value: 'customer.name'}, {title: 'Total', value: 'total'}, ], - purchases: { - cash: [ - {id: 1, date: '2024-02-01', customer:{name: 'camilocash'}, total: 12000}, - {id: 1, date: '2024-02-01', customer:{name: 'camilocash'}, total: 12000} - ], - confiar: [{id: 1, date: '2024-02-01', customer:{name: 'camiloconfiar'}, total: 12000}], - bancolombia: [{id: 1, date: '2024-02-01', customer:{name: 'camilobancolobia'}, total: 12000}], - }, + purchases: {}, }, rules: { required: value => !!value || 'Requerido.', @@ -128,7 +121,7 @@ }; }, mounted() { - this.reconciliation.total_cash_purchases = this.totalByMethod('cash'); + this.fetchPurchases(); this.reconciliation.datetime = this.getCurrentDate(); }, watch: { @@ -139,7 +132,7 @@ methods: { totalByMethod(method) { if (method in this.summary.purchases) { - return this.summary.purchases[method].reduce((a, b) => a + b.total, 0); + return this.summary.purchases[method].reduce((a, b) => a + parseFloat(b.total), 0); } return 0; }, @@ -158,6 +151,18 @@ this.selectedPurchaseId = id; this.$refs.summaryModal.dialog = true; }, + fetchPurchases() { + const endpoint = '/don_confiao/purchases/for_reconciliation'; + fetch(endpoint) + .then(response => response.json()) + .then(data => { + this.summary.purchases = data; + this.reconciliation.total_cash_purchases = this.totalByMethod('CASH'); + }) + .catch(error => { + console.error(error); + }); + }, }, } From 0a643730373f249292ed40d0501550994e7c05d8 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Mon, 2 Dec 2024 21:22:06 -0500 Subject: [PATCH 10/25] ci(Test): add task tests to Rake. --- Rakefile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Rakefile b/Rakefile index cd59006..68777fb 100644 --- a/Rakefile +++ b/Rakefile @@ -52,6 +52,14 @@ namespace :live do end +desc 'Desarrollo' +namespace :dev do + desc 'correr test de django' + task :test do + compose('exec', 'django', 'python', '/app/manage.py', 'test', '/app/don_confiao') + end +end + def compose(*arg, compose: DOCKER_COMPOSE) sh "docker compose -f #{compose} #{arg.join(' ')}" end From 3189363ba9c9d5923da57c2f1f3d496750566700 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Mon, 2 Dec 2024 21:22:36 -0500 Subject: [PATCH 11/25] style: minor fix. --- .../don_confiao/tests/test_reconciliation_jar_client.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tienda_ilusion/don_confiao/tests/test_reconciliation_jar_client.py b/tienda_ilusion/don_confiao/tests/test_reconciliation_jar_client.py index ae9ba90..5deb698 100644 --- a/tienda_ilusion/don_confiao/tests/test_reconciliation_jar_client.py +++ b/tienda_ilusion/don_confiao/tests/test_reconciliation_jar_client.py @@ -29,7 +29,6 @@ class TestReconciliationJarClient(TestCase): ) self.assertRedirects(response, '/don_confiao/cuadres') - def _generate_two_cash_payments(self): cash_payment1 = Payment() cash_payment1.date_time = '2024-07-07 12:00:00' From 3294b8e8149611b22c81423744480d7a448cc704 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Mon, 2 Dec 2024 21:28:20 -0500 Subject: [PATCH 12/25] refactor(test): rename method. --- tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py b/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py index 708a6ee..19ad36d 100644 --- a/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py +++ b/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py @@ -77,12 +77,12 @@ class TestJarReconcliation(TestCase): self.purchase4 = purchase4 def test_create_reconciliation_jar(self): - reconciliation = self._create_reconciliation() + reconciliation = self._create_simple_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() + reconciliation = self._create_simple_reconciliation() self.purchase3.reconciliation = reconciliation self.purchase3.clean() self.purchase3.save() @@ -101,7 +101,7 @@ class TestJarReconcliation(TestCase): self.assertNotIn(str(37*72500), rawContent) self.assertIn(str(47*72500), rawContent) - def _create_reconciliation(self): + def _create_simple_reconciliation(self): reconciliation = ReconciliationJar() reconciliation.date_time = "2024-07-30" reconciliation.cash_taken = 0 From 0d61e457c7f875c0543827f3370e107e18416c43 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Mon, 2 Dec 2024 21:43:48 -0500 Subject: [PATCH 13/25] #69 refactor(ReconciliationJar): remove old view. --- tienda_ilusion/don_confiao/models.py | 18 ---- .../templates/don_confiao/menu.html | 1 - .../don_confiao/reconciliate_jar.html | 34 ------- .../don_confiao/tests/test_billing.py | 88 ------------------- .../tests/test_reconciliation_jar_client.py | 44 ---------- tienda_ilusion/don_confiao/urls.py | 1 - tienda_ilusion/don_confiao/views.py | 18 +--- 7 files changed, 1 insertion(+), 203 deletions(-) delete mode 100644 tienda_ilusion/don_confiao/templates/don_confiao/reconciliate_jar.html delete mode 100644 tienda_ilusion/don_confiao/tests/test_billing.py delete mode 100644 tienda_ilusion/don_confiao/tests/test_reconciliation_jar_client.py diff --git a/tienda_ilusion/don_confiao/models.py b/tienda_ilusion/don_confiao/models.py index 911f943..ada1cdc 100644 --- a/tienda_ilusion/don_confiao/models.py +++ b/tienda_ilusion/don_confiao/models.py @@ -70,24 +70,6 @@ class ReconciliationJar(models.Model): 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) diff --git a/tienda_ilusion/don_confiao/templates/don_confiao/menu.html b/tienda_ilusion/don_confiao/templates/don_confiao/menu.html index b5b21d7..7b60ddc 100644 --- a/tienda_ilusion/don_confiao/templates/don_confiao/menu.html +++ b/tienda_ilusion/don_confiao/templates/don_confiao/menu.html @@ -10,7 +10,6 @@
  • Productos
  • Importar Productos
  • Importar Terceros
  • -
  • Cuadrar tarro
  • Don Confiao - Tienda la Ilusión

    diff --git a/tienda_ilusion/don_confiao/templates/don_confiao/reconciliate_jar.html b/tienda_ilusion/don_confiao/templates/don_confiao/reconciliate_jar.html deleted file mode 100644 index 74a47d3..0000000 --- a/tienda_ilusion/don_confiao/templates/don_confiao/reconciliate_jar.html +++ /dev/null @@ -1,34 +0,0 @@ -{% extends 'don_confiao/base.html' %} -{% block content %} - -{% if summary.total %} -
    -

    Pagos No reconciliados

    - - - - - - {% for payment in summary.payments %} - - {% endfor %} - - - - -
    FechaMonto
    {{ payment.date_time }}{{ payment.amount }}
    Total{{ summary.total }}
    -
    -
    - - {% csrf_token %} - {{ form.as_table }} -
    -
    -
    -{% else %} -
    -

    No hay pagos registrados.

    -
    -{% endif %} - -{% endblock %} diff --git a/tienda_ilusion/don_confiao/tests/test_billing.py b/tienda_ilusion/don_confiao/tests/test_billing.py deleted file mode 100644 index 69f6047..0000000 --- a/tienda_ilusion/don_confiao/tests/test_billing.py +++ /dev/null @@ -1,88 +0,0 @@ -from django.test import TestCase -from django.core.exceptions import ValidationError -from ..models import Payment, ReconciliationJar - - -class TestBilling(TestCase): - - def test_reconciliation_jar_summary(self): - 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) - ) - - 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' - confiar_payment.type_payment = 'CONFIAR' - confiar_payment.amount = 85000 - confiar_payment.save() - - bancolombia_payment = Payment() - bancolombia_payment.date_time = '2024-07-07 12:30:00' - bancolombia_payment.type_payment = 'BANCOLOMBIA' - bancolombia_payment.amount = 12000 - bancolombia_payment.save() - - jar_summary = Payment.get_reconciliation_jar_summary() - self.assertEqual(164000, jar_summary.total) - self.assertSetEqual( - {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() - - reconciliation_jar.add_payments(jar_summary.payments) - 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_taken = jar_summary.total - reconciliation_jar.cash_discrepancy = 0 - reconciliation_jar.save() - - reconciliation_jar.add_payments(jar_summary.payments) - 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] diff --git a/tienda_ilusion/don_confiao/tests/test_reconciliation_jar_client.py b/tienda_ilusion/don_confiao/tests/test_reconciliation_jar_client.py deleted file mode 100644 index 5deb698..0000000 --- a/tienda_ilusion/don_confiao/tests/test_reconciliation_jar_client.py +++ /dev/null @@ -1,44 +0,0 @@ -from django.test import Client, TestCase -from django.contrib.auth.models import AnonymousUser, User - -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) - self.assertEqual(response.context["summary"].total, 160000) - self.assertIn('160000', response.content.decode('utf-8')) - - def test_create_reconciliation_jar(self): - self._generate_two_cash_payments() - response = self.client.post( - "/don_confiao/cuadrar_tarro", - { - "date_time": "2024-07-20T00:00", - "description": "Cuadre de prueba", - "reconcilier": "Jorge", - "cash_taken": "100000", - "cash_discrepancy": "60000", - } - ) - self.assertRedirects(response, '/don_confiao/cuadres') - - 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() - - 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() diff --git a/tienda_ilusion/don_confiao/urls.py b/tienda_ilusion/don_confiao/urls.py index 997f3f0..c874c4e 100644 --- a/tienda_ilusion/don_confiao/urls.py +++ b/tienda_ilusion/don_confiao/urls.py @@ -24,7 +24,6 @@ urlpatterns = [ views.exportar_ventas_para_tryton, name="exportar_ventas_para_tryton"), path("cuadrar_tarro", views.reconciliate_jar, name="reconciliate_jar"), - path("cuadres", views.reconciliate_jar, name="reconciliations"), path("resumen_compra/", views.purchase_summary, name="purchase_summary"), path("resumen_compra_json/", views.purchase_json_summary, name="purchase_json_summary"), path("payment_methods/all/select_format", views.payment_methods_to_select, name="payment_methods_to_select"), diff --git a/tienda_ilusion/don_confiao/views.py b/tienda_ilusion/don_confiao/views.py index ca494f6..7fd7329 100644 --- a/tienda_ilusion/don_confiao/views.py +++ b/tienda_ilusion/don_confiao/views.py @@ -10,7 +10,6 @@ from .forms import ( ImportCustomersForm, PurchaseForm, SaleLineFormSet, - ReconciliationJarForm, PurchaseSummaryForm) import csv @@ -110,22 +109,7 @@ def import_customers(request): ) def reconciliate_jar(request): - summary = Payment.get_reconciliation_jar_summary() - if request.method == 'POST': - form = ReconciliationJarForm(request.POST) - if form.is_valid(): - reconciliation = form.save() - reconciliation.add_payments(summary.payments) - reconciliation.clean() - reconciliation.save() - return HttpResponseRedirect('cuadres') - else: - form = ReconciliationJarForm() - return render( - request, - "don_confiao/reconciliate_jar.html", - {'summary': summary, 'form': form} - ) + pass def reconciliations(request): From 4679170ab97b2d796c428fa44e2fef0bbe9ef32d Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Mon, 2 Dec 2024 21:44:21 -0500 Subject: [PATCH 14/25] #69 refactor(ReconciliationJar): remove old form. --- tienda_ilusion/don_confiao/forms.py | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/tienda_ilusion/don_confiao/forms.py b/tienda_ilusion/don_confiao/forms.py index 0b9df88..faef067 100644 --- a/tienda_ilusion/don_confiao/forms.py +++ b/tienda_ilusion/don_confiao/forms.py @@ -3,7 +3,7 @@ from django.forms.models import inlineformset_factory from django.forms.widgets import DateInput, DateTimeInput -from .models import Sale, SaleLine, ReconciliationJar, PaymentMethods +from .models import Sale, SaleLine, PaymentMethods readonly_number_widget = forms.NumberInput(attrs={'readonly': 'readonly'}) @@ -64,18 +64,3 @@ SaleLineFormSet = inlineformset_factory( extra=1, fields='__all__' ) - - -class ReconciliationJarForm(forms.ModelForm): - class Meta: - model = ReconciliationJar - fields = [ - 'date_time', - 'description', - 'reconcilier', - 'cash_taken', - 'cash_discrepancy', - ] - widgets = { - 'date_time': DateTimeInput(attrs={'type': 'datetime-local'}) - } From a3d5fb1b45aa65cea1bb283619d17e92143effe2 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Mon, 2 Dec 2024 21:56:23 -0500 Subject: [PATCH 15/25] ci(Rake): add dev migrations tasks. --- Rakefile | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Rakefile b/Rakefile index 68777fb..1668191 100644 --- a/Rakefile +++ b/Rakefile @@ -54,10 +54,22 @@ end desc 'Desarrollo' namespace :dev do + desc 'correr test de django' task :test do compose('exec', 'django', 'python', '/app/manage.py', 'test', '/app/don_confiao') end + + desc 'crear migraciones' + task :makemigrations do + compose('exec', 'django', 'python', '/app/manage.py', 'makemigrations') + end + + desc 'aplicar migraciones' + task :migrate do + compose('exec', 'django', 'python', '/app/manage.py', 'migrate') + end + end def compose(*arg, compose: DOCKER_COMPOSE) From bea08da17d4f4faabe2913ec95d9e0b43900a572 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Mon, 2 Dec 2024 22:00:05 -0500 Subject: [PATCH 16/25] #69 feat(ReconciliationJar): Add total_cash_purchases field. --- ..._reconciliationjar_total_cash_purchases.py | 19 +++++++++++++++++++ tienda_ilusion/don_confiao/models.py | 11 +++++++++++ .../tests/test_jar_reconciliation.py | 12 ++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 tienda_ilusion/don_confiao/migrations/0035_reconciliationjar_total_cash_purchases.py diff --git a/tienda_ilusion/don_confiao/migrations/0035_reconciliationjar_total_cash_purchases.py b/tienda_ilusion/don_confiao/migrations/0035_reconciliationjar_total_cash_purchases.py new file mode 100644 index 0000000..55ba85f --- /dev/null +++ b/tienda_ilusion/don_confiao/migrations/0035_reconciliationjar_total_cash_purchases.py @@ -0,0 +1,19 @@ +# Generated by Django 5.0.6 on 2024-12-03 02:55 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('don_confiao', '0034_sale_reconciliation_alter_payment_type_payment_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='reconciliationjar', + name='total_cash_purchases', + field=models.DecimalField(decimal_places=2, default=0, max_digits=9), + preserve_default=False, + ), + ] diff --git a/tienda_ilusion/don_confiao/models.py b/tienda_ilusion/don_confiao/models.py index ada1cdc..c0b99ac 100644 --- a/tienda_ilusion/don_confiao/models.py +++ b/tienda_ilusion/don_confiao/models.py @@ -69,12 +69,23 @@ class ReconciliationJar(models.Model): 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) + total_cash_purchases = models.DecimalField(max_digits=9, decimal_places=2) + + def clean(self): + self._validate_taken_ammount() def add_payments(self, payments): for payment in payments: self.payment_set.add(payment) self.is_valid = True + def _validate_taken_ammount(self): + ammount_cash = self.cash_taken + self.cash_discrepancy + if not self.total_cash_purchases == ammount_cash: + raise ValidationError( + {"cash_taken": _("The taken ammount has discrepancy.")} + ) + class Sale(models.Model): customer = models.ForeignKey(Customer, on_delete=models.PROTECT) diff --git a/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py b/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py index 19ad36d..9a743fc 100644 --- a/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py +++ b/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py @@ -1,4 +1,5 @@ from django.test import TestCase, Client +from django.core.exceptions import ValidationError from ..models import Sale, Product, SaleLine, Customer, ReconciliationJar import json @@ -101,9 +102,20 @@ class TestJarReconcliation(TestCase): self.assertNotIn(str(37*72500), rawContent) self.assertIn(str(47*72500), rawContent) + def test_don_create_reconcialiation_with_bad_numbers(self): + reconciliation = ReconciliationJar() + reconciliation.date_time = "2024-07-30" + reconciliation.total_cash_purchases = 145000 + reconciliation.cash_taken = 143000 + reconciliation.cash_discrepancy = 1000 + with self.assertRaises(ValidationError): + reconciliation.clean() + reconciliation.save() + def _create_simple_reconciliation(self): reconciliation = ReconciliationJar() reconciliation.date_time = "2024-07-30" + reconciliation.total_cash_purchases = 0 reconciliation.cash_taken = 0 reconciliation.cash_discrepancy = 0 reconciliation.clean() From f0201a86b22cc87cd88e0cc816c3d241871048fd Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Mon, 2 Dec 2024 22:52:04 -0500 Subject: [PATCH 17/25] #69 feat(ReconciliationJar): accept post creation. --- .../tests/test_jar_reconciliation.py | 16 ++++++++++++++++ tienda_ilusion/don_confiao/urls.py | 2 +- tienda_ilusion/don_confiao/views.py | 19 +++++++++++++++++-- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py b/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py index 9a743fc..880cc0d 100644 --- a/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py +++ b/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py @@ -112,6 +112,22 @@ class TestJarReconcliation(TestCase): reconciliation.clean() reconciliation.save() + def test_create_reconciliation_with_purchases(self): + url = '/don_confiao/reconciliation_jar/create' + data = { + 'date_time': '2024-12-02T21:07', + 'cashman': 'carlos', + 'total_cash_purchases': 45000, + 'cash_taken': 44000, + 'cash_discrepancy': 1000, + } + response = self.client.post(url, data, format='json') + rawContent = response.content.decode('utf-8') + content = json.loads(rawContent) + + self.assertEqual(response.status_code, 200) + self.assertIn('id', content) + def _create_simple_reconciliation(self): reconciliation = ReconciliationJar() reconciliation.date_time = "2024-07-30" diff --git a/tienda_ilusion/don_confiao/urls.py b/tienda_ilusion/don_confiao/urls.py index c874c4e..3cd4d6c 100644 --- a/tienda_ilusion/don_confiao/urls.py +++ b/tienda_ilusion/don_confiao/urls.py @@ -23,10 +23,10 @@ urlpatterns = [ path("exportar_ventas_para_tryton", views.exportar_ventas_para_tryton, name="exportar_ventas_para_tryton"), - path("cuadrar_tarro", views.reconciliate_jar, name="reconciliate_jar"), path("resumen_compra/", views.purchase_summary, name="purchase_summary"), path("resumen_compra_json/", 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('purchases/for_reconciliation', views.sales_for_reconciliation, name='sales_for_reconciliation'), + path('reconciliation_jar/create', views.reconciliate_jar, name='reconciliate_jar'), path('api/', include(router.urls)), ] diff --git a/tienda_ilusion/don_confiao/views.py b/tienda_ilusion/don_confiao/views.py index 7fd7329..c6e5f48 100644 --- a/tienda_ilusion/don_confiao/views.py +++ b/tienda_ilusion/don_confiao/views.py @@ -4,7 +4,7 @@ from django.views.generic import ListView from django.db import transaction from .models import ( - Sale, SaleLine, Product, Customer, ProductCategory, Payment, PaymentMethods) + Sale, SaleLine, Product, Customer, ProductCategory, Payment, PaymentMethods, ReconciliationJar) from .forms import ( ImportProductsForm, ImportCustomersForm, @@ -16,6 +16,7 @@ import csv import io import json from decimal import Decimal +from datetime import datetime class DecimalEncoder(json.JSONEncoder): @@ -109,7 +110,21 @@ def import_customers(request): ) def reconciliate_jar(request): - pass + date_format = '%Y-%m-%dT%H:%M' + if request.method == 'POST': + content = request.POST.dict() + reconciliation = ReconciliationJar() + reconciliation.date_time = content.get('date_time') + reconciliation.cashman = content.get('cashman') + reconciliation.total_cash_purchases = float(content.get('total_cash_purchases')) + reconciliation.cash_taken = float(content.get('cash_taken')) + reconciliation.cash_discrepancy = float(content.get('cash_discrepancy')) + reconciliation.clean() + reconciliation.save() + return JsonResponse( + {'id': reconciliation.id}, + safe=False + ) def reconciliations(request): From ef721a6b53065f6e601f600cbaaff0a56f895699 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Fri, 13 Dec 2024 17:21:29 -0500 Subject: [PATCH 18/25] #69 feat(ReconciliationJar): add purchases to list. --- .../don_confiao/tests/test_jar_reconciliation.py | 16 +++++++++++++--- tienda_ilusion/don_confiao/views.py | 11 +++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py b/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py index 880cc0d..8397cbc 100644 --- a/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py +++ b/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py @@ -4,6 +4,7 @@ from ..models import Sale, Product, SaleLine, Customer, ReconciliationJar import json + class TestJarReconcliation(TestCase): def setUp(self): customer = Customer() @@ -114,12 +115,18 @@ class TestJarReconcliation(TestCase): def test_create_reconciliation_with_purchases(self): url = '/don_confiao/reconciliation_jar/create' + total_purchases = (11 * 72500) + (27 * 72500) data = { 'date_time': '2024-12-02T21:07', 'cashman': 'carlos', - 'total_cash_purchases': 45000, - 'cash_taken': 44000, - 'cash_discrepancy': 1000, + 'total_cash_purchases': total_purchases, + 'cash_taken': total_purchases, + 'cash_discrepancy': 0, + 'purchases': json.dumps([#machete por error al codificar el json en el request + self.purchase.id, + self.purchase2.id, + self.purchase.id, + ]), } response = self.client.post(url, data, format='json') rawContent = response.content.decode('utf-8') @@ -128,6 +135,9 @@ class TestJarReconcliation(TestCase): self.assertEqual(response.status_code, 200) self.assertIn('id', content) + purchases = Sale.objects.filter(reconciliation_id=content['id']) + self.assertEqual(len(purchases), 2) + def _create_simple_reconciliation(self): reconciliation = ReconciliationJar() reconciliation.date_time = "2024-07-30" diff --git a/tienda_ilusion/don_confiao/views.py b/tienda_ilusion/don_confiao/views.py index c6e5f48..d4fec5d 100644 --- a/tienda_ilusion/don_confiao/views.py +++ b/tienda_ilusion/don_confiao/views.py @@ -113,14 +113,25 @@ def reconciliate_jar(request): date_format = '%Y-%m-%dT%H:%M' if request.method == 'POST': content = request.POST.dict() + content['purchases'] = json.loads(content.get('purchases'))#machete por error al codificar el json en el test reconciliation = ReconciliationJar() reconciliation.date_time = content.get('date_time') reconciliation.cashman = content.get('cashman') reconciliation.total_cash_purchases = float(content.get('total_cash_purchases')) reconciliation.cash_taken = float(content.get('cash_taken')) reconciliation.cash_discrepancy = float(content.get('cash_discrepancy')) + purchases = Sale.objects.filter(pk__in=content.get('purchases')) + if reconciliation.total_cash_purchases != sum(p.get_total() for p in purchases): + return JsonResponse( + {'error': 'total_cash_purchases not equal to sum of all purchases.'}, + status=400 + ) reconciliation.clean() reconciliation.save() + for purchase in purchases: + purchase.reconciliation = reconciliation + purchase.clean() + purchase.save() return JsonResponse( {'id': reconciliation.id}, safe=False From 1f2f484e95600cee271deb07dc2253b779814b84 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 14 Dec 2024 09:59:26 -0500 Subject: [PATCH 19/25] #69 test(ReconciliationJar): add failed case. --- .../tests/test_jar_reconciliation.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py b/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py index 8397cbc..72899a3 100644 --- a/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py +++ b/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py @@ -113,6 +113,30 @@ class TestJarReconcliation(TestCase): reconciliation.clean() reconciliation.save() + def test_fail_create_reconciliation_with_wrong_total_purchases_purchases(self): + url = '/don_confiao/reconciliation_jar/create' + total_purchases = (11 * 72500) + (27 * 72500) + bad_total_purchases = total_purchases + 2 + data = { + 'date_time': '2024-12-02T21:07', + 'cashman': 'carlos', + 'total_cash_purchases': bad_total_purchases, + 'cash_taken': total_purchases, + 'cash_discrepancy': 0, + 'purchases': json.dumps([#machete por error al codificar el json en el request + self.purchase.id, + self.purchase2.id, + self.purchase.id, + ]), + } + response = self.client.post(url, data, format='json') + rawContent = response.content.decode('utf-8') + content = json.loads(rawContent) + + self.assertEqual(response.status_code, 400) + self.assertIn('error', content) + self.assertIn('total_cash_purchases', content['error']) + def test_create_reconciliation_with_purchases(self): url = '/don_confiao/reconciliation_jar/create' total_purchases = (11 * 72500) + (27 * 72500) From f6620db6e26fca2eb6cf8e2c28842a480f74605e Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 14 Dec 2024 10:00:11 -0500 Subject: [PATCH 20/25] ci(Rakefile): add start command. --- Rakefile | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Rakefile b/Rakefile index 1668191..6519992 100644 --- a/Rakefile +++ b/Rakefile @@ -10,7 +10,7 @@ namespace :live do compose('up', '--build', '-d', compose: DOCKER_COMPOSE) end - desc 'monitorear salida' + desc 'monitorear salida' task :tail do compose('logs', '-f', 'django', compose: DOCKER_COMPOSE) end @@ -20,7 +20,12 @@ namespace :live do compose('logs', '-f', '-n 50', 'django', compose: DOCKER_COMPOSE) end - desc 'detener entorno' + desc 'iniciar entorno' + task :start do + compose('start', compose: DOCKER_COMPOSE) + end + + desc 'bajar entorno' task :down do compose('down', compose: DOCKER_COMPOSE) end From 1b425542b34f82cc300bb4804a2d4039d535f561 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 14 Dec 2024 19:42:59 -0500 Subject: [PATCH 21/25] #69 feat(ReconciliationJar): send reconciliation jar from frontend --- tienda_ilusion/don_confiao/api_views.py | 35 ++++++++++- .../src/components/ReconciliationJar.vue | 61 +++++++++++++++---- tienda_ilusion/don_confiao/serializers.py | 16 ++++- .../tests/test_jar_reconciliation.py | 6 +- tienda_ilusion/don_confiao/urls.py | 1 + tienda_ilusion/don_confiao/views.py | 8 ++- 6 files changed, 109 insertions(+), 18 deletions(-) diff --git a/tienda_ilusion/don_confiao/api_views.py b/tienda_ilusion/don_confiao/api_views.py index ef0d617..89e9e23 100644 --- a/tienda_ilusion/don_confiao/api_views.py +++ b/tienda_ilusion/don_confiao/api_views.py @@ -1,9 +1,13 @@ from rest_framework import viewsets from rest_framework.response import Response +from rest_framework.status import HTTP_400_BAD_REQUEST +from rest_framework.views import APIView -from .models import Sale, SaleLine, Customer, Product -from .serializers import SaleSerializer, ProductSerializer, CustomerSerializer +from .models import Sale, SaleLine, Customer, Product, ReconciliationJar +from .serializers import SaleSerializer, ProductSerializer, CustomerSerializer, ReconciliationJarSerializer +from decimal import Decimal +import json class SaleView(viewsets.ModelViewSet): queryset = Sale.objects.all() @@ -46,3 +50,30 @@ class ProductView(viewsets.ModelViewSet): class CustomerView(viewsets.ModelViewSet): queryset = Customer.objects.all() serializer_class = CustomerSerializer + +class ReconciliateJarView(APIView): + def post(self, request): + data = request.data + cash_purchases_id = json.loads(data.get('cash_purchases')) + serializer = ReconciliationJarSerializer(data=data) + if serializer.is_valid(): + purchases = Sale.objects.filter(pk__in=cash_purchases_id) + + total_cash_purchases = sum(p.get_total() for p in purchases) + if total_cash_purchases != Decimal(data.get('total_cash_purchases')): + return Response( + {'error': 'total_cash_purchases not equal to sum of all purchases.'}, + status=HTTP_400_BAD_REQUEST + ) + reconciliation = serializer.save() + for purchase in purchases: + purchase.reconciliation = reconciliation + purchase.clean() + purchase.save() + return Response({'id': reconciliation.id}) + return Response(serializer.errors, status=HTTP_400_BAD_REQUEST) + + def get(self, request): + reconciliations = ReconciliationJar.objects.all() + serializer = ReconciliationJarSerializer(reconciliations, many=True) + return Response(serializer.data) diff --git a/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue index 201cb97..50882dc 100644 --- a/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue +++ b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue @@ -5,16 +5,17 @@ + + - + Recoger Dinero + @@ -93,10 +96,12 @@ }, data () { return { + valid: null, selectedPurchaseId: null, selectedTab: 'CASH', reconciliation: { - datetime: '', + csrfmiddlewaretoken: null, + date_time: '', total_cash_purchases: 0, cash_taken: 0, cash_discrepancy: 0, @@ -104,6 +109,7 @@ confiar: 0, bancolombia: 0 }, + cash_purchases: [], }, summary: { headers: [ @@ -122,7 +128,7 @@ }, mounted() { this.fetchPurchases(); - this.reconciliation.datetime = this.getCurrentDate(); + this.reconciliation.date_time = this.getCurrentDate(); }, watch: { 'reconciliation.cash_taken'() { @@ -151,18 +157,51 @@ this.selectedPurchaseId = id; this.$refs.summaryModal.dialog = true; }, + getCsrfToken() { + const cookies = document.cookie.split(';'); + const csrfToken = cookies.find(cookie => cookie.startsWith('csrftoken=')); + if (csrfToken) { + this.reconciliation.csrfmiddlewaretoken = csrfToken.split('=')[1]; + } + }, fetchPurchases() { const endpoint = '/don_confiao/purchases/for_reconciliation'; fetch(endpoint) .then(response => response.json()) .then(data => { this.summary.purchases = data; + this.reconciliation.cash_purchases = this.summary.purchases['CASH'].map(purchase => purchase.id); this.reconciliation.total_cash_purchases = this.totalByMethod('CASH'); + this.getCsrfToken(); }) .catch(error => { console.error(error); }); }, + async submit() { + this.$refs.taker.validate(); + if (this.valid) { + try { + const response = await fetch('/don_confiao/reconciliate_jar', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(this.reconciliation), + }); + if (response.ok) { + const data = await response.json(); + console.log('Cuadre enviado:', data); + this.$router.push({path: "/"}); + } else { + console.error('Error al enviar el cuadre', response.statusText); + + } + } catch (error) { + console.error('Error de red:', error); + } + } + }, }, } diff --git a/tienda_ilusion/don_confiao/serializers.py b/tienda_ilusion/don_confiao/serializers.py index 6792fd0..eb9db60 100644 --- a/tienda_ilusion/don_confiao/serializers.py +++ b/tienda_ilusion/don_confiao/serializers.py @@ -1,6 +1,6 @@ from rest_framework import serializers -from .models import Sale, SaleLine, Product, Customer +from .models import Sale, SaleLine, Product, Customer, ReconciliationJar class SaleLineSerializer(serializers.ModelSerializer): @@ -20,7 +20,21 @@ class ProductSerializer(serializers.ModelSerializer): model = Product fields = ['id', 'name', 'price', 'measuring_unit', 'categories'] + class CustomerSerializer(serializers.ModelSerializer): class Meta: model = Customer fields = ['id', 'name', 'address', 'email', 'phone'] + + +class ReconciliationJarSerializer(serializers.ModelSerializer): + class Meta: + model = ReconciliationJar + fields = [ + 'id', + 'date_time', + 'reconcilier', + 'cash_taken', + 'cash_discrepancy', + 'total_cash_purchases', + ] diff --git a/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py b/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py index 72899a3..2b49b09 100644 --- a/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py +++ b/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py @@ -138,15 +138,15 @@ class TestJarReconcliation(TestCase): self.assertIn('total_cash_purchases', content['error']) def test_create_reconciliation_with_purchases(self): - url = '/don_confiao/reconciliation_jar/create' + url = '/don_confiao/reconciliate_jar' total_purchases = (11 * 72500) + (27 * 72500) data = { 'date_time': '2024-12-02T21:07', - 'cashman': 'carlos', + 'reconcilier': 'carlos', 'total_cash_purchases': total_purchases, 'cash_taken': total_purchases, 'cash_discrepancy': 0, - 'purchases': json.dumps([#machete por error al codificar el json en el request + 'cash_purchases': json.dumps([#machete por error al codificar el json en el request self.purchase.id, self.purchase2.id, self.purchase.id, diff --git a/tienda_ilusion/don_confiao/urls.py b/tienda_ilusion/don_confiao/urls.py index 3cd4d6c..52925aa 100644 --- a/tienda_ilusion/don_confiao/urls.py +++ b/tienda_ilusion/don_confiao/urls.py @@ -28,5 +28,6 @@ urlpatterns = [ 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('reconciliation_jar/create', views.reconciliate_jar, name='reconciliate_jar'), + path('reconciliate_jar', api_views.ReconciliateJarView.as_view()), path('api/', include(router.urls)), ] diff --git a/tienda_ilusion/don_confiao/views.py b/tienda_ilusion/don_confiao/views.py index d4fec5d..c80f3fa 100644 --- a/tienda_ilusion/don_confiao/views.py +++ b/tienda_ilusion/don_confiao/views.py @@ -2,6 +2,7 @@ from django.shortcuts import render from django.http import HttpResponse, HttpResponseRedirect, JsonResponse from django.views.generic import ListView from django.db import transaction +from django.middleware.csrf import get_token from .models import ( Sale, SaleLine, Product, Customer, ProductCategory, Payment, PaymentMethods, ReconciliationJar) @@ -204,7 +205,12 @@ def sales_for_reconciliation(request): }, 'total': sale.get_total(), }) - return JsonResponse(grouped_sales, safe=False) + response = JsonResponse(grouped_sales, safe=False) + csrf_token = get_token(request) + response['X-CSRFToken'] = csrf_token + response['Access-Control-Allow-Headers'] = 'X-CSRFToken' + response.set_cookie('csrftoken', csrf_token) + return response def _mask_phone(phone): digits = str(phone)[-3:] if phone else " " * 3 From 8ab7903a0a88185eb8931d457812d4ba2b766070 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 14 Dec 2024 21:37:24 -0500 Subject: [PATCH 22/25] #69 test(ReconciliationJar): fix tests. --- tienda_ilusion/don_confiao/api_views.py | 4 +- .../src/components/ReconciliationJar.vue | 9 ----- .../tests/test_jar_reconciliation.py | 19 ++++++---- tienda_ilusion/don_confiao/urls.py | 1 - tienda_ilusion/don_confiao/views.py | 38 +------------------ 5 files changed, 15 insertions(+), 56 deletions(-) diff --git a/tienda_ilusion/don_confiao/api_views.py b/tienda_ilusion/don_confiao/api_views.py index 89e9e23..7130d7f 100644 --- a/tienda_ilusion/don_confiao/api_views.py +++ b/tienda_ilusion/don_confiao/api_views.py @@ -51,14 +51,14 @@ class CustomerView(viewsets.ModelViewSet): queryset = Customer.objects.all() serializer_class = CustomerSerializer + class ReconciliateJarView(APIView): def post(self, request): data = request.data - cash_purchases_id = json.loads(data.get('cash_purchases')) + cash_purchases_id = data.get('cash_purchases') serializer = ReconciliationJarSerializer(data=data) if serializer.is_valid(): purchases = Sale.objects.filter(pk__in=cash_purchases_id) - total_cash_purchases = sum(p.get_total() for p in purchases) if total_cash_purchases != Decimal(data.get('total_cash_purchases')): return Response( diff --git a/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue index 50882dc..d783651 100644 --- a/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue +++ b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue @@ -100,7 +100,6 @@ selectedPurchaseId: null, selectedTab: 'CASH', reconciliation: { - csrfmiddlewaretoken: null, date_time: '', total_cash_purchases: 0, cash_taken: 0, @@ -157,13 +156,6 @@ this.selectedPurchaseId = id; this.$refs.summaryModal.dialog = true; }, - getCsrfToken() { - const cookies = document.cookie.split(';'); - const csrfToken = cookies.find(cookie => cookie.startsWith('csrftoken=')); - if (csrfToken) { - this.reconciliation.csrfmiddlewaretoken = csrfToken.split('=')[1]; - } - }, fetchPurchases() { const endpoint = '/don_confiao/purchases/for_reconciliation'; fetch(endpoint) @@ -172,7 +164,6 @@ this.summary.purchases = data; this.reconciliation.cash_purchases = this.summary.purchases['CASH'].map(purchase => purchase.id); this.reconciliation.total_cash_purchases = this.totalByMethod('CASH'); - this.getCsrfToken(); }) .catch(error => { console.error(error); diff --git a/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py b/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py index 2b49b09..5b106c7 100644 --- a/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py +++ b/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py @@ -114,22 +114,23 @@ class TestJarReconcliation(TestCase): reconciliation.save() def test_fail_create_reconciliation_with_wrong_total_purchases_purchases(self): - url = '/don_confiao/reconciliation_jar/create' + url = '/don_confiao/reconciliate_jar' total_purchases = (11 * 72500) + (27 * 72500) bad_total_purchases = total_purchases + 2 data = { 'date_time': '2024-12-02T21:07', - 'cashman': 'carlos', + 'reconcilier': 'carlos', 'total_cash_purchases': bad_total_purchases, 'cash_taken': total_purchases, 'cash_discrepancy': 0, - 'purchases': json.dumps([#machete por error al codificar el json en el request + 'cash_purchases': [ self.purchase.id, self.purchase2.id, self.purchase.id, - ]), + ], } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data=json.dumps(data).encode('utf-8'), + content_type='application/json') rawContent = response.content.decode('utf-8') content = json.loads(rawContent) @@ -146,13 +147,15 @@ class TestJarReconcliation(TestCase): 'total_cash_purchases': total_purchases, 'cash_taken': total_purchases, 'cash_discrepancy': 0, - 'cash_purchases': json.dumps([#machete por error al codificar el json en el request + 'cash_purchases': [ self.purchase.id, self.purchase2.id, self.purchase.id, - ]), + ], } - response = self.client.post(url, data, format='json') + response = self.client.post(url, data=json.dumps(data).encode('utf-8'), + content_type='application/json') + rawContent = response.content.decode('utf-8') content = json.loads(rawContent) diff --git a/tienda_ilusion/don_confiao/urls.py b/tienda_ilusion/don_confiao/urls.py index 52925aa..18388f8 100644 --- a/tienda_ilusion/don_confiao/urls.py +++ b/tienda_ilusion/don_confiao/urls.py @@ -27,7 +27,6 @@ urlpatterns = [ path("resumen_compra_json/", 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('purchases/for_reconciliation', views.sales_for_reconciliation, name='sales_for_reconciliation'), - path('reconciliation_jar/create', views.reconciliate_jar, name='reconciliate_jar'), path('reconciliate_jar', api_views.ReconciliateJarView.as_view()), path('api/', include(router.urls)), ] diff --git a/tienda_ilusion/don_confiao/views.py b/tienda_ilusion/don_confiao/views.py index c80f3fa..a7f543b 100644 --- a/tienda_ilusion/don_confiao/views.py +++ b/tienda_ilusion/don_confiao/views.py @@ -2,7 +2,6 @@ from django.shortcuts import render from django.http import HttpResponse, HttpResponseRedirect, JsonResponse from django.views.generic import ListView from django.db import transaction -from django.middleware.csrf import get_token from .models import ( Sale, SaleLine, Product, Customer, ProductCategory, Payment, PaymentMethods, ReconciliationJar) @@ -17,7 +16,6 @@ import csv import io import json from decimal import Decimal -from datetime import datetime class DecimalEncoder(json.JSONEncoder): @@ -96,6 +94,7 @@ def import_products(request): {'form': form} ) + def import_customers(request): if request.method == "POST": form = ImportCustomersForm(request.POST, request.FILES) @@ -110,34 +109,6 @@ def import_customers(request): {'form': form} ) -def reconciliate_jar(request): - date_format = '%Y-%m-%dT%H:%M' - if request.method == 'POST': - content = request.POST.dict() - content['purchases'] = json.loads(content.get('purchases'))#machete por error al codificar el json en el test - reconciliation = ReconciliationJar() - reconciliation.date_time = content.get('date_time') - reconciliation.cashman = content.get('cashman') - reconciliation.total_cash_purchases = float(content.get('total_cash_purchases')) - reconciliation.cash_taken = float(content.get('cash_taken')) - reconciliation.cash_discrepancy = float(content.get('cash_discrepancy')) - purchases = Sale.objects.filter(pk__in=content.get('purchases')) - if reconciliation.total_cash_purchases != sum(p.get_total() for p in purchases): - return JsonResponse( - {'error': 'total_cash_purchases not equal to sum of all purchases.'}, - status=400 - ) - reconciliation.clean() - reconciliation.save() - for purchase in purchases: - purchase.reconciliation = reconciliation - purchase.clean() - purchase.save() - return JsonResponse( - {'id': reconciliation.id}, - safe=False - ) - def reconciliations(request): return HttpResponse('

    Reconciliaciones

    ') @@ -205,12 +176,7 @@ def sales_for_reconciliation(request): }, 'total': sale.get_total(), }) - response = JsonResponse(grouped_sales, safe=False) - csrf_token = get_token(request) - response['X-CSRFToken'] = csrf_token - response['Access-Control-Allow-Headers'] = 'X-CSRFToken' - response.set_cookie('csrftoken', csrf_token) - return response + return JsonResponse(grouped_sales, safe=False) def _mask_phone(phone): digits = str(phone)[-3:] if phone else " " * 3 From 9c0eebd07d65f84f0ff31002199ff591ad61b289 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 14 Dec 2024 22:34:58 -0500 Subject: [PATCH 23/25] #69 refactor(ReconciliationJar): extract to method. --- tienda_ilusion/don_confiao/api_views.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/tienda_ilusion/don_confiao/api_views.py b/tienda_ilusion/don_confiao/api_views.py index 7130d7f..e860314 100644 --- a/tienda_ilusion/don_confiao/api_views.py +++ b/tienda_ilusion/don_confiao/api_views.py @@ -58,18 +58,14 @@ class ReconciliateJarView(APIView): cash_purchases_id = data.get('cash_purchases') serializer = ReconciliationJarSerializer(data=data) if serializer.is_valid(): - purchases = Sale.objects.filter(pk__in=cash_purchases_id) - total_cash_purchases = sum(p.get_total() for p in purchases) - if total_cash_purchases != Decimal(data.get('total_cash_purchases')): + cash_purchases = Sale.objects.filter(pk__in=cash_purchases_id) + if not self._is_valid_total(cash_purchases, data.get('total_cash_purchases')): return Response( {'error': 'total_cash_purchases not equal to sum of all purchases.'}, status=HTTP_400_BAD_REQUEST ) reconciliation = serializer.save() - for purchase in purchases: - purchase.reconciliation = reconciliation - purchase.clean() - purchase.save() + self._link_purchases(reconciliation, cash_purchases) return Response({'id': reconciliation.id}) return Response(serializer.errors, status=HTTP_400_BAD_REQUEST) @@ -77,3 +73,13 @@ class ReconciliateJarView(APIView): reconciliations = ReconciliationJar.objects.all() serializer = ReconciliationJarSerializer(reconciliations, many=True) return Response(serializer.data) + + def _is_valid_total(self, purchases, total): + calculated_total = sum(p.get_total() for p in purchases) + return calculated_total == Decimal(total) + + def _link_purchases(self, reconciliation, purchases): + for purchase in purchases: + purchase.reconciliation = reconciliation + purchase.clean() + purchase.save() From 5cfefdf91a8746e32842369c05675cf4931d4735 Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 28 Dec 2024 17:01:51 -0500 Subject: [PATCH 24/25] #69 feat(ReconciliationJar): link purchases with other payment methods. --- tienda_ilusion/don_confiao/api_views.py | 23 +++++++++++-- .../src/components/ReconciliationJar.vue | 25 ++++++++++++--- .../tests/test_jar_reconciliation.py | 32 +++++++++++++++++++ 3 files changed, 72 insertions(+), 8 deletions(-) diff --git a/tienda_ilusion/don_confiao/api_views.py b/tienda_ilusion/don_confiao/api_views.py index e860314..bfb85bc 100644 --- a/tienda_ilusion/don_confiao/api_views.py +++ b/tienda_ilusion/don_confiao/api_views.py @@ -65,7 +65,9 @@ class ReconciliateJarView(APIView): status=HTTP_400_BAD_REQUEST ) reconciliation = serializer.save() - self._link_purchases(reconciliation, cash_purchases) + other_purchases = self._get_other_purchases(data.get('other_totals')) + + self._link_purchases(reconciliation, cash_purchases, other_purchases) return Response({'id': reconciliation.id}) return Response(serializer.errors, status=HTTP_400_BAD_REQUEST) @@ -78,8 +80,23 @@ class ReconciliateJarView(APIView): calculated_total = sum(p.get_total() for p in purchases) return calculated_total == Decimal(total) - def _link_purchases(self, reconciliation, purchases): - for purchase in purchases: + def _get_other_purchases(self, other_totals): + if not other_totals: + return [] + purchases = [] + for method in other_totals: + purchases.extend(other_totals[method]['purchases']) + if purchases: + return Sale.objects.filter(pk__in=purchases) + return [] + + def _link_purchases(self, reconciliation, cash_purchases, other_purchases): + for purchase in cash_purchases: + purchase.reconciliation = reconciliation + purchase.clean() + purchase.save() + + for purchase in other_purchases: purchase.reconciliation = reconciliation purchase.clean() purchase.save() diff --git a/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue index d783651..09b1891 100644 --- a/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue +++ b/tienda_ilusion/don_confiao/frontend/don-confiao/src/components/ReconciliationJar.vue @@ -105,8 +105,6 @@ cash_taken: 0, cash_discrepancy: 0, other_totals: { - confiar: 0, - bancolombia: 0 }, cash_purchases: [], }, @@ -141,6 +139,22 @@ } return 0; }, + idsBymethod(method) { + if (method in this.summary.purchases) { + return this.summary.purchases[method].map(purchase => purchase.id) + } + return []; + }, + processOtherMethods() { + for (const method of Object.keys(this.summary.purchases)) { + if (method !== 'CASH') { + this.reconciliation.other_totals[method] = { + total: this.totalByMethod(method), + purchases: this.idsBymethod(method), + } + } + } + }, updateDiscrepancy() { this.reconciliation.cash_discrepancy = (this.reconciliation.total_cash_purchases || 0 ) - (this.reconciliation.cash_taken || 0); }, @@ -162,8 +176,9 @@ .then(response => response.json()) .then(data => { this.summary.purchases = data; - this.reconciliation.cash_purchases = this.summary.purchases['CASH'].map(purchase => purchase.id); + this.reconciliation.cash_purchases = this.idsBymethod('CASH'); this.reconciliation.total_cash_purchases = this.totalByMethod('CASH'); + this.processOtherMethods(); }) .catch(error => { console.error(error); @@ -176,7 +191,7 @@ const response = await fetch('/don_confiao/reconciliate_jar', { method: 'POST', headers: { - 'Content-Type': 'application/json' + 'Content-Type': 'application/json' }, body: JSON.stringify(this.reconciliation), }); @@ -190,7 +205,7 @@ } } catch (error) { console.error('Error de red:', error); - } + } } }, }, diff --git a/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py b/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py index 5b106c7..de8503c 100644 --- a/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py +++ b/tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py @@ -165,6 +165,38 @@ class TestJarReconcliation(TestCase): purchases = Sale.objects.filter(reconciliation_id=content['id']) self.assertEqual(len(purchases), 2) + def test_create_reconciliation_with_purchases_and_other_totals(self): + url = '/don_confiao/reconciliate_jar' + total_purchases = (11 * 72500) + (27 * 72500) + data = { + 'date_time': '2024-12-02T21:07', + 'reconcilier': 'carlos', + 'total_cash_purchases': total_purchases, + 'cash_taken': total_purchases, + 'cash_discrepancy': 0, + 'cash_purchases': [ + self.purchase.id, + self.purchase2.id, + ], + 'other_totals': { + 'Confiar': { + 'total': (47 * 72500) + 1, + 'purchases': [self.purchase4.id], + }, + }, + } + response = self.client.post(url, data=json.dumps(data).encode('utf-8'), + content_type='application/json') + + rawContent = response.content.decode('utf-8') + content = json.loads(rawContent) + + self.assertEqual(response.status_code, 200) + self.assertIn('id', content) + + purchases = Sale.objects.filter(reconciliation_id=content['id']) + self.assertEqual(len(purchases), 3) + def _create_simple_reconciliation(self): reconciliation = ReconciliationJar() reconciliation.date_time = "2024-07-30" From b5fdd7fefd340f9bd8a4582ffac733c02faf2a4a Mon Sep 17 00:00:00 2001 From: Mono Mono Date: Sat, 28 Dec 2024 17:13:55 -0500 Subject: [PATCH 25/25] #69 fix(migrations): conflict. --- .../migrations/0036_merge_20241228_2212.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tienda_ilusion/don_confiao/migrations/0036_merge_20241228_2212.py diff --git a/tienda_ilusion/don_confiao/migrations/0036_merge_20241228_2212.py b/tienda_ilusion/don_confiao/migrations/0036_merge_20241228_2212.py new file mode 100644 index 0000000..a1091c5 --- /dev/null +++ b/tienda_ilusion/don_confiao/migrations/0036_merge_20241228_2212.py @@ -0,0 +1,14 @@ +# Generated by Django 5.0.6 on 2024-12-28 22:12 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('don_confiao', '0034_alter_payment_type_payment_alter_sale_date_and_more'), + ('don_confiao', '0035_reconciliationjar_total_cash_purchases'), + ] + + operations = [ + ]