JairoDanielMT commited on
Commit
dea68ed
verified
1 Parent(s): f0e9d8b

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +382 -382
main.py CHANGED
@@ -1,382 +1,382 @@
1
- from sqlalchemy import create_engine, Column, Integer, String, Float, ForeignKey, Enum
2
- from sqlalchemy.orm import sessionmaker, relationship, declarative_base
3
- from datetime import datetime
4
- import pytz
5
- import os
6
- import requests
7
- from dotenv import load_dotenv
8
- from pydantic import BaseModel
9
- from typing import List
10
- from flask import Flask, jsonify, render_template
11
- from flask import request, redirect, url_for, flash
12
- from flask_cors import CORS
13
-
14
- app = Flask(__name__)
15
- app.secret_key = "Jairo_y_Diana"
16
-
17
- CORS(app)
18
-
19
-
20
- @app.after_request
21
- def add_cors_headers(response):
22
- response.headers["Access-Control-Allow-Origin"] = "*"
23
- response.headers["Access-Control-Allow-Headers"] = "*"
24
- response.headers["Access-Control-Allow-Methods"] = "*"
25
- response.headers["Access-Control-Allow-Credentials"] = "true"
26
- return response
27
-
28
-
29
- # Cargar variables de entorno
30
- load_dotenv()
31
-
32
- # URL de la API de Google Apps Script
33
- GOOGLE_SHEET_API_URL = os.getenv("GOOGLE_SHEET_API_URL")
34
-
35
- # Conexi贸n con la base de datos SQLite (Finanzas.db)
36
- DATABASE_URL = "sqlite:///finanzas.db"
37
- engine = create_engine(DATABASE_URL)
38
-
39
- # Crear una clase base para el ORM
40
- Base = declarative_base()
41
-
42
- # Definici贸n de modelos ORM
43
-
44
-
45
- class Usuario(Base):
46
- __tablename__ = "usuarios"
47
-
48
- id_usuario = Column(Integer, primary_key=True, index=True)
49
- nombre = Column(String, nullable=False)
50
-
51
-
52
- class Categoria(Base):
53
- __tablename__ = "categorias"
54
-
55
- id_categoria = Column(Integer, primary_key=True, autoincrement=True)
56
- nombre_categoria = Column(String, nullable=False)
57
- tipo = Column(Enum("Ingreso", "Gasto", name="tipo_categoria"), nullable=False)
58
-
59
-
60
- class Subcategoria(Base):
61
- __tablename__ = "subcategorias"
62
-
63
- id_subcategoria = Column(Integer, primary_key=True, autoincrement=True)
64
- id_categoria = Column(
65
- Integer, ForeignKey("categorias.id_categoria"), nullable=False
66
- )
67
- nombre_subcategoria = Column(String, nullable=False)
68
-
69
- categoria = relationship("Categoria", backref="subcategorias")
70
-
71
-
72
- class Transaccion(Base):
73
- __tablename__ = "transacciones"
74
-
75
- id_transaccion = Column(Integer, primary_key=True, autoincrement=True)
76
- fecha = Column(String, nullable=False)
77
- tipo = Column(Enum("Ingreso", "Gasto", name="tipo_transaccion"), nullable=False)
78
- monto = Column(Float, nullable=False)
79
- id_subcategoria = Column(
80
- Integer, ForeignKey("subcategorias.id_subcategoria"), nullable=False
81
- )
82
- descripcion = Column(String)
83
- id_usuario = Column(Integer, ForeignKey("usuarios.id_usuario"), nullable=False)
84
-
85
- subcategoria = relationship("Subcategoria", backref="transacciones")
86
- usuario = relationship("Usuario", backref="transacciones")
87
-
88
-
89
- # Funci贸n para obtener la fecha y hora precisa en la zona horaria de Per煤
90
- def get_peru_time():
91
- peru_tz = pytz.timezone("America/Lima")
92
- return datetime.now(peru_tz).strftime("%Y-%m-%d %H:%M:%S")
93
-
94
-
95
- # Funci贸n para enviar datos a la hoja de Google Sheets
96
- def send_to_google_sheet(data_list):
97
- data_dicts = []
98
-
99
- for data in data_list:
100
- # Convertir la fecha a un string en el formato adecuado
101
- data_dict = data.model_dump()
102
- if isinstance(data_dict["fecha"], datetime):
103
- data_dict["fecha"] = data_dict["fecha"].strftime("%Y-%m-%d %H:%M:%S")
104
-
105
- data_dicts.append(data_dict)
106
- response = requests.post(GOOGLE_SHEET_API_URL, json=data_dicts)
107
- if response.status_code == 200:
108
- print("Datos enviados con 茅xito a la Google Sheet.")
109
- else:
110
- print(f"Error al enviar datos: {response.status_code}, {response.text}")
111
-
112
-
113
- # def send_to_google_sheet(data: List[BaseModel]):
114
- # """
115
- # Env铆a los datos a la Google Sheet mediante la API de Google Apps Script.
116
- # :param data: Lista de registros con toda la informaci贸n.
117
- # """
118
- # data_dicts = [record.model_dump() for record in data]
119
- # response = requests.post(GOOGLE_SHEET_API_URL, json=data_dicts)
120
-
121
- # if response.status_code == 200:
122
- # print("Datos enviados con 茅xito a la Google Sheet.")
123
- # else:
124
- # print(f"Error al enviar datos: {response.status_code}, {response.text}")
125
-
126
-
127
- SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
128
-
129
-
130
- def insert_transaccion(fecha, tipo, monto, id_subcategoria, descripcion, id_usuario):
131
- db = SessionLocal()
132
-
133
- try:
134
- # Crear la transacci贸n
135
- transaccion = Transaccion(
136
- fecha=fecha,
137
- tipo=tipo,
138
- monto=monto,
139
- descripcion=descripcion,
140
- id_subcategoria=id_subcategoria,
141
- id_usuario=id_usuario,
142
- )
143
- db.add(transaccion)
144
- db.commit()
145
-
146
- transaccion_db = (
147
- db.query(Transaccion)
148
- .filter(Transaccion.id_transaccion == transaccion.id_transaccion)
149
- .first()
150
- )
151
-
152
- if transaccion_db:
153
- subcategoria = transaccion_db.subcategoria.nombre_subcategoria
154
- categoria = transaccion_db.subcategoria.categoria.nombre_categoria
155
- usuario = transaccion_db.usuario.nombre
156
- transaccion_pydantic = TransaccionPydantic(
157
- fecha=fecha, # Usar fecha directamente
158
- tipo=tipo,
159
- monto=monto,
160
- descripcion=descripcion,
161
- subcategoria=subcategoria,
162
- categoria=categoria,
163
- usuario=usuario,
164
- )
165
-
166
- print(transaccion_pydantic.model_dump())
167
- send_to_google_sheet([transaccion_pydantic])
168
- finally:
169
- db.close()
170
-
171
-
172
- # Funci贸n para obtener los usuarios
173
- def get_usuarios():
174
- db = SessionLocal()
175
- try:
176
- return db.query(Usuario).all()
177
- finally:
178
- db.close()
179
-
180
-
181
- # Funci贸n para obtener las categor铆as
182
- def get_categorias():
183
- db = SessionLocal()
184
- try:
185
- return db.query(Categoria).all()
186
- finally:
187
- db.close()
188
-
189
-
190
- # Funci贸n para obtener las categor铆as por tipo
191
- def get_categorias_por_tipo(tipo):
192
- db = SessionLocal()
193
- try:
194
- return db.query(Categoria).filter(Categoria.tipo == tipo).all()
195
- finally:
196
- db.close()
197
-
198
-
199
- # Funci贸n para obtener las subcategor铆as por categor铆a
200
- def get_subcategorias(id_categoria=None):
201
- db = SessionLocal()
202
- try:
203
- if id_categoria:
204
- return (
205
- db.query(Subcategoria)
206
- .filter(Subcategoria.id_categoria == id_categoria)
207
- .all()
208
- )
209
- return db.query(Subcategoria).all()
210
- finally:
211
- db.close()
212
-
213
-
214
- # Funci贸n para obtener las transacciones completas
215
- def get_full_transacciones():
216
- db = SessionLocal()
217
- try:
218
- result = (
219
- db.query(Transaccion).join(Subcategoria).join(Categoria).join(Usuario).all()
220
- )
221
- return [
222
- {
223
- "id_transaccion": t.id_transaccion,
224
- "fecha": t.fecha,
225
- "tipo": t.tipo,
226
- "monto": t.monto,
227
- "descripcion": t.descripcion,
228
- "nombre_subcategoria": t.subcategoria.nombre_subcategoria,
229
- "nombre_categoria": t.subcategoria.categoria.nombre_categoria,
230
- "usuario": t.usuario.nombre,
231
- }
232
- for t in result
233
- ]
234
- finally:
235
- db.close()
236
-
237
-
238
- def get_tipos():
239
- return ["Ingreso", "Gasto"]
240
-
241
-
242
- # Definici贸n de modelos Pydantic
243
-
244
-
245
- class TransaccionPydantic(BaseModel):
246
- fecha: datetime
247
- tipo: str
248
- monto: float
249
- descripcion: str
250
- subcategoria: str
251
- categoria: str
252
- usuario: str
253
-
254
-
255
- class CategoriaPydantic(BaseModel):
256
- id_categoria: int
257
- nombre_categoria: str
258
- tipo: str
259
-
260
-
261
- class SubcategoriaPydantic(BaseModel):
262
- id_subcategoria: int
263
- nombre_subcategoria: str
264
-
265
-
266
- class UsuarioPydantic(BaseModel):
267
- id_usuario: int
268
- nombre: str
269
-
270
-
271
- class TransaccionIngreso(BaseModel):
272
- fecha: datetime
273
- monto: float
274
- tipo: str
275
- id_subcategoria: int
276
- descripcion: str
277
- id_usuario: int
278
-
279
-
280
- # rutas
281
- @app.route("/usuarios")
282
- def usuarios():
283
- usuarios = get_usuarios()
284
- return {"usuarios": usuarios}
285
-
286
-
287
- @app.route("/categorias")
288
- def categorias():
289
- categorias = get_categorias()
290
- return {"categorias": categorias}
291
-
292
-
293
- # Ruta para obtener categor铆as por tipo a trav茅s de AJAX
294
- @app.route("/categorias/<tipo>", methods=["GET"])
295
- def categorias_por_tipo(tipo):
296
- categorias = get_categorias_por_tipo(tipo) # Obtener las categor铆as por el tipo
297
- return jsonify(
298
- [
299
- {
300
- "id_categoria": categoria.id_categoria,
301
- "nombre_categoria": categoria.nombre_categoria,
302
- "tipo": categoria.tipo,
303
- }
304
- for categoria in categorias
305
- ]
306
- )
307
-
308
-
309
- @app.route("/subcategorias")
310
- def subcategorias():
311
- subcategorias = get_subcategorias()
312
- return {"subcategorias": subcategorias}
313
-
314
-
315
- # Ruta para obtener subcategor铆as por categor铆a a trav茅s de AJAX
316
- @app.route("/subcategorias/<id_categoria>", methods=["GET"])
317
- def subcategorias_por_categoria(id_categoria):
318
- subcategorias = get_subcategorias(id_categoria)
319
- return jsonify(
320
- [
321
- {
322
- "id_subcategoria": subcategoria.id_subcategoria,
323
- "nombre_subcategoria": subcategoria.nombre_subcategoria,
324
- }
325
- for subcategoria in subcategorias
326
- ]
327
- )
328
-
329
-
330
- # Rutas del API
331
-
332
-
333
- @app.get("/")
334
- def home():
335
- usuarios = get_usuarios()
336
- categorias = get_categorias()
337
- subcategorias = get_subcategorias()
338
- tipos = get_tipos()
339
- return render_template(
340
- "index.html",
341
- usuarios=usuarios,
342
- categorias=categorias,
343
- subcategorias=subcategorias,
344
- tipos=tipos,
345
- )
346
-
347
-
348
- @app.post("/guardar-transaccion")
349
- def guardar_transaccion():
350
- try:
351
- # Obtener datos del formulario
352
- id_usuario = request.form.get("usuario")
353
- fecha = datetime.now() # Asigna la fecha actual
354
- tipo = request.form.get("tipo")
355
- monto = float(request.form.get("monto", 0)) # Convertir a float
356
- id_subcategoria = request.form.get("subcategoria")
357
- descripcion = request.form.get("descripcion")
358
-
359
- # Validar que todos los campos est茅n presentes
360
- if not all([id_usuario, tipo, monto, id_subcategoria]):
361
- flash("Por favor complete todos los campos", "error")
362
- return redirect(url_for("home")) # Redirigir al formulario principal
363
-
364
- # Insertar la transacci贸n
365
- insert_transaccion(
366
- id_usuario=int(id_usuario),
367
- fecha=fecha,
368
- tipo=tipo,
369
- monto=monto,
370
- id_subcategoria=int(id_subcategoria),
371
- descripcion=descripcion,
372
- )
373
-
374
- flash("Transacci贸n guardada exitosamente", "success")
375
- return redirect(url_for("home")) # Redirigir al formulario principal
376
- except Exception as e:
377
- flash(f"Error al guardar la transacci贸n: {str(e)}", "error")
378
- return redirect(url_for("home")) # Redirigir al formulario principal
379
-
380
-
381
- if __name__ == "__main__":
382
- app.run(host="0.0.0.0", port=8000, debug=False)
 
