Przeglądaj źródła

API para lanzar transacciones recurrentes

Celestino Rey 1 rok temu
rodzic
commit
da10ccedb9

+ 1 - 1
K8S/Makefile

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

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

@@ -2,7 +2,7 @@ apiVersion: v1
 data:
 data:
   DEBUG: "False"
   DEBUG: "False"
   ENTORNO: "Producción"
   ENTORNO: "Producción"
-  APP_VERSION: 15.0.13
+  APP_VERSION: 15.0.14
   SECRET_KEY: change_me
   SECRET_KEY: change_me
   SQL_HOST: postgresql
   SQL_HOST: postgresql
   SQL_PORT: "5432"
   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.
 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 django.urls import path
 from . import views
 from . import views
+from .views import api_ejecutar_recurrentes
 
 
 urlpatterns = [
 urlpatterns = [
     path('', views.dashboard, name='dashboard'),
     path('', views.dashboard, name='dashboard'),
@@ -16,6 +17,6 @@ urlpatterns = [
     # API
     # API
     path('api/datos/', views.api_datos_completos, name='api_datos_completos'),
     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.shortcuts import render, redirect, get_object_or_404
 from django.http import JsonResponse
 from django.http import JsonResponse
+from django.views.decorators.csrf import csrf_exempt
 from decimal import Decimal, InvalidOperation
 from decimal import Decimal, InvalidOperation
 from django.db import models as db_models
 from django.db import models as db_models
 from django.contrib.auth.decorators import login_required
 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.utils.timezone import now
 from django.core.serializers import serialize
 from django.core.serializers import serialize
 from datetime import date, timedelta
 from datetime import date, timedelta
+from django.conf import settings
 
 
 import logging
 import logging
 import re
 import re
@@ -15,6 +17,8 @@ import calendar
 from accounts import models
 from accounts import models
 from .models import Movimiento, Cuenta, MovimientoFrecuente, Categoria, TransaccionRecurrente
 from .models import Movimiento, Cuenta, MovimientoFrecuente, Categoria, TransaccionRecurrente
 from .forms import MovimientoForm, FiltroForm, CuentaForm
 from .forms import MovimientoForm, FiltroForm, CuentaForm
+from .recurrentes import procesar_transacciones_recurrentes
+
 
 
 logger = logging.getLogger(__name__)
 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})
     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
 @login_required
 def ejecutar_recurrentes(request):
 def ejecutar_recurrentes(request):
     procesar_transacciones_recurrentes()
     procesar_transacciones_recurrentes()
     return redirect('dashboard')
     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'