views.py 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. from django.shortcuts import render, redirect, get_object_or_404
  2. from decimal import Decimal, InvalidOperation
  3. import logging
  4. import re
  5. from django.db import models as db_models
  6. from accounts import models
  7. from .models import Movimiento, Cuenta, MovimientoFrecuente
  8. from .forms import MovimientoForm, FiltroForm, CuentaForm
  9. from django.contrib.auth.decorators import login_required
  10. from django.contrib import messages
  11. from django.utils.timezone import now
  12. logger = logging.getLogger(__name__)
  13. @login_required
  14. def dashboard(request):
  15. movimientos = Movimiento.objects.filter(usuario=request.user).order_by('-fecha')
  16. favoritas = Cuenta.objects.filter(favorita='True')
  17. frecuentes = MovimientoFrecuente.objects.filter(usuario=request.user)
  18. form = FiltroForm(request.GET or None)
  19. if form.is_valid():
  20. # if form.cleaned_data['fecha_inicio']:
  21. # movimientos = movimientos.filter(fecha__gte=form.cleaned_data['fecha_inicio'])
  22. # if form.cleaned_data['fecha_fin']:
  23. # movimientos = movimientos.filter(fecha__lte=form.cleaned_data['fecha_fin'])
  24. # if form.cleaned_data['cuenta']:
  25. # cuenta = form.cleaned_data['cuenta']
  26. # movimientos = movimientos.filter(models.Q(cuenta_origen=cuenta) | models.Q(cuenta_destino=cuenta))
  27. busqueda = form.cleaned_data.get('buscar')
  28. if busqueda:
  29. movimientos = movimientos.filter(
  30. db_models.Q(descripcion__icontains=busqueda) |
  31. db_models.Q(cuenta_origen__nombre__icontains=busqueda) |
  32. db_models.Q(cuenta_destino__nombre__icontains=busqueda)
  33. )
  34. logger.warning(f"Frecuentes: {frecuentes}")
  35. logger.warning(f"Monto: {frecuentes[0].monto}")
  36. # Aplicar filtros si se han proporcionado
  37. return render(request, 'dashboard.html', {
  38. 'movimientos': movimientos,
  39. 'user': request.user,
  40. 'form': form,
  41. 'favoritas': favoritas,
  42. 'frecuentes': frecuentes,
  43. })
  44. # Movimientos
  45. @login_required
  46. def agregar_movimiento(request):
  47. if request.method == 'POST':
  48. form = MovimientoForm(request.POST)
  49. form.fields['cuenta_origen'].queryset = Cuenta.objects.filter(usuario=request.user)
  50. form.fields['cuenta_destino'].queryset = Cuenta.objects.filter(usuario=request.user)
  51. if form.is_valid():
  52. movimiento = form.save(commit=False)
  53. movimiento.usuario = request.user
  54. movimiento.save()
  55. # Ajustar saldos de cuentas
  56. movimiento.cuenta_origen.saldo -= movimiento.monto
  57. movimiento.cuenta_origen.save()
  58. movimiento.cuenta_destino.saldo += movimiento.monto
  59. movimiento.cuenta_destino.save()
  60. messages.success(request, 'Movimiento registrado con éxito.')
  61. return redirect('dashboard')
  62. else:
  63. datos_iniciales = {}
  64. origen = request.GET.get('origen')
  65. destino = request.GET.get('destino')
  66. monto_raw = request.GET.get('monto')
  67. try:
  68. if origen:
  69. datos_iniciales['cuenta_origen'] = Cuenta.objects.get(nombre=request.GET['origen'], usuario=request.user)
  70. if destino:
  71. datos_iniciales['cuenta_destino'] = Cuenta.objects.get(nombre=request.GET['destino'], usuario=request.user)
  72. if monto_raw:
  73. # Reemplaza coma por punto, elimina símbolos y espacios
  74. monto_normalizado = re.sub(r'[^\d,.-]', '', monto_raw).replace(',', '.')
  75. try:
  76. datos_iniciales['monto'] = str(Decimal(monto_normalizado).quantize(Decimal('0.01')))
  77. except InvalidOperation:
  78. pass # Ignorar monto malformado
  79. logger.warning(f"monto: {datos_iniciales['monto']}")
  80. except (Cuenta.DoesNotExist, InvalidOperation):
  81. pass
  82. logger.warning(f"datos iniciales: {datos_iniciales}")
  83. form = MovimientoForm(initial=datos_iniciales)
  84. form.fields['cuenta_origen'].queryset = Cuenta.objects.filter(usuario=request.user)
  85. form.fields['cuenta_destino'].queryset = Cuenta.objects.filter(usuario=request.user)
  86. return render(request, 'agregar_movimiento.html', {'form': form})
  87. @login_required
  88. def editar_movimiento(request, movimiento_id):
  89. movimiento = get_object_or_404(Movimiento, id=movimiento_id, usuario=request.user)
  90. saldo_original_origen = movimiento.cuenta_origen
  91. saldo_original_destino = movimiento.cuenta_destino
  92. monto_original = movimiento.monto
  93. if request.method == 'POST':
  94. form = MovimientoForm(request.POST, instance=movimiento)
  95. form.fields['cuenta_origen'].queryset = Cuenta.objects.filter(usuario=request.user)
  96. form.fields['cuenta_destino'].queryset = Cuenta.objects.filter(usuario=request.user)
  97. if form.is_valid():
  98. movimiento_nuevo = form.save(commit=False)
  99. # Revertir efecto anterior
  100. saldo_original_origen.saldo += monto_original
  101. saldo_original_origen.save()
  102. saldo_original_destino.saldo -= monto_original
  103. saldo_original_destino.save()
  104. # Aplicar nuevo efecto
  105. movimiento_nuevo.usuario = request.user
  106. movimiento_nuevo.save()
  107. movimiento_nuevo.cuenta_origen.saldo -= movimiento_nuevo.monto
  108. movimiento_nuevo.cuenta_origen.save()
  109. movimiento_nuevo.cuenta_destino.saldo += movimiento_nuevo.monto
  110. movimiento_nuevo.cuenta_destino.save()
  111. return redirect('dashboard')
  112. else:
  113. form = MovimientoForm(instance=movimiento)
  114. form.fields['cuenta_origen'].queryset = Cuenta.objects.filter(usuario=request.user)
  115. form.fields['cuenta_destino'].queryset = Cuenta.objects.filter(usuario=request.user)
  116. return render(request, 'editar_movimiento.html', {'form': form})
  117. @login_required
  118. def eliminar_movimiento(request, movimiento_id):
  119. movimiento = get_object_or_404(Movimiento, id=movimiento_id, usuario=request.user)
  120. if request.method == 'POST':
  121. # Revertir efecto del movimiento antes de borrarlo
  122. movimiento.cuenta_origen.saldo += movimiento.monto
  123. movimiento.cuenta_origen.save()
  124. movimiento.cuenta_destino.saldo -= movimiento.monto
  125. movimiento.cuenta_destino.save()
  126. movimiento.delete()
  127. return redirect('dashboard')
  128. return render(request, 'eliminar_movimiento.html', {'movimiento': movimiento})
  129. @login_required
  130. def duplicar_movimiento(request, movimiento_id):
  131. original = get_object_or_404(Movimiento, id=movimiento_id, usuario=request.user)
  132. # Crear una copia del movimiento sin guardar
  133. movimiento_nuevo = Movimiento(
  134. cuenta_origen=original.cuenta_origen,
  135. cuenta_destino=original.cuenta_destino,
  136. monto=original.monto,
  137. fecha=now(),
  138. descripcion=original.descripcion,
  139. usuario=request.user,
  140. )
  141. if request.method == 'POST':
  142. form = MovimientoForm(request.POST, instance=movimiento_nuevo)
  143. form.fields['cuenta_origen'].queryset = Cuenta.objects.filter(usuario=request.user)
  144. form.fields['cuenta_destino'].queryset = Cuenta.objects.filter(usuario=request.user)
  145. if form.is_valid():
  146. nuevo = form.save(commit=False)
  147. nuevo.usuario = request.user
  148. nuevo.save()
  149. # Ajustar saldos
  150. nuevo.cuenta_origen.saldo -= nuevo.monto
  151. nuevo.cuenta_origen.save()
  152. nuevo.cuenta_destino.saldo += nuevo.monto
  153. nuevo.cuenta_destino.save()
  154. messages.success(request, 'Movimiento duplicado con éxito.')
  155. return redirect('dashboard')
  156. else:
  157. form = MovimientoForm(instance=movimiento_nuevo)
  158. form.fields['cuenta_origen'].queryset = Cuenta.objects.filter(usuario=request.user)
  159. form.fields['cuenta_destino'].queryset = Cuenta.objects.filter(usuario=request.user)
  160. return render(request, 'duplicar_movimiento.html', {'form': form})
  161. # Cuentas
  162. @login_required
  163. def agregar_cuenta(request):
  164. if request.method == 'POST':
  165. form = CuentaForm(request.POST)
  166. if form.is_valid():
  167. cuenta = form.save(commit=False)
  168. cuenta.usuario = request.user
  169. cuenta.save()
  170. return redirect('dashboard')
  171. else:
  172. form = CuentaForm()
  173. return render(request, 'agregar_cuenta.html', {'form': form})
  174. @login_required
  175. def listar_cuentas(request):
  176. cuentas = Cuenta.objects.filter(usuario=request.user)
  177. return render(request, 'listar_cuentas.html', {'cuentas': cuentas})
  178. @login_required
  179. def editar_cuenta(request, cuenta_id):
  180. cuenta = get_object_or_404(Cuenta, id=cuenta_id, usuario=request.user)
  181. if request.method == 'POST':
  182. form = CuentaForm(request.POST, instance=cuenta)
  183. if form.is_valid():
  184. form.save()
  185. return redirect('listar_cuentas')
  186. else:
  187. form = CuentaForm(instance=cuenta)
  188. return render(request, 'editar_cuenta.html', {'form': form})
  189. @login_required
  190. def eliminar_cuenta(request, cuenta_id):
  191. cuenta = get_object_or_404(Cuenta, id=cuenta_id, usuario=request.user)
  192. tiene_movimientos = cuenta.movimientos_salida.exists() or cuenta.movimientos_entrada.exists()
  193. if request.method == 'POST' and not tiene_movimientos:
  194. cuenta.delete()
  195. return redirect('listar_cuentas')
  196. return render(request, 'eliminar_cuenta.html', {
  197. 'cuenta': cuenta,
  198. 'tiene_movimientos': tiene_movimientos,
  199. })