1
+ from sqlalchemy import create_engine, Column, Integer, String, Float, ForeignKey, Enum
2
+ from sqlalchemy.orm import sessionmaker, relationship, declarative_base
3
+ from datetime import datetime
4
+ import pytz
5
+ import os
6
+ import requests
7
+ from dotenv import load_dotenv
8
+ from pydantic import BaseModel
9
+ from typing import List
10
+ from flask import Flask, jsonify, render_template
11
+ from flask import request, redirect, url_for, flash
12
+ from flask_cors import CORS
13
+
14
+ app = Flask(__name__)
15
+ app.secret_key = "Jairo_y_Diana"
16
+
17
+ CORS(app)
18
+
19
+
20
+ @app.after_request
21
+ def add_cors_headers(response):
22
+ response.headers["Access-Control-Allow-Origin"] = "*"
23
+ response.headers["Access-Control-Allow-Headers"] = "*"
24
+ response.headers["Access-Control-Allow-Methods"] = "*"
25
+ response.headers["Access-Control-Allow-Credentials"] = "true"
26
+ return response
27
+
28
+
29
+ # Cargar variables de entorno
30
+ load_dotenv()
31
+
32
+ # URL de la API de Google Apps Script
33
+ GOOGLE_SHEET_API_URL = os.getenv("GOOGLE_SHEET_API_URL")
34
+
35
+ # Conexi贸n con la base de datos SQLite (Finanzas.db)
36
+ DATABASE_URL = "sqlite:///finanzas.db"
37
+ engine = create_engine(DATABASE_URL)
38
+
39
+ # Crear una clase base para el ORM
40
+ Base = declarative_base()
41
+
42
+ # Definici贸n de modelos ORM
43
+
44
+
45
+ class Usuario(Base):
46
+ __tablename__ = "usuarios"
47
+
48
+ id_usuario = Column(Integer, primary_key=True, index=True)
49
+ nombre = Column(String, nullable=False)
50
+
51
+
52
+ class Categoria(Base):
53
+ __tablename__ = "categorias"
54
+
55
+ id_categoria = Column(Integer, primary_key=True, autoincrement=True)
56
+ nombre_categoria = Column(String, nullable=False)
57
+ tipo = Column(Enum("Ingreso", "Gasto", name="tipo_categoria"), nullable=False)
58
+
59
+
60
+ class Subcategoria(Base):
61
+ __tablename__ = "subcategorias"
62
+
63
+ id_subcategoria = Column(Integer, primary_key=True, autoincrement=True)
64
+ id_categoria = Column(
65
+ Integer, ForeignKey("categorias.id_categoria"), nullable=False
66
+ )
67
+ nombre_subcategoria = Column(String, nullable=False)
68
+
69
+ categoria = relationship("Categoria", backref="subcategorias")
70
+
71
+
72
+ class Transaccion(Base):
73
+ __tablename__ = "transacciones"
74
+
75
+ id_transaccion = Column(Integer, primary_key=True, autoincrement=True)
76
+ fecha = Column(String, nullable=False)
77
+ tipo = Column(Enum("Ingreso", "Gasto", name="tipo_transaccion"), nullable=False)
78
+ monto = Column(Float, nullable=False)
79
+ id_subcategoria = Column(
80
+ Integer, ForeignKey("subcategorias.id_subcategoria"), nullable=False
81
+ )
82
+ descripcion = Column(String)
83
+ id_usuario = Column(Integer, ForeignKey("usuarios.id_usuario"), nullable=False)
84
+
85
+ subcategoria = relationship("Subcategoria", backref="transacciones")
86
+ usuario = relationship("Usuario", backref="transacciones")
87
+
88
+
89
+ # Funci贸n para obtener la fecha y hora precisa en la zona horaria de Per煤
90
+ def get_peru_time():
91
+ peru_tz = pytz.timezone("America/Lima")
92
+ return datetime.now(peru_tz).strftime("%Y-%m-%d %H:%M:%S")
93
+
94
+
95
+ # Funci贸n para enviar datos a la hoja de Google Sheets
96
+ def send_to_google_sheet(data_list):
97
+ data_dicts = []
98
+
99
+ for data in data_list:
100
+ # Convertir la fecha a un string en el formato adecuado
101
+ data_dict = data.model_dump()
102
+ if isinstance(data_dict["fecha"], datetime):
103
+ data_dict["fecha"] = data_dict["fecha"].strftime("%Y-%m-%d %H:%M:%S")
104
+
105
+ data_dicts.append(data_dict)
106
+ response = requests.post(GOOGLE_SHEET_API_URL, json=data_dicts)
107
+ if response.status_code == 200:
108
+ print("Datos enviados con 茅xito a la Google Sheet.")
109
+ else:
110
+ print(f"Error al enviar datos: {response.status_code}, {response.text}")
111
+
112
+
113
+ # def send_to_google_sheet(data: List[BaseModel]):
114
+ # """
115
+ # Env铆a los datos a la Google Sheet mediante la API de Google Apps Script.
116
+ # :param data: Lista de registros con toda la informaci贸n.
117
+ # """
118
+ # data_dicts = [record.model_dump() for record in data]
119
+ # response = requests.post(GOOGLE_SHEET_API_URL, json=data_dicts)
120
+
121
+ # if response.status_code == 200:
122
+ # print("Datos enviados con 茅xito a la Google Sheet.")
123
+ # else:
124
+ # print(f"Error al enviar datos: {response.status_code}, {response.text}")
125
+
126
+
127
+ SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
128
+
129
+
130
+ def insert_transaccion(fecha, tipo, monto, id_subcategoria, descripcion, id_usuario):
131
+ db = SessionLocal()
132
+
133
+ try:
134
+ # Crear la transacci贸n
135
+ transaccion = Transaccion(
136
+ fecha=fecha,
137
+ tipo=tipo,
138
+ monto=monto,
139
+ descripcion=descripcion,
140
+ id_subcategoria=id_subcategoria,
141
+ id_usuario=id_usuario,
142
+ )
143
+ db.add(transaccion)
144
+ db.commit()
145
+
146
+ transaccion_db = (
147
+ db.query(Transaccion)
148
+ .filter(Transaccion.id_transaccion == transaccion.id_transaccion)
149
+ .first()
150
+ )
151
+
152
+ if transaccion_db:
153
+ subcategoria = transaccion_db.subcategoria.nombre_subcategoria
154
+ categoria = transaccion_db.subcategoria.categoria.nombre_categoria
155
+ usuario = transaccion_db.usuario.nombre
156
+ transaccion_pydantic = TransaccionPydantic(
157
+ fecha=fecha, # Usar fecha directamente
158
+ tipo=tipo,
159
+ monto=monto,
160
+ descripcion=descripcion,
161
+ subcategoria=subcategoria,
162
+ categoria=categoria,
163
+ usuario=usuario,
164
+ )
165
+
166
+ print(transaccion_pydantic.model_dump())
167
+ send_to_google_sheet([transaccion_pydantic])
168
+ finally:
169
+ db.close()
170
+
171
+
172
+ # Funci贸n para obtener los usuarios
173
+ def get_usuarios():
174
+ db = SessionLocal()
175
+ try:
176
+ return db.query(Usuario).all()
177
+ finally:
178
+ db.close()
179
+
180
+
181
+ # Funci贸n para obtener las categor铆as
182
+ def get_categorias():
183
+ db = SessionLocal()
184
+ try:
185
+ return db.query(Categoria).all()
186
+ finally:
187
+ db.close()
188
+
189
+
190
+ # Funci贸n para obtener las categor铆as por tipo
191
+ def get_categorias_por_tipo(tipo):
192
+ db = SessionLocal()
193
+ try:
194
+ return db.query(Categoria).filter(Categoria.tipo == tipo).all()
195
+ finally:
196
+ db.close()
197
+
198
+
199
+ # Funci贸n para obtener las subcategor铆as por categor铆a
200
+ def get_subcategorias(id_categoria=None):
201
+ db = SessionLocal()
202
+ try:
203
+ if id_categoria:
204
+ return (
205
+ db.query(Subcategoria)
206
+ .filter(Subcategoria.id_categoria == id_categoria)
207
+ .all()
208
+ )
209
+ return db.query(Subcategoria).all()
210
+ finally:
211
+ db.close()
212
+
213
+
214
+ # Funci贸n para obtener las transacciones completas
215
+ def get_full_transacciones():
216
+ db = SessionLocal()
217
+ try:
218
+ result = (
219
+ db.query(Transaccion).join(Subcategoria).join(Categoria).join(Usuario).all()
220
+ )
221
+ return [
222
+ {
223
+ "id_transaccion": t.id_transaccion,
224
+ "fecha": t.fecha,
225
+ "tipo": t.tipo,
226
+ "monto": t.monto,
227
+ "descripcion": t.descripcion,
228
+ "nombre_subcategoria": t.subcategoria.nombre_subcategoria,
229
+ "nombre_categoria": t.subcategoria.categoria.nombre_categoria,
230
+ "usuario": t.usuario.nombre,
231
+ }
232
+ for t in result
233
+ ]
234
+ finally:
235
+ db.close()
236
+
237
+
238
+ def get_tipos():
239
+ return ["Ingreso", "Gasto"]
240
+
241
+
242
+ # Definici贸n de modelos Pydantic
243
+
244
+
245
+ class TransaccionPydantic(BaseModel):
246
+ fecha: datetime
247
+ tipo: str
248
+ monto: float
249
+ descripcion: str
250
+ subcategoria: str
251
+ categoria: str
252
+ usuario: str
253
+
254
+
255
+ class CategoriaPydantic(BaseModel):
256
+ id_categoria: int
257
+ nombre_categoria: str
258
+ tipo: str
259
+
260
+
261
+ class SubcategoriaPydantic(BaseModel):
262
+ id_subcategoria: int
263
+ nombre_subcategoria: str
264
+
265
+
266
+ class UsuarioPydantic(BaseModel):
267
+ id_usuario: int
268
+ nombre: str
269
+
270
+
271
+ class TransaccionIngreso(BaseModel):
272
+ fecha: datetime
273
+ monto: float
274
+ tipo: str
275
+ id_subcategoria: int
276
+ descripcion: str
277
+ id_usuario: int
278
+
279
+
280
+ # rutas
281
+ @app.route("/usuarios")
282
+ def usuarios():
283
+ usuarios = get_usuarios()
284
+ return {"usuarios": usuarios}
285
+
286
+
287
+ @app.route("/categorias")
288
+ def categorias():
289
+ categorias = get_categorias()
290
+ return {"categorias": categorias}
291
+
292
+
293
+ # Ruta para obtener categor铆as por tipo a trav茅s de AJAX
294
+ @app.route("/categorias/<tipo>", methods=["GET"])
295
+ def categorias_por_tipo(tipo):
296
+ categorias = get_categorias_por_tipo(tipo) # Obtener las categor铆as por el tipo
297
+ return jsonify(
298
+ [
299
+ {
300
+ "id_categoria": categoria.id_categoria,
301
+ "nombre_categoria": categoria.nombre_categoria,
302
+ "tipo": categoria.tipo,
303
+ }
304
+ for categoria in categorias
305
+ ]
306
+ )
307
+
308
+
309
+ @app.route("/subcategorias")
310
+ def subcategorias():
311
+ subcategorias = get_subcategorias()
312
+ return {"subcategorias": subcategorias}
313
+
314
+
315
+ # Ruta para obtener subcategor铆as por categor铆a a trav茅s de AJAX
316
+ @app.route("/subcategorias/<id_categoria>", methods=["GET"])
317
+ def subcategorias_por_categoria(id_categoria):
318
+ subcategorias = get_subcategorias(id_categoria)
319
+ return jsonify(
320
+ [
321
+ {
322
+ "id_subcategoria": subcategoria.id_subcategoria,
323
+ "nombre_subcategoria": subcategoria.nombre_subcategoria,
324
+ }
325
+ for subcategoria in subcategorias
326
+ ]
327
+ )
328
+
329
+
330
+ # Rutas del API
331
+
332
+
333
+ @app.get("/")
334
+ def home():
335
+ usuarios = get_usuarios()
336
+ categorias = get_categorias()
337
+ subcategorias = get_subcategorias()
338
+ tipos = get_tipos()
339
+ return render_template(
340
+ "index.html",
341
+ usuarios=usuarios,
342
+ categorias=categorias,
343
+ subcategorias=subcategorias,
344
+ tipos=tipos,
345
+ )
346
+
347
+
348
+ @app.post("/guardar-transaccion")
349
+ def guardar_transaccion():
350
+ try:
351
+ # Obtener datos del formulario
352
+ id_usuario = request.form.get("usuario")
353
+ fecha = datetime.now() # Asigna la fecha actual
354
+ tipo = request.form.get("tipo")
355
+ monto = float(request.form.get("monto", 0)) # Convertir a float
356
+ id_subcategoria = request.form.get("subcategoria")
357
+ descripcion = request.form.get("descripcion")
358
+
359
+ # Validar que todos los campos est茅n presentes
360
+ if not all([id_usuario, tipo, monto, id_subcategoria]):
361
+ flash("Por favor complete todos los campos", "error")
362
+ return redirect(url_for("home")) # Redirigir al formulario principal
363
+
364
+ # Insertar la transacci贸n
365
+ insert_transaccion(
366
+ id_usuario=int(id_usuario),
367
+ fecha=fecha,
368
+ tipo=tipo,
369
+ monto=monto,
370
+ id_subcategoria=int(id_subcategoria),
371
+ descripcion=descripcion,
372
+ )
373
+
374
+ flash("Transacci贸n guardada exitosamente", "success")
375
+ return redirect(url_for("home")) # Redirigir al formulario principal
376
+ except Exception as e:
377
+ flash(f"Error al guardar la transacci贸n: {str(e)}", "error")
378
+ return redirect(url_for("home")) # Redirigir al formulario principal
379
+
380
+
381
+ if __name__ == "__main__":
382
+ app.run(host="0.0.0.0", port=7860, debug=False)