-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.py
482 lines (403 loc) · 16.7 KB
/
main.py
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
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
# This Python file uses the following encoding: utf-8
# from PySide2.QtCore import QUrl, QTimer
from data.database import Database
from dotenv import load_dotenv
from utils.helpers import *
from connection import ConnectionDB
from models.budget import Budget
from models.client import Client
from models.user import User
from data.budget import BudgetData
from data.client import ClientData
from data.user import UserData
from PySide2.QtQml import QQmlApplicationEngine
from PySide2.QtGui import QGuiApplication, QIcon
from utils.encrypter import generate_key, load_key, encriptedPassword, createLocalEnv
from PySide2.QtCore import QObject, Qt, Signal, Property, Slot, qVersion
import sys
import os
import PySide2
print("Versión de PySide2:: ", PySide2.__version__)
print("Versión de Qt Usada por PySide2: ", qVersion())
load_dotenv()
env_file = ".env"
DEFAULT_ADMIN_USERNAME = "default_username"
ADMIN_USERNAME = os.getenv("ADMIN_USERNAME", DEFAULT_ADMIN_USERNAME)
# Carga la clave de desencriptación
key = load_key()
# Verifica si el archivo users.db existe
if not os.path.exists("users.db"):
# Si no existe, crea la conexión y llama al método para inicializar la DB y crear las tablas
db_connection = ConnectionDB()
db_connection.init_db()
# ConnectionDB().init_db() # Para Pruebas, crear y actualizar tablas de DB. borrar linea en produccion
# Clase para logarse
class Login(QObject):
userLoged = Signal(str, str) # Señal de usuario logado
loggedUsernameChanged = Signal() # Señal de nombre de usuario
userIdChanged = Signal(int) # Señal para user_id de usuario
clientsRetrieved = Signal(list) # Señal para clientes del usuario
def __init__(self, parent=None):
super(Login, self).__init__(parent)
self._username = ""
self._password = ""
self._loggedUsername = ""
self._userId = None # Nueva variable para guardar el user_id
# Property para el user_id
@Property(int, notify=userIdChanged)
def userId(self):
return self._userId
@userId.setter
def userId(self, value):
if self._userId != value:
self._userId = value
self.userIdChanged.emit()
# Property para el username
@Property(str, notify=loggedUsernameChanged)
def loggedUsername(self):
return self._loggedUsername
@loggedUsername.setter
def loggedUsername(self, value):
if self._loggedUsername != value:
self._loggedUsername = value
self.loggedUsernameChanged.emit()
# Metodo para la consulta de clientes
def getClientsForUser(self):
db = Database()
print("The username's logged is: ", self._username)
# Consulta de todos los cliente para el superusuario XD
if self._username == ADMIN_USERNAME:
clients = db.getAllClients(self._userId)
# Consulta sólo de los clientes del usuario
else:
clients = db.getClientsForUserId(self._userId)
clients_list = [
{
"name": client._name,
"address": client._address,
"email": client._email,
"city": client._city,
"zip_code": client._zip_code,
"phone": client._phone,
"user_id": client._user_id,
}
for client in clients
]
print(f"The clients belong to {self._username} is :", clients_list)
self.clientsRetrieved.emit(clients_list)
db.close()
# Metodo para logarse
@Slot(str, str)
def user_login(self, username, password):
user = User(username, None, password)
userData = UserData()
response = userData.login(user)
if response == "user_not_found":
self.userLoged.emit(
"No existe usuario debe crear una cuenta", None)
return
elif response == "incorrect_password":
self.userLoged.emit("Contraseña incorrecta!", None)
return
elif isinstance(response, User):
self._username = username
self._userId = response._id
print("El userId obtenido la clase Login es: ", self._userId)
self.userLoged.emit("Acceso concedido", None)
self.loggedUsername = self._username
self.userId = (
self._userId
) # Actualizar y emitir la nueva señal userIdChanged
print("El userId obtenido la clase Login es: ", self.userId)
# Obtener e imprimir clientes del usuario
self.getClientsForUser()
# Clase para creacion de usuarios
class signUp(QObject):
userCreated = Signal(str)
loggedUsernameChanged = Signal()
userIdChanged = Signal(int) # Nueva señal para user_id
def __init__(self, parent=None):
super(signUp, self).__init__(parent)
self._loggedUsername = ""
self._userId = None # Nueva variable para guardar el user_id
@Property(int, notify=userIdChanged)
def userId(self):
return self._userId
@userId.setter
def userId(self, value):
if self._userId != value:
self._userId = value
self.userIdChanged.emit()
@Property(str, notify=loggedUsernameChanged)
def loggedUsername(self):
return self._loggedUsername
@loggedUsername.setter
def loggedUsername(self, value):
if self._loggedUsername != value:
self._loggedUsername = value
self.loggedUsernameChanged.emit()
@Slot(str, str, str, str)
def create_user(self, username, email, password, rptPassword):
# Aquí implementas la lógica para crear un usuario.
if username == "" or password == "" or email == "":
self.userCreated.emit("Rellene todos los campos")
return
if password != rptPassword:
self.userCreated.emit("Las contraseñas no coinciden.")
return
userData = UserData()
if userData.user_Exists(username):
self.userCreated.emit("Este usuario ya existe.")
return
if userData.email_Exists(email):
self.userCreated.emit("Este email ya está registrado.")
return
# Cifrar la contraseña (esto es un paso crucial que debes investigar más)
encrypted_password = encriptedPassword(password, key)
print("Antes de guardar:", encrypted_password)
# Guardar username, email y password en DB
user = userData.create_User(User(username, email, encrypted_password))
self.loggedUsername = username
if user is None:
self.userCreated.emit("Error al crear el usuario")
print("Error al crear el usuario")
return
self._userId = user._id # Asigna el ID del usuario
print("El userId obtenido la clase signUp es: ", self._userId)
self.userId = self._userId # Actualizar y emitir la nueva señal userIdChanged
print("El userId obtenido la clase signUp es: ", self.userId)
# Finalmente, emites la señal userCreated correcta
self.userCreated.emit("User created successfull")
# Clase para la creacion de clientes
class ClientManager(QObject):
# Señales
clientCreated = Signal(
str, str, str, str, str, str, int
) # nombre, direccion, email, ciudad, cp, telefono del cliente y id del usaurio al que pertenece el cliente
clientEdited = Signal(
str, str, str, str, str, str, int
) # nombre, direccion, email, ciudad, cp, telefono del cliente y id del usaurio al que pertenece el cliente
clientValidated = Signal(str) # Confirmacion de cliente creado
clientUpgraded = Signal(str) # Confirmacion de cliente editado
def __init__(self, parent=None):
super(ClientManager, self).__init__(parent)
self._client = Client() # Instancia vacía de cliente.
# # Función para crear un nuevo cliente y emitir señales (aqui recibe los datos desde el lado del cliente)
@Slot(str, str, str, str, str, str, int)
def createClient(self, name, address, email, city, zip_code, phone, user_id):
if (
not name
or not address
or not email
or not city
or not zip_code
or not phone
):
self.clientValidated.emit("Rellene todos los campos")
return
# Llama al Metodo Data que crea el cliente en la DB
clientData = ClientData()
# Creamos al cliente (Lo que guarda en DB)
newClient = clientData.create_Client(
Client(name, address, email, city,
zip_code, phone, user_id), user_id
)
# Validamos que el cliente se haya creado correctamente
if newClient is None:
self.clientCreated.emit("Error al crear el cliente")
print("Error al crear el cliente")
return
# Aquí se debería emitir la señal clientCreated para su uso en el lado del cliente
self.clientCreated.emit(name, address, email,
city, zip_code, phone, user_id)
self.clientValidated.emit("Cliente creado")
# Funcion para editar cliente (aun no en uso en cliente)
@Slot(str, str, str, str, str, str, int)
def updateClient(self, name, address, email, city, zip_code, phone, user_id):
if (
not name
or not address
or not email
or not city
or not zip_code
or not phone
):
self.clientValidated.emit("Debe al menos cambiar un campo")
return
clientData = ClientData()
# Llama al Metodo Data que edita el cliente en la DB (aun en desarrollo)
editedClient = clientData.update_Client(
Client(name, address, email, city,
zip_code, phone, user_id), user_id
)
if editedClient is None:
self.clientCreated.emit("Error al crear el cliente")
print("Error al editar al cliente")
return
self.clientEdited.emit(name, address, email,
city, zip_code, phone, user_id)
self.clientUpgraded.emit("Cliente editado")
# Clase para la creacion de presupuestos
class BudgetManager(QObject):
# Señales
budgetCreated = Signal(str, str, int, int, int, str,
str, str, str, str, str, int)
budgetValidated = Signal(str)
def __init__(self, parent=None):
super(BudgetManager, self).__init__(parent)
self._budget = Budget() # Instancia vacía de cliente.
# Funcion para crear presupuesto y emitir señales (aqui recibe los datos desde el lado del cliente)
@Slot(str, str, float, float, float, str, str, str, str, str, str, int)
def createBudget(
self,
budgetId,
budgetName,
budgetAmountSubtotal,
budgetAmountTaxes,
budgetAmountTotal,
budgetDate,
budgetDescription,
budgetStatus,
budgetType,
budgetCategory,
budgetNotes,
client_id,
):
if (
not budgetId
or not budgetName
or not budgetAmountSubtotal
or not budgetAmountTaxes
or not budgetAmountTotal
or not budgetDate
or not budgetDescription
or not budgetStatus
or not budgetType
or not budgetCategory
or not budgetNotes
):
self.budgetValidated.emit("Rellene todos los campos")
return
# Pasamos las cantidades desde el lado del cliente, de euros(float) a centimos(integer)
budgetAmountSubtotal_inCents = eurs_to_cents(budgetAmountSubtotal)
budgetAmountTaxes_inCents = eurs_to_cents(budgetAmountTaxes)
budgetAmountTotal_inCents = eurs_to_cents(budgetAmountTotal)
# # Pasamos la fecha desde el cliente a formato datetime
# budgetDate = datetime.strptime(budgetDate, "%d/%m/%Y")
# # Pasamos el status desde el cliente a formato booleano
# budgetStatus = budgetStatus == "Activo"
# # Pasamos el tipo desde el cliente a formato booleano
# budgetType = budgetType == "Fijo"
# # Pasamos la categoria desde el cliente a formato booleano
# budgetCategory = budgetCategory == "Personal"
# # Pasamos los notas desde el cliente a formato booleano
# budgetNotes = budgetNotes == "Sin notas"
# LLama al metodo Data que crea el presupuesto en la DB
budgetData = BudgetData()
# Creamos el presupuesto (Lo que guarda en DB)
budget = budgetData.add_Budget(
Budget(
budgetId,
budgetName,
budgetAmountSubtotal_inCents,
budgetAmountTaxes_inCents,
budgetAmountTotal_inCents,
budgetDate,
budgetDescription,
budgetStatus,
budgetType,
budgetCategory,
budgetNotes,
client_id,
),
client_id,
)
# Validamos que el presupuesto se haya creado correctamente
if budget is None:
self.budgetCreated.emit("Error al crear el presupuesto")
print("Error al crear el presupuesto")
return
# self._budget.update_info(budgetId, budgetName, budgetAmountSubtotal, budgetAmountTaxes, budgetAmountTotal, budgetDate, budgetDescription, budgetStatus, budgetType, budgetCategory, budgetNotes, client_id) # For update budget
# Pasamos las cantidades hacia el lado del cliente, de centimos(integer) a euros(float)
budgetAmountSubtotal_inEurs = round(
float(cents_to_eurs(budgetAmountSubtotal_inCents)), 2
)
budgetAmountTaxes_inEurs = round(
float(cents_to_eurs(budgetAmountTaxes_inCents)), 2
)
budgetAmountTotal_inEurs = round(
float(cents_to_eurs(budgetAmountTotal_inCents)), 2
)
# Aquí se debería emitir la señal budgetCreated (Lo que se envia al cliente)
self.budgetCreated.emit(
budgetId,
budgetName,
budgetAmountSubtotal_inEurs,
budgetAmountTaxes_inEurs,
budgetAmountTotal_inEurs,
budgetDate,
budgetDescription,
budgetStatus,
budgetType,
budgetCategory,
budgetNotes,
client_id,
)
# Clase para control de ventanas
class WindowManager(QObject):
def __init__(self, window):
super().__init__()
self.window = window
self.alwaysOnTop = True
# Funcion para mostrar siempre por encima de las demas ventanas
@Slot(bool)
def setAlwaysOnTop(self, on_top):
if on_top:
self.window.setFlags(
Qt.Window | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint
)
self.alwaysOnTop = True
else:
self.window.setFlags(Qt.Window | Qt.FramelessWindowHint)
self.alwaysOnTop = False
self.window.show()
# Boton que ejecuta la funcion setAlwaysOnTop()
@Slot()
def toggleAlwaysOnTop(self):
self.setAlwaysOnTop(not self.alwaysOnTop)
if __name__ == "__main__":
app = QGuiApplication(sys.argv)
app.setWindowIcon(QIcon("./images/anera_ico.ico"))
engine = QQmlApplicationEngine()
# CARGA DE CLASES:
# Carga la clase presupuestos
budget_manager = BudgetManager()
engine.rootContext().setContextProperty("budgetObj", budget_manager)
# Carga la clase clientes
client_manager = ClientManager()
engine.rootContext().setContextProperty("clientObj", client_manager)
# Carga la clase Login
login_userdata = Login()
engine.rootContext().setContextProperty("loginUser", login_userdata)
# Carga la clase signUp
signup_userdata = signUp()
engine.rootContext().setContextProperty("signupUser", signup_userdata)
# ARRANCANDO MOTORES DE VENTANA
# engine.load(os.path.join(os.path.dirname(__file__), "test/Example2.qml")) # Borrar en Producccion, solo para pruebas
# engine.load(os.path.join(os.path.dirname(__file__), "qml/main.qml")) # Borrar en Producccion
engine.load(os.path.join(os.path.dirname(__file__), "qml/loginPage.qml"))
# ASIGNANDO a primera posicion VENTANA loginPage
login_window = engine.rootObjects()[0]
# Carga la clase WindowManager
window_manager = WindowManager(login_window)
engine.rootContext().setContextProperty("WindowManager", window_manager)
# FUNCION PARA CERRAR VENTANA
def close_login():
login_window.close()
# Connect the signal to the close function
login_window.loginSuccessful.connect(close_login)
# FUNCION PARA CERRAR VENTANA
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec_())
# Developed by David Castagneto