#69 feat(ReconciliationJar): send reconciliation jar from frontend
This commit is contained in:
parent
f6620db6e2
commit
1b425542b3
@ -1,9 +1,13 @@
|
|||||||
from rest_framework import viewsets
|
from rest_framework import viewsets
|
||||||
from rest_framework.response import Response
|
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 .models import Sale, SaleLine, Customer, Product, ReconciliationJar
|
||||||
from .serializers import SaleSerializer, ProductSerializer, CustomerSerializer
|
from .serializers import SaleSerializer, ProductSerializer, CustomerSerializer, ReconciliationJarSerializer
|
||||||
|
|
||||||
|
from decimal import Decimal
|
||||||
|
import json
|
||||||
|
|
||||||
class SaleView(viewsets.ModelViewSet):
|
class SaleView(viewsets.ModelViewSet):
|
||||||
queryset = Sale.objects.all()
|
queryset = Sale.objects.all()
|
||||||
@ -46,3 +50,30 @@ class ProductView(viewsets.ModelViewSet):
|
|||||||
class CustomerView(viewsets.ModelViewSet):
|
class CustomerView(viewsets.ModelViewSet):
|
||||||
queryset = Customer.objects.all()
|
queryset = Customer.objects.all()
|
||||||
serializer_class = CustomerSerializer
|
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)
|
||||||
|
@ -5,16 +5,17 @@
|
|||||||
</v-toolbar>
|
</v-toolbar>
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
|
<v-form ref="taker" v-model="valid">
|
||||||
|
<v-text-field
|
||||||
|
v-model="reconciliation.date_time"
|
||||||
|
label="Fecha"
|
||||||
|
type="datetime-local"
|
||||||
|
:rules="[rules.required]"
|
||||||
|
required
|
||||||
|
readonly
|
||||||
|
></v-text-field>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="reconciliation.datetime"
|
v-model="reconciliation.reconcilier"
|
||||||
label="Fecha"
|
|
||||||
type="datetime-local"
|
|
||||||
:rules="[rules.required]"
|
|
||||||
required
|
|
||||||
readonly
|
|
||||||
></v-text-field>
|
|
||||||
<v-text-field
|
|
||||||
v-model="reconciliation.cashman"
|
|
||||||
label="Cajero"
|
label="Cajero"
|
||||||
:rules="[rules.required]"
|
:rules="[rules.required]"
|
||||||
required
|
required
|
||||||
@ -41,6 +42,8 @@
|
|||||||
prefix="$"
|
prefix="$"
|
||||||
type="number"
|
type="number"
|
||||||
></v-text-field>
|
></v-text-field>
|
||||||
|
<v-btn @click="submit" color="green">Recoger Dinero</v-btn>
|
||||||
|
</v-form>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
<v-tabs v-model="selectedTab">
|
<v-tabs v-model="selectedTab">
|
||||||
@ -93,10 +96,12 @@
|
|||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
|
valid: null,
|
||||||
selectedPurchaseId: null,
|
selectedPurchaseId: null,
|
||||||
selectedTab: 'CASH',
|
selectedTab: 'CASH',
|
||||||
reconciliation: {
|
reconciliation: {
|
||||||
datetime: '',
|
csrfmiddlewaretoken: null,
|
||||||
|
date_time: '',
|
||||||
total_cash_purchases: 0,
|
total_cash_purchases: 0,
|
||||||
cash_taken: 0,
|
cash_taken: 0,
|
||||||
cash_discrepancy: 0,
|
cash_discrepancy: 0,
|
||||||
@ -104,6 +109,7 @@
|
|||||||
confiar: 0,
|
confiar: 0,
|
||||||
bancolombia: 0
|
bancolombia: 0
|
||||||
},
|
},
|
||||||
|
cash_purchases: [],
|
||||||
},
|
},
|
||||||
summary: {
|
summary: {
|
||||||
headers: [
|
headers: [
|
||||||
@ -122,7 +128,7 @@
|
|||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.fetchPurchases();
|
this.fetchPurchases();
|
||||||
this.reconciliation.datetime = this.getCurrentDate();
|
this.reconciliation.date_time = this.getCurrentDate();
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
'reconciliation.cash_taken'() {
|
'reconciliation.cash_taken'() {
|
||||||
@ -151,18 +157,51 @@
|
|||||||
this.selectedPurchaseId = id;
|
this.selectedPurchaseId = id;
|
||||||
this.$refs.summaryModal.dialog = true;
|
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() {
|
fetchPurchases() {
|
||||||
const endpoint = '/don_confiao/purchases/for_reconciliation';
|
const endpoint = '/don_confiao/purchases/for_reconciliation';
|
||||||
fetch(endpoint)
|
fetch(endpoint)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
this.summary.purchases = 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.reconciliation.total_cash_purchases = this.totalByMethod('CASH');
|
||||||
|
this.getCsrfToken();
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error(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>
|
</script>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from .models import Sale, SaleLine, Product, Customer
|
from .models import Sale, SaleLine, Product, Customer, ReconciliationJar
|
||||||
|
|
||||||
|
|
||||||
class SaleLineSerializer(serializers.ModelSerializer):
|
class SaleLineSerializer(serializers.ModelSerializer):
|
||||||
@ -20,7 +20,21 @@ class ProductSerializer(serializers.ModelSerializer):
|
|||||||
model = Product
|
model = Product
|
||||||
fields = ['id', 'name', 'price', 'measuring_unit', 'categories']
|
fields = ['id', 'name', 'price', 'measuring_unit', 'categories']
|
||||||
|
|
||||||
|
|
||||||
class CustomerSerializer(serializers.ModelSerializer):
|
class CustomerSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Customer
|
model = Customer
|
||||||
fields = ['id', 'name', 'address', 'email', 'phone']
|
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',
|
||||||
|
]
|
||||||
|
@ -138,15 +138,15 @@ class TestJarReconcliation(TestCase):
|
|||||||
self.assertIn('total_cash_purchases', content['error'])
|
self.assertIn('total_cash_purchases', content['error'])
|
||||||
|
|
||||||
def test_create_reconciliation_with_purchases(self):
|
def test_create_reconciliation_with_purchases(self):
|
||||||
url = '/don_confiao/reconciliation_jar/create'
|
url = '/don_confiao/reconciliate_jar'
|
||||||
total_purchases = (11 * 72500) + (27 * 72500)
|
total_purchases = (11 * 72500) + (27 * 72500)
|
||||||
data = {
|
data = {
|
||||||
'date_time': '2024-12-02T21:07',
|
'date_time': '2024-12-02T21:07',
|
||||||
'cashman': 'carlos',
|
'reconcilier': 'carlos',
|
||||||
'total_cash_purchases': total_purchases,
|
'total_cash_purchases': total_purchases,
|
||||||
'cash_taken': total_purchases,
|
'cash_taken': total_purchases,
|
||||||
'cash_discrepancy': 0,
|
'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.purchase.id,
|
||||||
self.purchase2.id,
|
self.purchase2.id,
|
||||||
self.purchase.id,
|
self.purchase.id,
|
||||||
|
@ -28,5 +28,6 @@ urlpatterns = [
|
|||||||
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('purchases/for_reconciliation', views.sales_for_reconciliation, name='sales_for_reconciliation'),
|
||||||
path('reconciliation_jar/create', views.reconciliate_jar, name='reconciliate_jar'),
|
path('reconciliation_jar/create', views.reconciliate_jar, name='reconciliate_jar'),
|
||||||
|
path('reconciliate_jar', api_views.ReconciliateJarView.as_view()),
|
||||||
path('api/', include(router.urls)),
|
path('api/', include(router.urls)),
|
||||||
]
|
]
|
||||||
|
@ -2,6 +2,7 @@ from django.shortcuts import render
|
|||||||
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
|
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
|
||||||
from django.views.generic import ListView
|
from django.views.generic import ListView
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
from django.middleware.csrf import get_token
|
||||||
|
|
||||||
from .models import (
|
from .models import (
|
||||||
Sale, SaleLine, Product, Customer, ProductCategory, Payment, PaymentMethods, ReconciliationJar)
|
Sale, SaleLine, Product, Customer, ProductCategory, Payment, PaymentMethods, ReconciliationJar)
|
||||||
@ -204,7 +205,12 @@ def sales_for_reconciliation(request):
|
|||||||
},
|
},
|
||||||
'total': sale.get_total(),
|
'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):
|
def _mask_phone(phone):
|
||||||
digits = str(phone)[-3:] if phone else " " * 3
|
digits = str(phone)[-3:] if phone else " " * 3
|
||||||
|
Loading…
Reference in New Issue
Block a user