-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdatabase.py
More file actions
291 lines (266 loc) · 10.6 KB
/
database.py
File metadata and controls
291 lines (266 loc) · 10.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
import sqlite3
import bcrypt
class Database:
def __init__(self, db_path='cooperadora.db'):
self.conn = sqlite3.connect(db_path)
self.create_tables()
self.crear_usuario_predeterminado()
def create_tables(self):
cursor = self.conn.cursor()
# Nueva estructura de la tabla socios
cursor.execute('''
CREATE TABLE IF NOT EXISTS socios (
id INTEGER PRIMARY KEY AUTOINCREMENT,
numero_socio TEXT UNIQUE NOT NULL,
nombre_socio TEXT NOT NULL,
dni_socio TEXT UNIQUE NOT NULL,
parentesco TEXT NOT NULL,
email TEXT,
telefono TEXT NOT NULL,
nombre_estudiante TEXT NOT NULL,
curso_estudiante TEXT NOT NULL,
ciclo_lectivo TEXT NOT NULL
)
''')
# Mantener la tabla de pagos sin cambios
cursor.execute('''
CREATE TABLE IF NOT EXISTS pagos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
socio_id INTEGER NOT NULL,
ultimo_pago TEXT NOT NULL,
fecha_pago DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (socio_id) REFERENCES socios(id) ON DELETE CASCADE
)
''')
# Mantener la tabla de usuarios
cursor.execute('''
CREATE TABLE IF NOT EXISTS usuarios (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL
)
''')
self.conn.commit()
# ===== CRUD Socios =====
def agregar_socio(self, data):
try:
cursor = self.conn.cursor()
cursor.execute('''
INSERT INTO socios (
numero_socio, nombre_socio, dni_socio, parentesco,
email, telefono, nombre_estudiante, curso_estudiante, ciclo_lectivo
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
''', (
data['numero_socio'],
data['nombre_socio'],
data['dni_socio'],
data['parentesco'],
data['email'],
data['telefono'],
data['nombre_estudiante'],
data['curso_estudiante'],
data['ciclo_lectivo']
))
self.conn.commit()
return True, "Socio agregado exitosamente"
except sqlite3.IntegrityError as e:
error_msg = {
"UNIQUE constraint failed: socios.numero_socio": "Número de socio ya existe",
"UNIQUE constraint failed: socios.dni_socio": "DNI socio ya registrado"
}.get(str(e), "Error de duplicación: Datos ya existen")
return False, error_msg
def buscar_socios(self, criterio):
cursor = self.conn.cursor()
query = '''
SELECT
s.id,
s.numero_socio,
s.nombre_socio,
s.dni_socio,
s.nombre_estudiante,
s.curso_estudiante,
s.ciclo_lectivo,
p.ultimo_pago
FROM socios s
LEFT JOIN (
SELECT socio_id, MAX(ultimo_pago) as ultimo_pago
FROM pagos
GROUP BY socio_id
) p ON s.id = p.socio_id
WHERE
s.numero_socio LIKE ? OR
s.nombre_socio LIKE ? OR
s.dni_socio LIKE ? OR
s.nombre_estudiante LIKE ? OR
s.curso_estudiante LIKE ? OR
s.ciclo_lectivo LIKE ? OR
p.ultimo_pago LIKE ?
'''
param = f"%{criterio}%"
cursor.execute(query, (param, param, param, param, param, param, param))
return cursor.fetchall()
def eliminar_socios(self, ids):
try:
cursor = self.conn.cursor()
placeholders = ','.join(['?'] * len(ids))
cursor.execute(f"DELETE FROM socios WHERE id IN ({placeholders})", ids)
cursor.execute(f"DELETE FROM pagos WHERE socio_id IN ({placeholders})", ids)
self.conn.commit()
return cursor.rowcount > 0
except sqlite3.Error as e:
print(f"Error al eliminar socios: {e}")
return False
# ===== Gestión de Pagos =====
def tiene_pagos(self, socio_id):
"""Verifica si el socio tiene pagos registrados"""
cursor = self.conn.cursor()
cursor.execute("SELECT 1 FROM pagos WHERE socio_id = ? LIMIT 1", (socio_id,))
return cursor.fetchone() is not None
def obtener_ultimo_pago(self, socio_id):
"""Obtiene el último pago registrado para un socio"""
cursor = self.conn.cursor()
cursor.execute("""
SELECT ultimo_pago FROM pagos
WHERE socio_id = ?
ORDER BY fecha_pago DESC
LIMIT 1
""", (socio_id,))
result = cursor.fetchone()
return result[0] if result else None
def registrar_pago(self, socio_id, mes):
"""Registra o actualiza un pago según corresponda"""
cursor = self.conn.cursor()
# Verificar si ya existe al menos un pago para este socio
cursor.execute("SELECT 1 FROM pagos WHERE socio_id = ? LIMIT 1", (socio_id,))
tiene_pagos = cursor.fetchone() is not None
if tiene_pagos:
# ACTUALIZAR el último pago existente
cursor.execute('''
UPDATE pagos
SET ultimo_pago = ?,
fecha_pago = CURRENT_TIMESTAMP
WHERE id = (
SELECT id FROM pagos
WHERE socio_id = ?
ORDER BY fecha_pago DESC
LIMIT 1
)
''', (mes, socio_id))
else:
# INSERTAR nuevo registro (primer pago)
cursor.execute('''
INSERT INTO pagos (socio_id, ultimo_pago)
VALUES (?, ?)
''', (socio_id, mes))
self.conn.commit()
# ===== Autenticación =====
def crear_usuario(self, usuario, password):
hashed = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt())
try:
cursor = self.conn.cursor()
cursor.execute('''
INSERT INTO usuarios (username, password_hash)
VALUES (?, ?)
''', (usuario, hashed.decode('utf-8'))) # Decodificar el hash para almacenarlo
self.conn.commit()
return True
except sqlite3.IntegrityError:
return False
def verificar_usuario(self, usuario, password):
cursor = self.conn.cursor()
cursor.execute('''
SELECT password_hash FROM usuarios WHERE username = ?
''', (usuario,))
result = cursor.fetchone()
if result:
# Asegúrate de que el hash esté en bytes
stored_hash = result[0].encode('utf-8') if isinstance(result[0], str) else result[0]
return bcrypt.checkpw(password.encode('utf-8'), stored_hash)
return False
def crear_usuario_predeterminado(self):
"""Crea el usuario por defecto si no existe"""
cursor = self.conn.cursor()
# Verificar si ya existe el usuario
cursor.execute("SELECT 1 FROM usuarios WHERE username = 'coope'")
if not cursor.fetchone():
self.crear_usuario("coope", "coope123")
print("Usuario predeterminado creado: coope/coope123")
else:
print("Usuario predeterminado ya existe")
def obtener_socio_por_id(self, socio_id):
cursor = self.conn.cursor()
cursor.execute("""
SELECT
id, numero_socio, nombre_socio, dni_socio, parentesco,
email, telefono, nombre_estudiante, curso_estudiante, ciclo_lectivo
FROM socios
WHERE id = ?
""", (socio_id,))
return cursor.fetchone()
def actualizar_socio(self, socio_id, data):
"""Actualiza los datos de un socio existente con validación de duplicados"""
try:
cursor = self.conn.cursor()
# Validación adicional: Verificar conflictos con otros registros
cursor.execute("""
SELECT id FROM socios
WHERE (dni_socio = ? OR numero_socio = ?)
AND id != ?
""", (
data['dni_socio'],
data['numero_socio'],
socio_id
))
conflicto = cursor.fetchone()
if conflicto:
# Identificar exactamente qué campo está en conflicto
cursor.execute("""
SELECT
CASE
WHEN dni_socio = ? THEN 'DNI socio'
WHEN numero_socio = ? THEN 'Número de socio'
END as campo_conflicto
FROM socios
WHERE id = ?
""", (
data['dni_socio'],
data['numero_socio'],
conflicto[0]
))
campo_conflicto = cursor.fetchone()[0]
return False, f"{campo_conflicto} ya está registrado en otro socio"
cursor.execute('''
UPDATE socios
SET
numero_socio = ?,
nombre_socio = ?,
dni_socio = ?,
parentesco = ?,
email = ?,
telefono = ?,
nombre_estudiante = ?,
curso_estudiante = ?,
ciclo_lectivo = ?
WHERE id = ?
''', (
data['numero_socio'],
data['nombre_socio'],
data['dni_socio'],
data['parentesco'],
data['email'],
data['telefono'],
data['nombre_estudiante'],
data['curso_estudiante'],
data['ciclo_lectivo'],
socio_id
))
self.conn.commit()
return True, "Socio actualizado exitosamente"
except sqlite3.IntegrityError as e:
error_msg = {
"UNIQUE constraint failed: socios.numero_socio": "Número de socio ya existe",
"UNIQUE constraint failed: socios.dni_socio": "DNI socio ya registrado"
}.get(str(e), "Error de duplicación: Datos ya existen")
return False, error_msg
except Exception as e:
return False, f"Error inesperado al actualizar socio: {str(e)}"