Ver código fonte

API para lanzar transacciones recurrentes

Celestino Rey 1 ano atrás
pai
commit
da10ccedb9

+ 1 - 1
K8S/Makefile

@@ -1,6 +1,6 @@
 export ARQUITECTURA := $(shell lscpu |grep itectur | tr -d ' '| cut -f2 -d':')
 export REGISTRY=registry.reymota.es
-export IMG_VERSION = 0.27
+export IMG_VERSION = 0.28
 export IMG_NGINX_VERSION = 1.0
 
 # limpia todo

+ 1 - 1
K8S/env-prod-configmap.yaml

@@ -2,7 +2,7 @@ apiVersion: v1
 data:
   DEBUG: "False"
   ENTORNO: "Producción"
-  APP_VERSION: 15.0.13
+  APP_VERSION: 15.0.14
   SECRET_KEY: change_me
   SQL_HOST: postgresql
   SQL_PORT: "5432"

+ 3 - 0
README.md

@@ -94,3 +94,6 @@ Con la shell entraPsql.sh:
 
 esto se hace cuando restauro un volcado de la bd sobre una instalación nueva. Si hay índices ya creados, hay que reinciar a partir del último.
 
+# TRANSACCIONES RECURRENTES
+
+    curl "http://finanzas.rancher.reymota.lab/api/ejecutar-recurrentes/?token=mi-token-secreto-superseguro"

+ 50 - 0
src/finanzas/recurrentes.py

@@ -0,0 +1,50 @@
+from .models import TransaccionRecurrente, Movimiento
+from datetime import date, timedelta
+import calendar
+
+
+def procesar_transacciones_recurrentes(hoy=None):
+    if hoy is None:
+        hoy = date.today()
+
+    for tr in TransaccionRecurrente.objects.filter(activa=True):
+        if tr.ultima_ejecucion and tr.ultima_ejecucion >= hoy.replace(day=1):
+            continue  # Ya se ejecutó este mes
+
+        ejecutar = False
+
+        if tr.frecuencia == 'mensual_dia' and tr.dia_del_mes:
+            ejecutar = hoy.day == tr.dia_del_mes
+
+        elif tr.frecuencia == 'mensual_semana' and tr.semana and tr.dia_semana is not None:
+            # Calcular fecha del primer (por ejemplo) lunes
+            primer_dia = hoy.replace(day=1)
+            weekday_count = 0
+            for i in range(31):  # máx 31 días
+                d = primer_dia + timedelta(days=i)
+                if d.month != hoy.month:
+                    break
+                if d.weekday() == tr.dia_semana:
+                    weekday_count += 1
+                    if weekday_count == tr.semana and d == hoy:
+                        ejecutar = True
+                        break
+
+        if ejecutar:
+            Movimiento.objects.create(
+                usuario=tr.usuario,
+                cuenta_origen=tr.cuenta_origen,
+                cuenta_destino=tr.cuenta_destino,
+                monto=tr.monto,
+                fecha=hoy,
+                descripcion=tr.descripcion,
+                categoria=tr.categoria,
+            )
+            tr.ultima_ejecucion = hoy
+            tr.save()
+
+            # Actualizar saldos
+            tr.cuenta_origen.saldo -= tr.monto
+            tr.cuenta_origen.save()
+            tr.cuenta_destino.saldo += tr.monto
+            tr.cuenta_destino.save()

+ 2 - 1
src/finanzas/urls.py

@@ -1,5 +1,6 @@
 from django.urls import path
 from . import views
