· 6 months ago · Mar 18, 2025, 04:10 PM
1# Django Core
2from django.shortcuts import render, redirect, get_object_or_404
3from django.http import HttpResponse, JsonResponse, HttpResponseNotAllowed
4from django.core.paginator import Paginator
5from django.db.models import Q
6from django.views.generic import ListView
7from django.views.decorators.csrf import csrf_exempt
8from django.views.decorators.http import require_http_methods
9from django.contrib import messages
10from django.views import View
11from .forms import PagoForm
12from datetime import date, datetime
13from django.utils.timezone import now
14from django.db.models import Exists, OuterRef, Sum
15import json
16
17
18# Autenticación
19from django.contrib.auth import authenticate, login, logout
20from django.contrib.auth.decorators import login_required, user_passes_test
21from .models import Cliente, DireccionInstalacion, Pago
22
23
24# Formularios locales
25from .forms import (
26 ClienteForm,
27 ContratoForm,
28 DireccionFormSet,
29 DireccionForm,
30 ServicioForm
31)
32
33# Modelos locales
34from .models import (
35 Cliente,
36 Contrato,
37 Servicio,
38 Usuario,
39 Rol,
40 Empleado,
41 Zona,
42 DireccionInstalacion # Usa la clase actualizada
43)
44
45# Librerías estándar
46import random
47import json
48import traceback
49
50
51
52def login_view(request):
53 if request.method == "POST":
54 username = request.POST['username']
55 password = request.POST['password']
56 user = authenticate(request, username=username, password=password)
57 if user is not None:
58 login(request, user)
59 return redirect('dashboard') # Redirigir al dashboard si el login es exitoso
60 else:
61 messages.error(request, "Usuario o contraseña incorrectos")
62 return render(request, 'usuarios/login.html')
63
64def logout_view(request):
65 logout(request)
66 return redirect('login') # Redirigir al login después de cerrar sesión
67
68@login_required
69def dashboard(request):
70 return render(request, 'usuarios/dashboard.html')
71
72### CRUD USUARIOS ###
73
74@login_required
75def lista_usuarios(request):
76 usuarios = Usuario.objects.all()
77 roles = Rol.objects.all() # ✅ Asegurar que los roles estén disponibles en la plantilla
78 return render(request, 'usuarios/lista_usuarios.html', {'usuarios': usuarios, 'roles': roles})
79
80@login_required
81def editar_usuario(request, user_id):
82 usuario = get_object_or_404(Usuario, id=user_id)
83
84 if request.method == 'POST':
85 usuario.username = request.POST['username']
86 usuario.first_name = request.POST['first_name']
87 usuario.last_name = request.POST['last_name']
88 usuario.email = request.POST['email']
89 usuario.rol_id = request.POST.get('rol')
90 usuario.estatus = 'estatus' in request.POST # Checkbox activo/inactivo
91 usuario.save()
92 messages.success(request, "Usuario actualizado correctamente.")
93 return redirect('lista_usuarios')
94
95 roles = Rol.objects.all()
96 return render(request, 'usuarios/editar_usuario.html', {'usuario': usuario, 'roles': roles})
97
98@login_required
99def eliminar_usuario(request, user_id):
100 usuario = get_object_or_404(Usuario, id=user_id)
101 usuario.delete()
102 messages.success(request, "Usuario eliminado correctamente.")
103 return redirect('lista_usuarios')
104
105@login_required
106def crear_usuario(request):
107 if request.method == "POST":
108 username = request.POST.get('username').strip()
109 first_name = request.POST.get('first_name').strip()
110 last_name = request.POST.get('last_name').strip()
111 email = request.POST.get('email').strip()
112 password = request.POST.get('password')
113 rol_id = request.POST.get('rol')
114
115 # Validar que no haya campos vacíos
116 if not username or not first_name or not last_name or not email or not password or not rol_id:
117 messages.error(request, "Todos los campos son obligatorios.")
118 return redirect('lista_usuarios')
119
120 # Validar si el usuario ya existe
121 if Usuario.objects.filter(username=username).exists():
122 messages.error(request, "El nombre de usuario ya está en uso.")
123 return redirect('lista_usuarios')
124
125 # Verificar si el rol existe en la base de datos
126 try:
127 rol = Rol.objects.get(id=rol_id)
128 except Rol.DoesNotExist:
129 messages.error(request, "El rol seleccionado no es válido.")
130 return redirect('lista_usuarios')
131
132 # Crear usuario y cifrar la contraseña
133 nuevo_usuario = Usuario(
134 username=username,
135 first_name=first_name,
136 last_name=last_name,
137 email=email,
138 rol=rol
139 )
140 nuevo_usuario.set_password(password) # 🔐 Cifra la contraseña
141 nuevo_usuario.save()
142
143 messages.success(request, f"Usuario '{username}' creado correctamente.")
144 return redirect('lista_usuarios')
145
146 # Si el método no es POST, regresar la lista de usuarios
147 usuarios = Usuario.objects.all()
148 roles = Rol.objects.all()
149 return render(request, 'usuarios/lista_usuarios.html', {'usuarios': usuarios, 'roles': roles})
150
151
152### CRUD EMPLEADOS ###
153
154@login_required
155def lista_empleados(request):
156 empleados = Empleado.objects.all()
157 return render(request, 'usuarios/lista_empleados.html', {'empleados': empleados})
158
159@login_required
160def crear_empleado(request):
161 if request.method == "POST":
162 nombre = request.POST['nombre']
163 apellido = request.POST['apellido']
164 dni = request.POST['dni']
165 rol_id = request.POST.get('rol')
166 rol = Rol.objects.get(id=rol_id)
167
168 Empleado.objects.create(nombre=nombre, apellido=apellido, dni=dni, rol=rol)
169 messages.success(request, "Empleado agregado correctamente.")
170 return redirect('lista_empleados')
171
172 roles = Rol.objects.all()
173 return render(request, 'usuarios/crear_empleado.html', {'roles': roles})
174
175@login_required
176def editar_empleado(request, emp_id):
177 empleado = get_object_or_404(Empleado, id=emp_id)
178
179 if request.method == "POST":
180 empleado.nombre = request.POST['nombre']
181 empleado.apellido = request.POST['apellido']
182 empleado.dni = request.POST['dni']
183 empleado.rol_id = request.POST.get('rol')
184 empleado.save()
185 messages.success(request, "Empleado actualizado correctamente.")
186 return redirect('lista_empleados')
187
188 roles = Rol.objects.all()
189 return render(request, 'usuarios/editar_empleado.html', {'empleado': empleado, 'roles': roles})
190
191@login_required
192def eliminar_empleado(request, emp_id):
193 empleado = get_object_or_404(Empleado, id=emp_id)
194 empleado.delete()
195 messages.success(request, "Empleado eliminado correctamente.")
196 return redirect('lista_empleados')
197
198### CRUD ROLES ###
199
200@login_required
201def lista_roles(request):
202 roles = Rol.objects.all()
203 return render(request, 'usuarios/lista_roles.html', {'roles': roles})
204
205@login_required
206def crear_rol(request):
207 if request.method == "POST":
208 nombre = request.POST['nombre']
209 Rol.objects.create(nombre=nombre)
210 messages.success(request, "Rol creado correctamente.")
211 return redirect('lista_roles')
212
213 return render(request, 'usuarios/crear_rol.html')
214
215@login_required
216def editar_rol(request, rol_id):
217 rol = get_object_or_404(Rol, id=rol_id)
218
219 if request.method == "POST":
220 rol.nombre = request.POST['nombre']
221 rol.save()
222 messages.success(request, "Rol actualizado correctamente.")
223 return redirect('lista_roles')
224
225 return render(request, 'usuarios/editar_rol.html', {'rol': rol})
226
227@login_required
228def eliminar_rol(request, rol_id):
229 rol = get_object_or_404(Rol, id=rol_id)
230 rol.delete()
231 messages.success(request, "Rol eliminado correctamente.")
232 return redirect('lista_roles')
233
234
235@login_required
236def editar_usuario(request, user_id):
237 usuario = get_object_or_404(Usuario, id=user_id)
238
239 if request.method == "POST":
240 usuario.username = request.POST.get('username').strip()
241 usuario.first_name = request.POST.get('first_name').strip()
242 usuario.last_name = request.POST.get('last_name').strip()
243 usuario.email = request.POST.get('email').strip()
244 rol_id = request.POST.get('rol')
245 usuario.estatus = 'estatus' in request.POST # Checkbox para activar/desactivar usuario
246
247 # Validar si el usuario ya existe con otro ID
248 if Usuario.objects.exclude(id=user_id).filter(username=usuario.username).exists():
249 messages.error(request, "El nombre de usuario ya está en uso por otro usuario.")
250 return redirect('lista_usuarios')
251
252 # Verificar si el rol existe
253 try:
254 usuario.rol = Rol.objects.get(id=rol_id)
255 except Rol.DoesNotExist:
256 messages.error(request, "El rol seleccionado no es válido.")
257 return redirect('lista_usuarios')
258
259 usuario.save()
260 messages.success(request, f"Usuario '{usuario.username}' actualizado correctamente.")
261 return redirect('lista_usuarios')
262
263 roles = Rol.objects.all()
264 return render(request, 'usuarios/editar_usuario.html', {'usuario': usuario, 'roles': roles})
265
266
267@login_required
268def eliminar_usuario(request, user_id):
269 usuario = get_object_or_404(Usuario, id=user_id)
270 usuario.delete()
271 messages.success(request, f"Usuario '{usuario.username}' eliminado correctamente.")
272 return redirect('lista_usuarios')
273
274
275# Función para verificar si el usuario es administrador
276def es_admin(user):
277 return user.is_authenticated and user.is_superuser
278
279### RESTRINGIR VISTAS A ADMINISTRADORES ###
280
281@login_required
282@user_passes_test(es_admin, login_url='/dashboard/') # Redirigir si no es admin
283def lista_usuarios(request):
284 usuarios = Usuario.objects.all()
285 roles = Rol.objects.all()
286 return render(request, 'usuarios/lista_usuarios.html', {'usuarios': usuarios, 'roles': roles})
287
288@login_required
289@user_passes_test(es_admin, login_url='/dashboard/')
290def crear_usuario(request):
291 if request.method == "POST":
292 username = request.POST.get('username').strip()
293 first_name = request.POST.get('first_name').strip()
294 last_name = request.POST.get('last_name').strip()
295 email = request.POST.get('email').strip()
296 password = request.POST.get('password')
297 rol_id = request.POST.get('rol')
298
299 if Usuario.objects.filter(username=username).exists():
300 messages.error(request, "El nombre de usuario ya está en uso.")
301 return redirect('lista_usuarios')
302
303 try:
304 rol = Rol.objects.get(id=rol_id)
305 except Rol.DoesNotExist:
306 messages.error(request, "El rol seleccionado no es válido.")
307 return redirect('lista_usuarios')
308
309 nuevo_usuario = Usuario(
310 username=username,
311 first_name=first_name,
312 last_name=last_name,
313 email=email,
314 rol=rol
315 )
316 nuevo_usuario.set_password(password)
317 nuevo_usuario.save()
318
319 messages.success(request, f"Usuario '{username}' creado correctamente.")
320 return redirect('lista_usuarios')
321
322 return redirect('lista_usuarios')
323
324@login_required
325@user_passes_test(es_admin, login_url='/dashboard/')
326def eliminar_usuario(request, user_id):
327 usuario = get_object_or_404(Usuario, id=user_id)
328 usuario.delete()
329 messages.success(request, f"Usuario '{usuario.username}' eliminado correctamente.")
330 return redirect('lista_usuarios')
331
332@login_required
333@user_passes_test(es_admin, login_url='/dashboard/')
334def lista_roles(request):
335 roles = Rol.objects.all()
336 return render(request, 'usuarios/lista_roles.html', {'roles': roles})
337
338@login_required
339@user_passes_test(es_admin, login_url='/dashboard/')
340def crear_rol(request):
341 if request.method == "POST":
342 nombre = request.POST['nombre']
343 Rol.objects.create(nombre=nombre)
344 messages.success(request, "Rol creado correctamente.")
345 return redirect('lista_roles')
346
347 return render(request, 'usuarios/crear_rol.html')
348
349@login_required
350@user_passes_test(es_admin, login_url='/dashboard/')
351def eliminar_rol(request, rol_id):
352 rol = get_object_or_404(Rol, id=rol_id)
353 rol.delete()
354 messages.success(request, "Rol eliminado correctamente.")
355 return redirect('lista_roles')
356
357
358def lista_zonas(request):
359 zonas = Zona.objects.all()
360 return render(request, "usuarios/lista_zonas.html", {"zonas": zonas})
361
362def crear_zona(request):
363 if request.method == "POST":
364 nombre = request.POST["nombre"]
365 Zona.objects.create(nombre=nombre)
366 messages.success(request, "Zona creada correctamente.")
367 return redirect("lista_zonas")
368 return redirect("lista_zonas")
369
370def editar_zona(request, zona_id):
371 zona = get_object_or_404(Zona, id=zona_id)
372 if request.method == "POST":
373 zona.nombre = request.POST["nombre"]
374 zona.save()
375 messages.success(request, "Zona actualizada correctamente.")
376 return redirect("lista_zonas")
377 return redirect("lista_zonas")
378
379def eliminar_zona(request, zona_id):
380 zona = get_object_or_404(Zona, id=zona_id)
381 zona.delete()
382 messages.success(request, "Zona eliminada correctamente.")
383 return redirect("lista_zonas")
384
385
386def get_zonas(request):
387 zonas = list(Zona.objects.values('id', 'nombre'))
388 return JsonResponse({'zonas': zonas})
389
390
391
392# Lista todos los clientes
393class ClienteListView(ListView):
394 model = Cliente
395 template_name = 'usuarios/cliente_list.html'
396 context_object_name = 'clientes'
397 paginate_by = 10 # Muestra de 10 en 10
398
399 def get_queryset(self):
400 queryset = super().get_queryset()
401 buscar = self.request.GET.get('buscar', '')
402 if buscar:
403 queryset = queryset.filter(
404 Q(nombre__icontains=buscar) |
405 Q(apellido_paterno__icontains=buscar) |
406 Q(apellido_materno__icontains=buscar) |
407 Q(numero_documento__icontains=buscar)
408 )
409 return queryset.order_by('nombre')
410
411 def get_context_data(self, **kwargs):
412 context = super().get_context_data(**kwargs)
413 context['buscar'] = self.request.GET.get('buscar', '')
414 return context
415
416# Crea un nuevo cliente con múltiples direcciones
417def crear_cliente(request):
418 if request.method == 'POST':
419 form = ClienteForm(request.POST)
420 formset = DireccionFormSet(request.POST)
421 if form.is_valid() and formset.is_valid():
422 cliente = form.save()
423 direcciones = formset.save(commit=False)
424 for direccion in direcciones:
425 direccion.cliente = cliente
426 direccion.save()
427 return redirect('cliente_list')
428 else:
429 form = ClienteForm()
430 formset = DireccionFormSet()
431
432 return render(request, 'usuarios/cliente_form.html', {
433 'form': form,
434 'formset': formset,
435 })
436
437
438def editar_cliente(request, pk):
439 cliente = get_object_or_404(Cliente, pk=pk)
440
441 if request.method == "POST":
442 form = ClienteForm(request.POST, instance=cliente)
443 formset = DireccionFormSet(request.POST, instance=cliente)
444
445 if form.is_valid() and formset.is_valid():
446 form.save()
447 formset.save()
448 print("✅ Cliente guardado correctamente")
449 return redirect('cliente_list')
450
451 else:
452 print("❌ Error en el formulario:")
453 print(form.errors)
454 print(formset.errors)
455
456 else:
457 form = ClienteForm(instance=cliente)
458 formset = DireccionFormSet(instance=cliente)
459
460 return render(request, 'usuarios/cliente_form.html', {'form': form, 'formset': formset})
461
462
463
464
465
466def obtener_direcciones_cliente(request, cliente_id):
467 try:
468 cliente = Cliente.objects.get(id=cliente_id)
469 data = {'direccion': cliente.direccion} # Asegúrate de que 'direccion' sea el campo correcto
470 except Cliente.DoesNotExist:
471 data = {'direccion': ''} # Si el cliente no existe, devuelve una dirección vacía
472 return JsonResponse(data)
473
474
475def crear_contrato(request):
476 if request.method == 'POST':
477 cliente_id = request.POST.get('cliente')
478 form = ContratoForm(request.POST, cliente_id=cliente_id)
479 if form.is_valid():
480 contrato = form.save(commit=False)
481 contrato.total = sum(servicio.precio for servicio in form.cleaned_data['servicios'])
482 contrato.save()
483 form.save_m2m()
484 messages.success(request, "Contrato creado exitosamente.")
485 return redirect('lista_contratos')
486 else:
487 form = ContratoForm()
488
489 return render(request, 'usuarios/contrato_form.html', {'form': form})
490
491
492
493# Editar un contrato existente
494def editar_contrato(request, pk):
495 contrato = get_object_or_404(Contrato, pk=pk)
496 if request.method == 'POST':
497 cliente_id = contrato.cliente.id
498 form = ContratoForm(request.POST, instance=contrato, cliente_id=cliente_id)
499 if form.is_valid():
500 contrato = form.save(commit=False)
501 contrato.total = sum(servicio.precio for servicio in form.cleaned_data['servicios'])
502 contrato.save()
503 form.save_m2m()
504 messages.success(request, "Contrato actualizado correctamente.")
505 return redirect('lista_contratos')
506 else:
507 form = ContratoForm(instance=contrato, cliente_id=contrato.cliente.id)
508
509 return render(request, 'usuarios/contrato_form.html', {'form': form})
510
511def lista_contratos(request):
512 contratos_list = Contrato.objects.all().order_by('-fecha_contratacion') # Ordenar por fecha
513 paginator = Paginator(contratos_list, 5) # 5 contratos por página
514
515 page_number = request.GET.get('page')
516 contratos = paginator.get_page(page_number)
517
518 return render(request, 'usuarios/lista_contratos.html', {'contratos': contratos})
519
520
521def eliminar_contrato(request, pk):
522 contrato = get_object_or_404(Contrato, pk=pk)
523 contrato.delete()
524 messages.success(request, "Contrato eliminado correctamente.")
525 return redirect('lista_contratos') # Asegúrate de que esta vista existe en `urls.py`
526
527
528
529def lista_servicios(request):
530 servicios = Servicio.objects.all()
531 return render(request, 'usuarios/lista_servicios.html', {'servicios': servicios})
532
533def agregar_servicio(request):
534 if request.method == 'POST':
535 form = ServicioForm(request.POST)
536 if form.is_valid():
537 form.save()
538 return redirect('servicios')
539 else:
540 form = ServicioForm()
541 return render(request, 'usuarios/agregar_servicio.html', {'form': form})
542
543def editar_servicio(request, servicio_id):
544 servicio = get_object_or_404(Servicio, pk=servicio_id)
545 if request.method == 'POST':
546 form = ServicioForm(request.POST, instance=servicio)
547 if form.is_valid():
548 form.save()
549 return redirect('servicios')
550 else:
551 form = ServicioForm(instance=servicio)
552 return render(request, 'usuarios/editar_servicio.html', {'form': form, 'servicio': servicio})
553
554
555def eliminar_servicio(request, servicio_id):
556 servicio = get_object_or_404(Servicio, pk=servicio_id)
557 try:
558 servicio.delete()
559 messages.success(request, "Servicio eliminado correctamente.")
560 except Exception as e:
561 messages.error(request, f"No se pudo eliminar el servicio: {e}")
562
563 return redirect('servicios')
564# API para obtener la lista de clientes
565def api_clientes(request):
566 clientes = Cliente.objects.all().values("id", "numero_documento", "nombre")
567 return JsonResponse(list(clientes), safe=False)
568
569# API para obtener direcciones del cliente seleccionado
570def api_direcciones_cliente(request, cliente_id):
571 direcciones = DireccionInstalacion.objects.filter(cliente_id=cliente_id).values("id", "direccion", "zona__nombre")
572 return JsonResponse(list(direcciones), safe=False)
573
574
575def buscar_cliente(request):
576 query = request.GET.get('query', '')
577
578 if query:
579 clientes = Cliente.objects.filter(
580 Q(nombre__icontains=query) | Q(numero_documento__icontains=query)
581 ).prefetch_related('contrato_set')
582
583 data = []
584 for cliente in clientes:
585 contrato = cliente.contrato_set.first() # Obtener el primer contrato si existe
586 servicios = contrato.servicios.all() if contrato else []
587 servicio_nombres = ", ".join([s.nombre for s in servicios]) if servicios else "Sin servicio"
588
589 data.append({
590 'id': cliente.id,
591 'nombre': cliente.nombre,
592 'direccion': contrato.direccion_instalacion.direccion if contrato and contrato.direccion_instalacion else "No registrada",
593 'telefono': cliente.telefono if cliente.telefono else "No registrado",
594 'servicio': servicio_nombres
595 })
596
597 return JsonResponse(data, safe=False)
598
599 return JsonResponse({'error': 'No se encontraron clientes'}, status=404)
600
601def pago_servicios(request):
602 return render(request, 'usuarios/pago_servicios.html')
603
604
605
606
607class RegistrarPagoView(View):
608 def get(self, request, cliente_id):
609 cliente = get_object_or_404(Cliente, id=cliente_id)
610 contratos = Contrato.objects.filter(cliente=cliente)
611
612 # ✅ Verificar si el cliente tiene contratos antes de continuar
613 if not contratos.exists():
614 messages.error(request, f"El cliente {cliente.nombre} no tiene contratos asociados.")
615 return redirect('lista_pagos') # Redirige a la lista de pagos
616
617 form = PagoForm(cliente_id=cliente.id)
618 pagos_realizados = Pago.objects.filter(cliente=cliente).values_list('mes_pagado', flat=True)
619
620 # ✅ Crear estructura para mostrar estado de pagos en los meses del año
621 MESES_CHOICES = [
622 (1, "Enero"), (2, "Febrero"), (3, "Marzo"), (4, "Abril"),
623 (5, "Mayo"), (6, "Junio"), (7, "Julio"), (8, "Agosto"),
624 (9, "Septiembre"), (10, "Octubre"), (11, "Noviembre"), (12, "Diciembre")
625 ]
626
627 estado_pagos = [
628 {
629 "mes": nombre_mes,
630 "pagado": mes in pagos_realizados
631 }
632 for mes, nombre_mes in MESES_CHOICES
633 ]
634
635 return render(request, 'usuarios/registrar_pago.html', {
636 'cliente': cliente,
637 'contratos': contratos,
638 'form': form,
639 'pagos_realizados': pagos_realizados,
640 'estado_pagos': estado_pagos, # 👈 Enviamos la estructura de pagos al template
641 })
642
643 def post(self, request, cliente_id):
644 print("🔴 Datos recibidos en POST:", request.POST) # 👈 Imprime los datos enviados en la solicitud
645
646 cliente = get_object_or_404(Cliente, id=cliente_id)
647 contratos = Contrato.objects.filter(cliente=cliente)
648
649 # ✅ Verificar si el cliente tiene contratos antes de continuar
650 if not contratos.exists():
651 messages.error(request, f"El cliente {cliente.nombre} no tiene contratos asociados.")
652 return redirect('lista_pagos')
653
654 form = PagoForm(request.POST, cliente_id=cliente.id)
655
656 if form.is_valid():
657 pago = form.save(commit=False)
658 pago.cliente = cliente
659
660 # ✅ Asegurar que el contrato es válido antes de continuar
661 contrato_seleccionado = form.cleaned_data.get('contrato')
662 if contrato_seleccionado:
663 pago.monto = contrato_seleccionado.total # Usa el total del contrato
664 else:
665 messages.error(request, "Debe seleccionar un contrato válido.")
666 return self._recargar_pagina(request, cliente, contratos, form)
667
668 pago.save()
669 form.save_m2m()
670
671 # ✅ Agregar mensaje de éxito
672 messages.success(request, f'Pago registrado con éxito para {cliente.nombre} {cliente.apellido_paterno}.')
673
674 # ✅ Redirigir al historial de pagos
675 return redirect('historial_pagos', cliente_id=cliente.id)
676
677 # ❌ Si hay un error, mostrar el mensaje y recargar el formulario
678 print("⚠️ Errores en el formulario:", form.errors) # 👈 Imprime errores del formulario en consola
679 messages.error(request, "Hubo un error al registrar el pago. Revisa los datos ingresados.")
680 return self._recargar_pagina(request, cliente, contratos, form)
681
682def _recargar_pagina(self, request, cliente, contratos, form):
683 """ Función auxiliar para recargar la página con los datos actuales """
684 pagos_realizados = Pago.objects.filter(cliente=cliente).values_list('mes_pagado', flat=True)
685
686 MESES_CHOICES = [
687 (1, "Enero"), (2, "Febrero"), (3, "Marzo"), (4, "Abril"),
688 (5, "Mayo"), (6, "Junio"), (7, "Julio"), (8, "Agosto"),
689 (9, "Septiembre"), (10, "Octubre"), (11, "Noviembre"), (12, "Diciembre")
690 ]
691
692 estado_pagos = [
693 {
694 "mes": nombre_mes,
695 "pagado": mes in pagos_realizados
696 }
697 for mes, nombre_mes in MESES_CHOICES
698 ]
699
700 return render(request, 'usuarios/registrar_pago.html', {
701 'cliente': cliente,
702 'contratos': contratos,
703 'form': form,
704 'pagos_realizados': pagos_realizados,
705 'estado_pagos': estado_pagos, # 👈 Enviamos la estructura de pagos al template
706 })
707
708
709
710class HistorialPagosView(View):
711 template_name = 'usuarios/historial_pagos.html'
712
713 def get(self, request, cliente_id): # ✅ Ahora correctamente indentado
714 cliente = get_object_or_404(Cliente, id=cliente_id)
715 pagos = Pago.objects.filter(cliente=cliente).order_by('-fecha_pago')
716 return render(request, self.template_name, {'cliente': cliente, 'pagos': pagos})
717
718class DetalleClienteView(View):
719 template_name = 'usuarios/detalle_cliente.html'
720
721 def get(self, request, cliente_id):
722 cliente = get_object_or_404(Cliente, id=cliente_id)
723 return render(request, self.template_name, {'cliente': cliente})
724
725
726
727class BuscarClientePagoView(View):
728 template_name = 'usuarios/buscar_cliente_pago.html'
729
730 def get(self, request):
731 buscar = request.GET.get('buscar', '')
732 clientes = Cliente.objects.all()
733
734 if buscar:
735 clientes = clientes.filter(nombre__icontains=buscar)
736
737 # Verificar si el cliente ya pagó en el mes y año actual
738 mes_actual = now().month
739 anio_actual = now().year
740
741 clientes = clientes.annotate(
742 ha_pagado=Exists(
743 Pago.objects.filter(
744 cliente=OuterRef('pk'),
745 mes_pagado=mes_actual,
746 anio_pagado=anio_actual
747 )
748 )
749 )
750
751 return render(request, self.template_name, {
752 'clientes': clientes,
753 'buscar': buscar
754 })
755
756
757class HistorialPagosGeneralView(ListView):
758 model = Pago
759 template_name = "usuarios/historial_pagos_general.html"
760 context_object_name = "pagos"
761 paginate_by = 10 # Agregar paginación
762
763 def get_queryset(self):
764 queryset = Pago.objects.all().order_by('-fecha_pago')
765 buscar = self.request.GET.get("buscar")
766 if buscar:
767 queryset = queryset.filter(contrato__cliente__nombre__icontains=buscar)
768 return queryset
769
770def lista_contratos_pago(request):
771 contratos = Contrato.objects.all()
772 return render(request, 'usuarios/lista_pagos.html', {'contratos': contratos})
773
774
775class HistorialPagosClienteView(View):
776 def get(self, request, cliente_id):
777 cliente = get_object_or_404(Cliente, id=cliente_id)
778 pagos = Pago.objects.filter(cliente_id=cliente_id).order_by('-fecha_pago')
779
780 return render(request, 'usuarios/historial_pagos_cliente.html', {
781 'cliente': cliente,
782 'pagos': pagos
783 })
784
785
786class DashboardView(View):
787 def get(self, request):
788 total_clientes = Cliente.objects.count()
789 total_contratos = Contrato.objects.count()
790 total_pagos = Pago.objects.count()
791 total_ingresos = Pago.objects.aggregate(total=Sum('monto'))['total'] or 0
792
793 # 📊 Datos para el gráfico de ingresos por mes
794 ingresos_por_mes = Pago.objects.values('mes_pagado').annotate(total=Sum('monto')).order_by('mes_pagado')
795 ingresos_dict = {mes['mes_pagado']: mes['total'] for mes in ingresos_por_mes}
796
797 meses = [
798 "Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio",
799 "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"
800 ]
801 ingresos_data = [ingresos_dict.get(i, 0) for i in range(1, 13)]
802
803 print("📊 JSON de Meses:", json.dumps(meses, ensure_ascii=False))
804 print("📊 JSON de Ingresos:", json.dumps(ingresos_data, ensure_ascii=False))
805
806 return render(request, 'dashboard.html', {
807 'total_clientes': total_clientes,
808 'total_contratos': total_contratos,
809 'total_pagos': total_pagos,
810 'total_ingresos': total_ingresos,
811 'meses_json': json.dumps(meses, ensure_ascii=False),
812 'ingresos_data_json': json.dumps(ingresos_data, ensure_ascii=False)
813 })