#69 feat(ReconciliationJar): send reconciliation jar from frontend

This commit is contained in:
Mono Mono 2024-12-14 19:42:59 -05:00
parent f6620db6e2
commit 1b425542b3
6 changed files with 109 additions and 18 deletions

View File

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

View File

@ -5,8 +5,9 @@
</v-toolbar>
<v-card>
<v-card-text>
<v-form ref="taker" v-model="valid">
<v-text-field
v-model="reconciliation.datetime"
v-model="reconciliation.date_time"
label="Fecha"
type="datetime-local"
:rules="[rules.required]"
@ -14,7 +15,7 @@
readonly
></v-text-field>
<v-text-field
v-model="reconciliation.cashman"
v-model="reconciliation.reconcilier"
label="Cajero"
:rules="[rules.required]"
required
@ -41,6 +42,8 @@
prefix="$"
type="number"
></v-text-field>
<v-btn @click="submit" color="green">Recoger Dinero</v-btn>
</v-form>
</v-card-text>
</v-card>
<v-tabs v-model="selectedTab">
@ -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);
}
}
},
},
}
</script>

View File

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

View File

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

View File

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

View File

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