+from .views import api_ejecutar_recurrentes
 
 urlpatterns = [
     path('', views.dashboard, name='dashboard'),
@@ -16,6 +17,6 @@ urlpatterns = [
     # API
     path('api/datos/', views.api_datos_completos, name='api_datos_completos'),
 
-    path('ejecutar-recurrentes/', views.ejecutar_recurrentes, name='ejecutar_recurrentes'),
+    path('api/ejecutar-recurrentes/', api_ejecutar_recurrentes, name='api_ejecutar_recurrentes'),
 
 ]

+ 15 - 47
src/finanzas/views.py

@@ -1,5 +1,6 @@
 from django.shortcuts import render, redirect, get_object_or_404
 from django.http import JsonResponse
+from django.views.decorators.csrf import csrf_exempt
 from decimal import Decimal, InvalidOperation
 from django.db import models as db_models
 from django.contrib.auth.decorators import login_required
@@ -7,6 +8,7 @@ from django.contrib import messages
 from django.utils.timezone import now
 from django.core.serializers import serialize
 from datetime import date, timedelta
+from django.conf import settings
 
 import logging
 import re
@@ -15,6 +17,8 @@ import calendar
 from accounts import models
 from .models import Movimiento, Cuenta, MovimientoFrecuente, Categoria, TransaccionRecurrente
 from .forms import MovimientoForm, FiltroForm, CuentaForm
+from .recurrentes import procesar_transacciones_recurrentes
+
 
 logger = logging.getLogger(__name__)
 
@@ -277,54 +281,18 @@ def api_datos_completos(request):
     return JsonResponse(data, safe=False, json_dumps_params={'ensure_ascii': False, 'indent': 2})
 
 
-def procesar_transacciones_recurrentes(hoy=None):
-    if hoy is None:
-        hoy = date.today()
-
-    for tr in TransaccionRecurrente.objects.filter(activa=True):
-        if tr.ultima_ejecucion and tr.ultima_ejecucion >= hoy.replace(day=1):
-            continue  # Ya se ejecutó este mes
-
-        ejecutar = False
-
-        if tr.frecuencia == 'mensual_dia' and tr.dia_del_mes:
-            ejecutar = hoy.day == tr.dia_del_mes
-
-        elif tr.frecuencia == 'mensual_semana' and tr.semana and tr.dia_semana is not None:
-            # Calcular fecha del primer (por ejemplo) lunes
-            primer_dia = hoy.replace(day=1)
-            weekday_count = 0
-            for i in range(31):  # máx 31 días
-                d = primer_dia + timedelta(days=i)
-                if d.month != hoy.month:
-                    break
-                if d.weekday() == tr.dia_semana:
-                    weekday_count += 1
-                    if weekday_count == tr.semana and d == hoy:
-                        ejecutar = True
-                        break
-
-        if ejecutar:
-            Movimiento.objects.create(
-                usuario=tr.usuario,
-                cuenta_origen=tr.cuenta_origen,
-                cuenta_destino=tr.cuenta_destino,
-                monto=tr.monto,
-                fecha=hoy,
-                descripcion=tr.descripcion,
-                categoria=tr.categoria,
-            )
-            tr.ultima_ejecucion = hoy
-            tr.save()
-
-            # Actualizar saldos
-            tr.cuenta_origen.saldo -= tr.monto
-            tr.cuenta_origen.save()
-            tr.cuenta_destino.saldo += tr.monto
-            tr.cuenta_destino.save()
-
-
 @login_required
 def ejecutar_recurrentes(request):
     procesar_transacciones_recurrentes()
     return redirect('dashboard')
+
+
+@csrf_exempt
+def api_ejecutar_recurrentes(request):
+    token_enviado = request.headers.get('X-API-KEY') or request.GET.get('token')
+
+    if token_enviado != settings.RECURRENTES_API_TOKEN:
+        return JsonResponse({'error': 'No autorizado'}, status=403)
+
+    procesar_transacciones_recurrentes(hoy=now().date())
+    return JsonResponse({'ok': True, 'mensaje': 'Transacciones recurrentes ejecutadas'})

+ 2 - 0
src/misfinanzas/settings.py

@@ -216,3 +216,5 @@ LOGGING = {
         },
     },
 }
+
+RECURRENTES_API_TOKEN = 'mi-token-secreto-superseguro'