Merge pull request 'Habilitando Resumen de compra' (#63) from enable_summary_purchase_#55 into main
Reviewed-on: OneTeam/don_confiao#63
This commit is contained in:
		| @@ -1,17 +1,103 @@ | ||||
| <template> | ||||
|   <v-app> | ||||
|     <v-navigation-drawer app> | ||||
|     </v-navigation-drawer> | ||||
|     <v-app-bar> | ||||
|       Resumen de la compra | ||||
|     </v-app-bar> | ||||
|     <v-container> | ||||
|       Pon aqui la información de la compra | ||||
|     </v-container> | ||||
|   </v-app> | ||||
| </template> | ||||
| <script> | ||||
|  | ||||
|   <v-container> | ||||
|     <v-container v-show="!id"> | ||||
|       <v-toolbar> | ||||
|         <v-toolbar-title> No se indicó Id de la compra</v-toolbar-title> | ||||
|       </v-toolbar> | ||||
|     </v-container> | ||||
|     <v-container v-show="id"> | ||||
|       <v-toolbar> | ||||
|         <v-toolbar-title> Resumen de la compra {{ id }}</v-toolbar-title> | ||||
|       </v-toolbar> | ||||
|       <v-list> | ||||
|         <v-list-item> | ||||
|           <v-list-item-content> | ||||
|             <v-list-item-title>Fecha:</v-list-item-title> | ||||
|             <v-list-item-subtitle>{{ purchase.date }}</v-list-item-subtitle> | ||||
|           </v-list-item-content> | ||||
|         </v-list-item> | ||||
|         <v-list-item> | ||||
|           <v-list-item-content> | ||||
|             <v-list-item-title>Cliente:</v-list-item-title> | ||||
|             <v-list-item-subtitle v-if="purchase.customer">{{ purchase.customer.name }}</v-list-item-subtitle> | ||||
|           </v-list-item-content> | ||||
|         </v-list-item> | ||||
|         <v-list-item> | ||||
|           <v-list-item-content> | ||||
|             <v-list-item-title>Total:</v-list-item-title> | ||||
|             <v-list-item-subtitle v-if="purchase.set_lines">{{ currencyFormat(calculateTotal(purchase.set_lines)) }}</v-list-item-subtitle> | ||||
|           </v-list-item-content> | ||||
|         </v-list-item> | ||||
|       </v-list> | ||||
|       <v-data-table-virtual | ||||
|         :headers="headers" | ||||
|         :items="purchase.set_lines" | ||||
|       > | ||||
|         <template v-slot:item.unit_price="{ item }"> | ||||
|           {{ currencyFormat(item.unit_price) }} | ||||
|         </template> | ||||
|         <template v-slot:item.subtotal="{ item }"> | ||||
|           {{ currencyFormat(calculateSubtotal(item.price, item.quantity)) }} | ||||
|         </template> | ||||
|       </v-data-table-virtual> | ||||
|     </v-container> | ||||
|   </v-container> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   export default { | ||||
|     name: 'SummaryPurchase', | ||||
|     props: { | ||||
|       msg: String, | ||||
|       id: String | ||||
|     }, | ||||
|     data () { | ||||
|       return { | ||||
|         purchase: {}, | ||||
|         headers: [ | ||||
|           { title: 'Nombre', value: 'product.name' }, | ||||
|           { title: 'Precio', value: 'unit_price' }, | ||||
|           { title: 'Cantidad', value: 'quantity' }, | ||||
|           { title: 'Subtotal', value: 'subtotal' }, | ||||
|         ], | ||||
|       }; | ||||
|     }, | ||||
|     created() { | ||||
|       if (this.id) { | ||||
|         this.fetchPurchase(this.id); | ||||
|       } else { | ||||
|         console.error('No se proporcionó un ID de compra.'); | ||||
|       } | ||||
|     }, | ||||
|     methods: { | ||||
|       fetchPurchase(purchaseId) { | ||||
|         fetch(`/don_confiao/resumen_compra_json/${purchaseId}`) | ||||
|           .then(response => response.json()) | ||||
|           .then(data => { | ||||
|             this.purchase = data; | ||||
|           }) | ||||
|           .catch(error => { | ||||
|             console.error(error); | ||||
|           }); | ||||
|       }, | ||||
|       currencyFormat(value) { | ||||
|         return new Intl.NumberFormat('es-CO', { style: 'currency', currency: 'COP' }).format(value); | ||||
|       }, | ||||
|       calculateSubtotal(price, quantity) { | ||||
|         price = parseFloat(price || 0); | ||||
|         quantity = parseFloat(price || 0); | ||||
|         return price * quantity; | ||||
|       }, | ||||
|       calculateTotal(lines) { | ||||
|         let total = 0; | ||||
|         lines.forEach(line => { | ||||
|           total += this.calculateSubtotal(line.price, line.quantity); | ||||
|         }); | ||||
|         return total; | ||||
|       } | ||||
|     }, | ||||
|   }; | ||||
| </script> | ||||
| <style> | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| <template> | ||||
|   <SummaryPurchase /> | ||||
|   <SummaryPurchase :id="$route.query.id"/> | ||||
| </template> | ||||
| 
 | ||||
| <script setup> | ||||
| @@ -17,16 +17,7 @@ class TestAPI(APITestCase): | ||||
|         ) | ||||
|  | ||||
|     def test_create_sale(self): | ||||
|         url = '/don_confiao/api/sales/' | ||||
|         data = { | ||||
|             'customer': self.customer.id, | ||||
|             'date': '2024-09-02', | ||||
|             'saleline_set': [ | ||||
|                 {'product': self.product.id, 'quantity': 2, 'unit_price': 3000}, | ||||
|                 {'product': self.product.id, 'quantity': 3, 'unit_price': 5000} | ||||
|             ], | ||||
|         } | ||||
|         response = self.client.post(url, data, format='json') | ||||
|         response = self._create_sale() | ||||
|         self.assertEqual(response.status_code, status.HTTP_201_CREATED) | ||||
|         self.assertEqual(Sale.objects.count(), 1) | ||||
|         self.assertEqual( | ||||
| @@ -47,3 +38,15 @@ class TestAPI(APITestCase): | ||||
|         json_response = json.loads(response.content.decode('utf-8')) | ||||
|         self.assertEqual(response.status_code, 200) | ||||
|         self.assertEqual(self.customer.name, json_response[0]['name']) | ||||
|  | ||||
|     def _create_sale(self): | ||||
|         url = '/don_confiao/api/sales/' | ||||
|         data = { | ||||
|             'customer': self.customer.id, | ||||
|             'date': '2024-09-02', | ||||
|             'saleline_set': [ | ||||
|                 {'product': self.product.id, 'quantity': 2, 'unit_price': 3000}, | ||||
|                 {'product': self.product.id, 'quantity': 3, 'unit_price': 5000} | ||||
|             ], | ||||
|         } | ||||
|         return self.client.post(url, data, format='json') | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| from django.test import TestCase, Client | ||||
| from ..models import Sale, Product, SaleLine, Customer | ||||
|  | ||||
|  | ||||
| class TestSummaryViewPurchase(TestCase): | ||||
|     def setUp(self): | ||||
|         customer = Customer() | ||||
| @@ -22,13 +23,29 @@ class TestSummaryViewPurchase(TestCase): | ||||
|         line = SaleLine() | ||||
|         line.sale = purchase | ||||
|         line.product = product | ||||
|         line.quantity = "2" | ||||
|         line.quantity = "11" | ||||
|         line.unit_price = "72500" | ||||
|         line.save() | ||||
|         self.purchase = purchase | ||||
|  | ||||
|     def test_summary_has_customer(self): | ||||
|         response = self.client.get("/don_confiao/resumen_compra/" + str(self.purchase.id)) | ||||
|         url = "/don_confiao/resumen_compra/" + str(self.purchase.id) | ||||
|         response = self.client.get(url) | ||||
|         self.assertEqual(response.status_code, 200) | ||||
|         self.assertEqual(response.context["purchase"].customer, self.purchase.customer) | ||||
|         self.assertEqual( | ||||
|             response.context["purchase"].customer, | ||||
|             self.purchase.customer | ||||
|         ) | ||||
|         self.assertIn('Alejo Mono', response.content.decode('utf-8')) | ||||
|  | ||||
|     def test_json_summary(self): | ||||
|         url = f"/don_confiao/resumen_compra_json/{self.purchase.id}" | ||||
|         response = self.client.get(url) | ||||
|         self.assertEqual(response.status_code, 200) | ||||
|         self.assertIn('Alejo Mono', response.content.decode('utf-8')) | ||||
|         self.assertIn('cafe', response.content.decode('utf-8')) | ||||
|         self.assertIn('72500', response.content.decode('utf-8')) | ||||
|         self.assertIn('quantity', response.content.decode('utf-8')) | ||||
|         self.assertIn('11', response.content.decode('utf-8')) | ||||
|         self.assertIn('date', response.content.decode('utf-8')) | ||||
|         self.assertIn(self.purchase.date, response.content.decode('utf-8')) | ||||
|   | ||||
| @@ -26,5 +26,6 @@ urlpatterns = [ | ||||
|     path("cuadrar_tarro", views.reconciliate_jar, name="reconciliate_jar"), | ||||
|     path("cuadres", views.reconciliate_jar, name="reconciliations"), | ||||
|     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('api/', include(router.urls)), | ||||
| ] | ||||
|   | ||||
| @@ -131,6 +131,7 @@ def reconciliate_jar(request): | ||||
| def reconciliations(request): | ||||
|     return HttpResponse('<h1>Reconciliaciones</h1>') | ||||
|  | ||||
|  | ||||
| def purchase_summary(request, id): | ||||
|     purchase = Sale.objects.get(pk=id) | ||||
|     return render( | ||||
| @@ -142,6 +143,37 @@ def purchase_summary(request, id): | ||||
|     ) | ||||
|  | ||||
|  | ||||
| def purchase_json_summary(request, id): | ||||
|     purchase = Sale.objects.get(pk=id) | ||||
|     lines = [] | ||||
|     for line in purchase.saleline_set.all(): | ||||
|         lines.append({ | ||||
|             'product': { | ||||
|                 'id': line.product.id, | ||||
|                 'name': line.product.name, | ||||
|             }, | ||||
|             'quantity': line.quantity, | ||||
|             'unit_price': line.unit_price, | ||||
|             'description': line.description, | ||||
|         }) | ||||
|     to_response = { | ||||
|         'id': purchase.id, | ||||
|         'date': purchase.date, | ||||
|         'customer': { | ||||
|             'id': purchase.customer.id, | ||||
|             'name': purchase.customer.name, | ||||
|             # 'phone': _mask_phone(purchase.customer.phone) | ||||
|         }, | ||||
|         'set_lines': lines, | ||||
|     } | ||||
|     return JsonResponse(to_response, safe=False) | ||||
|  | ||||
|  | ||||
| def _mask_phone(phone): | ||||
|     digits = str(phone)[-3:] if phone else " " * 3 | ||||
|     return "X" * 7 + digits | ||||
|  | ||||
|  | ||||
| def _categories_from_csv_string(categories_string, separator="&"): | ||||
|     categories = categories_string.split(separator) | ||||
|     clean_categories = [c.strip() for c in categories] | ||||
|   | ||||
		Reference in New Issue
	
	Block a user