INSTITUTO DE CIENCIAS Y ESTUDIOS
SUPERIORES DE TAMAULIPAS A.C
GUILLERMO GEOVANNY RODRIGUEZ GONZALEZ
ALMACENAMIENTO DE FARMACOS
“PROGRAMACION ORIENTADA A OBJETOS”
1
INTRODUCCION
En la actualidad, la gestión eficiente de la información es un factor
determinante para el correcto funcionamiento de cualquier
organización, incluyendo establecimientos del sector salud como las
farmacias. El control manual de inventarios, proveedores y accesos
suele generar errores, pérdida de tiempo y dificultad para mantener los
datos actualizados y seguros.
Ante esta necesidad, se desarrolló un sistema informático de escritorio
orientado a la administración de una farmacia, el cual permite
gestionar de manera digital la información de los medicamentos
disponibles y de los proveedores encargados de su distribución,
además de contar con un módulo de control de acceso que garantiza
que solo usuarios autorizados puedan operar el sistema.
El presente documento tiene como finalidad describir el desarrollo de
dicho sistema, abordando su justificación, objetivos, alcance, así como
los aspectos técnicos y funcionales que lo conforman, con el propósito
de dar a conocer el proceso de diseño e implementación llevado a
cabo durante el proyecto.
2
INDICE
INTRODUCCION………………………………………. 2
DESCRIPCION………………………………………… 3
DIAGRAMA……………………………………………. 4
BASE DE DATOS……………………………………... 5-6
LISTADO DE CODIGOS……………………………… 7-9
PROYECTO FINAL……………………………………………. 11-33
3
DESCRIPCION DEL PROYECTO
El presente proyecto consiste en el desarrollo de un Sistema de
Farmacia mediante Python, utilizando la librería tkinter para la interfaz
gráfica y SQLite como motor de base de datos. El sistema tiene como
objetivo automatizar la gestión de información relacionada con los
medicamentos disponibles y los proveedores encargados de
suministrarlos, sustituyendo el manejo manual de estos datos por un
entorno digital, ordenado y de fácil acceso.
La aplicación cuenta con un módulo de acceso mediante usuario y
contraseña, que restringe el ingreso al sistema únicamente a personal
autorizado. Una vez dentro, el usuario puede acceder a dos módulos
principales: el de Medicamentos, donde es posible registrar, consultar,
modificar y dar de baja productos farmacéuticos; y el de Proveedores,
donde se administra la información de las empresas distribuidoras,
incluyendo su razón social, RFC, teléfono y correo de contacto.
Este proyecto fue desarrollado aplicando los principios de la
Programación Orientada a Objetos y buenas prácticas de diseño de
interfaces, con el fin de ofrecer una herramienta funcional, escalable y
de fácil mantenimiento.
4
DIAGRAMA DEL PROYECTO
MEDICAMENTOS {
int id_medicamento PK
string clave UK
string nombre
string presentacion
string concentracion
string unidad_medida
int stock_minimo
int activo
}
PROVEEDORES {
int id_proveedor PK
string razon_social
string rfc UK
string telefono
string correo
}
5
BASE DE DATOS
# Base de datos de usuarios permitidos (Usuario: Clave)
USUARIOS_REGISTRADOS = {
"admin": "admin123",
"user1": "clave1",
"user2": "clave2"
}
def conectar_db():
return [Link]("[Link]")
def inicializar_db():
conexion = conectar_db()
cursor = [Link]()
[Link]("""
CREATE TABLE IF NOT EXISTS Medicamentos (
id_medicamento INTEGER PRIMARY KEY AUTOINCREMENT,
clave TEXT NOT NULL UNIQUE,
nombre TEXT NOT NULL,
presentacion TEXT,
concentracion TEXT,
unidad_medida TEXT,
stock_minimo INTEGER,
activo INTEGER DEFAULT 1
)
""")
6
[Link]("""
CREATE TABLE IF NOT EXISTS Proveedores (
id_proveedor INTEGER PRIMARY KEY AUTOINCREMENT,
razon_social TEXT NOT NULL,
rfc TEXT UNIQUE,
telefono TEXT,
correo TEXT
7
LISTADO DE CODIGOS
[Link]("SELECT COUNT(*) FROM Medicamentos")
if [Link]()[0] == 0:
medicamentos = [
("MED001", "Paracetamol", "Tabletas", "500 mg", "Caja", 20, 1),
("MED002", "Ibuprofeno", "Cápsulas", "400 mg", "Caja", 15, 1),
("MED003", "Amoxicilina", "Cápsulas", "500 mg", "Caja", 10, 1),
("MED004", "Loratadina", "Tabletas", "10 mg", "Caja", 12, 1),
("MED005", "Omeprazol", "Cápsulas", "20 mg", "Caja", 18, 1),
("MED006", "Diclofenaco", "Tabletas", "50 mg", "Caja", 15, 1),
("MED007", "Metformina", "Tabletas", "850 mg", "Caja", 20, 1),
("MED008", "Losartán", "Tabletas", "50 mg", "Caja", 25, 1),
("MED009", "Vitamina C", "Tabletas efervescentes", "1 g", "Caja", 30, 1),
("MED010", "Jarabe para la tos", "Jarabe", "120 ml", "Frasco", 10, 1)
[Link]("""
INSERT INTO Medicamentos (clave, nombre, presentacion, concentracion,
unidad_medida, stock_minimo, activo)
VALUES (?, ?, ?, ?, ?, ?, ?)
""", medicamentos)
[Link]("SELECT COUNT(*) FROM Proveedores")
if [Link]()[0] == 0:
proveedores = [
("Farmacias del Norte", "FAN123456ABC", "8331234567",
"contacto@[Link]"),
8
("Medicamentos SA", "MED987654XYZ", "8337654321",
"ventas@[Link]"),
("Distribuidora Salud", "DIS456789QWE", "8331112233",
"info@[Link]")
]
[Link]("""
INSERT INTO Proveedores (razon_social, rfc, telefono, correo)
VALUES (?, ?, ?, ?)
""", proveedores)
[Link]()
[Link]()
9
import sqlite3
import tkinter as tk
from tkinter import messagebox, ttk
# Base de datos de usuarios permitidos (Usuario: Clave)
USUARIOS_REGISTRADOS = {
"admin": "admin123",
"user1": "clave1",
"user2": "clave2"
# Variable global de control de acceso
acceso_concedido = False
# ==========================================
# PALETA DE COLORES SIMPLIFICADA
# ==========================================
COLOR_FONDO = "#F5F5F5"
COLOR_TEXTO = "#333333"
COLOR_BOTON = "#4A4A4A"
COLOR_BOTON_TEXTO = "#FFFFFF"
COLOR_ACENTO = "#5C6BC0"
FUENTE_TITULO = ("Segoe UI", 14, "bold")
FUENTE_NORMAL = ("Segoe UI", 10)
10
BASE DE DATOS Y CONFIGURACIÓN
def conectar_db():
return [Link]("[Link]")
def inicializar_db():
conexion = conectar_db()
cursor = [Link]()
[Link]("""
CREATE TABLE IF NOT EXISTS Medicamentos (
id_medicamento INTEGER PRIMARY KEY AUTOINCREMENT,
clave TEXT NOT NULL UNIQUE,
nombre TEXT NOT NULL,
presentacion TEXT,
concentracion TEXT,
unidad_medida TEXT,
stock_minimo INTEGER,
activo INTEGER DEFAULT 1
""")
[Link]("""
CREATE TABLE IF NOT EXISTS Proveedores (
id_proveedor INTEGER PRIMARY KEY AUTOINCREMENT,
razon_social TEXT NOT NULL,
11
rfc TEXT UNIQUE,
telefono TEXT,
correo TEXT
""")
# Carga inicial solo si la tabla está vacía
[Link]("SELECT COUNT(*) FROM Medicamentos")
if [Link]()[0] == 0:
medicamentos = [
("MED001", "Paracetamol", "Tabletas", "500 mg", "Caja", 20, 1),
("MED002", "Ibuprofeno", "Cápsulas", "400 mg", "Caja", 15, 1),
("MED003", "Amoxicilina", "Cápsulas", "500 mg", "Caja", 10, 1),
("MED004", "Loratadina", "Tabletas", "10 mg", "Caja", 12, 1),
("MED005", "Omeprazol", "Cápsulas", "20 mg", "Caja", 18, 1),
("MED006", "Diclofenaco", "Tabletas", "50 mg", "Caja", 15, 1),
("MED007", "Metformina", "Tabletas", "850 mg", "Caja", 20, 1),
("MED008", "Losartán", "Tabletas", "50 mg", "Caja", 25, 1),
("MED009", "Vitamina C", "Tabletas efervescentes", "1 g", "Caja", 30, 1),
("MED010", "Jarabe para la tos", "Jarabe", "120 ml", "Frasco", 10, 1)
[Link]("""
INSERT INTO Medicamentos (clave, nombre, presentacion, concentracion,
unidad_medida, stock_minimo, activo)
VALUES (?, ?, ?, ?, ?, ?, ?)
""", medicamentos)
12
[Link]("SELECT COUNT(*) FROM Proveedores")
if [Link]()[0] == 0:
proveedores = [
("Farmacias del Norte", "FAN123456ABC", "8331234567",
"contacto@[Link]"),
("Medicamentos SA", "MED987654XYZ", "8337654321",
"ventas@[Link]"),
("Distribuidora Salud", "DIS456789QWE", "8331112233",
"info@[Link]")
[Link]("""
INSERT INTO Proveedores (razon_social, rfc, telefono, correo)
VALUES (?, ?, ?, ?)
""", proveedores)
[Link]()
[Link]()
# ==========================================
# MÓDULO DE MEDICAMENTOS (CRUD COMPLETO)
# ==========================================
def abrir_ventana_medicamentos():
ventana = [Link]()
[Link]("Gestión de Medicamentos")
[Link]("750x550")
[Link](bg=COLOR_FONDO)
13
[Link](ventana, text="Gestión de Medicamentos", font=FUENTE_TITULO,
bg=COLOR_FONDO, fg=COLOR_TEXTO).pack(pady=10)
# --- BÚSQUEDA ---
frame_busqueda = [Link](ventana, bg=COLOR_FONDO)
frame_busqueda.pack(fill=tk.X, padx=15, pady=5)
[Link](frame_busqueda, text="Buscar (Nombre/Clave):",
bg=COLOR_FONDO, fg=COLOR_TEXTO,
font=FUENTE_NORMAL).pack(side=[Link], padx=5)
entry_buscar = [Link](frame_busqueda, width=25, font=FUENTE_NORMAL)
entry_buscar.pack(side=[Link], padx=5)
def cargar_datos(filtro=""):
for fila in tabla.get_children():
[Link](fila)
conexion = conectar_db()
cursor = [Link]()
if filtro:
query = "SELECT id_medicamento, clave, nombre, presentacion,
concentracion FROM Medicamentos WHERE activo = 1 AND (nombre LIKE ? OR
clave LIKE ?)"
[Link](query, (f"%{filtro}%", f"%{filtro}%"))
else:
[Link]("SELECT id_medicamento, clave, nombre, presentacion,
concentracion FROM Medicamentos WHERE activo = 1")
for m in [Link]():
14
[Link]("", [Link], values=m)
[Link]()
btn_buscar = [Link](frame_busqueda, text="Buscar", bg=COLOR_BOTON,
fg=COLOR_BOTON_TEXTO, font=FUENTE_NORMAL, relief="flat",
command=lambda: cargar_datos(entry_buscar.get()))
btn_buscar.pack(side=[Link], padx=5)
btn_reset = [Link](frame_busqueda, text="Mostrar Todos",
bg=COLOR_FONDO, fg=COLOR_TEXTO, font=FUENTE_NORMAL, relief="flat",
command=lambda: [entry_buscar.delete(0, [Link]), cargar_datos()])
btn_reset.pack(side=[Link], padx=5)
# --- TABLA ---
columnas = ("id", "clave", "nombre", "presentacion", "concentracion")
tabla = [Link](ventana, columns=columnas, show="headings", height=10)
[Link]("id", text="ID")
[Link]("clave", text="Clave")
[Link]("nombre", text="Nombre")
[Link]("presentacion", text="Presentación")
[Link]("concentracion", text="Concentración")
[Link]("id", width=40, anchor="center")
[Link]("clave", width=80)
[Link]("nombre", width=180)
[Link]("presentacion", width=130)
[Link]("concentracion", width=100)
[Link](fill=[Link], expand=True, padx=15, pady=10)
15
# --- FORMULARIO Y BOTONES CRUD ---
frame_formulario = [Link](ventana, bg=COLOR_FONDO)
frame_formulario.pack(pady=10)
[Link](frame_formulario, text="Clave:", bg=COLOR_FONDO,
fg=COLOR_TEXTO, font=FUENTE_NORMAL).grid(row=0, column=0, padx=5,
pady=2)
entry_clave = [Link](frame_formulario, width=15, font=FUENTE_NORMAL)
entry_clave.grid(row=0, column=1, padx=5, pady=2)
[Link](frame_formulario, text="Nombre:", bg=COLOR_FONDO,
fg=COLOR_TEXTO, font=FUENTE_NORMAL).grid(row=0, column=2, padx=5,
pady=2)
entry_nombre = [Link](frame_formulario, width=20, font=FUENTE_NORMAL)
entry_nombre.grid(row=0, column=3, padx=5, pady=2)
[Link](frame_formulario, text="Presentación:", bg=COLOR_FONDO,
fg=COLOR_TEXTO, font=FUENTE_NORMAL).grid(row=1, column=0, padx=5,
pady=2)
entry_pres = [Link](frame_formulario, width=15, font=FUENTE_NORMAL)
entry_pres.grid(row=1, column=1, padx=5, pady=2)
[Link](frame_formulario, text="Concentración:", bg=COLOR_FONDO,
fg=COLOR_TEXTO, font=FUENTE_NORMAL).grid(row=1, column=2, padx=5,
pady=2)
entry_conc = [Link](frame_formulario, width=20, font=FUENTE_NORMAL)
entry_conc.grid(row=1, column=3, padx=5, pady=2)
def agregar():
16
clave, nombre = entry_clave.get().strip(), entry_nombre.get().strip()
if not clave or not nombre:
[Link]("Atención", "La clave y el nombre son
obligatorios.", parent=ventana)
return
try:
conexion = conectar_db()
cursor = [Link]()
[Link]("INSERT INTO Medicamentos (clave, nombre,
presentacion, concentracion, activo) VALUES (?, ?, ?, ?, 1)",
(clave, nombre, entry_pres.get().strip(), entry_conc.get().strip()))
[Link]()
[Link]()
[Link]("Éxito", "Medicamento agregado correctamente.",
parent=ventana)
limpiar_formulario()
cargar_datos()
except [Link]:
[Link]("Error", "La clave ingresada ya existe.",
parent=ventana)
def modificar():
seleccion = [Link]()
if not seleccion:
[Link]("Atención", "Selecciona un registro de la tabla
para modificar.", parent=ventana)
return
id_med = [Link](seleccion[0])['values'][0]
try:
17
conexion = conectar_db()
cursor = [Link]()
[Link]("UPDATE Medicamentos SET clave=?, nombre=?,
presentacion=?, concentracion=? WHERE id_medicamento=?",
(entry_clave.get().strip(), entry_nombre.get().strip(),
entry_pres.get().strip(), entry_conc.get().strip(), id_med))
[Link]()
[Link]()
[Link]("Éxito", "Medicamento modificado correctamente.",
parent=ventana)
limpiar_formulario()
cargar_datos()
except [Link] as e:
[Link]("Error", f"No se pudo modificar: {e}",
parent=ventana)
def eliminar():
seleccion = [Link]()
if not seleccion:
[Link]("Atención", "Selecciona un registro para
eliminar.", parent=ventana)
return
id_med = [Link](seleccion[0])['values'][0]
if [Link]("Confirmar", "¿Seguro que deseas eliminar este
medicamento?", parent=ventana):
conexion = conectar_db()
cursor = [Link]()
[Link]("UPDATE Medicamentos SET activo = 0 WHERE
id_medicamento = ?", (id_med,))
18
[Link]()
[Link]()
cargar_datos()
limpiar_formulario()
def al_seleccionar(event):
seleccion = [Link]()
if seleccion:
item = [Link](seleccion[0])['values']
limpiar_formulario()
entry_clave.insert(0, item[1])
entry_nombre.insert(0, item[2])
entry_pres.insert(0, item[3])
entry_conc.insert(0, item[4])
def limpiar_formulario():
entry_clave.delete(0, [Link])
entry_nombre.delete(0, [Link])
entry_pres.delete(0, [Link])
entry_conc.delete(0, [Link])
[Link]("<<TreeviewSelect>>", al_seleccionar)
# Botones de Acción
frame_botones = [Link](ventana, bg=COLOR_FONDO)
frame_botones.pack(pady=10)
19
[Link](frame_botones, text="Agregar", bg=COLOR_BOTON,
fg=COLOR_BOTON_TEXTO, font=FUENTE_NORMAL, relief="flat", width=12,
command=agregar).pack(side=[Link], padx=5)
[Link](frame_botones, text="Modificar", bg=COLOR_BOTON,
fg=COLOR_BOTON_TEXTO, font=FUENTE_NORMAL, relief="flat", width=12,
command=modificar).pack(side=[Link], padx=5)
[Link](frame_botones, text="Eliminar", bg=COLOR_BOTON,
fg=COLOR_BOTON_TEXTO, font=FUENTE_NORMAL, relief="flat", width=12,
command=eliminar).pack(side=[Link], padx=5)
cargar_datos()
# ==========================================
# MÓDULO DE PROVEEDORES (CRUD COMPLETO)
# ==========================================
def abrir_ventana_proveedores():
ventana = [Link]()
[Link]("Gestión de Proveedores")
[Link]("750x550")
[Link](bg=COLOR_FONDO)
[Link](ventana, text="Gestión de Proveedores", font=FUENTE_TITULO,
bg=COLOR_FONDO, fg=COLOR_TEXTO).pack(pady=10)
# --- BÚSQUEDA ---
frame_busqueda = [Link](ventana, bg=COLOR_FONDO)
frame_busqueda.pack(fill=tk.X, padx=15, pady=5)
20
[Link](frame_busqueda, text="Buscar (Razón Social/RFC):",
bg=COLOR_FONDO, fg=COLOR_TEXTO,
font=FUENTE_NORMAL).pack(side=[Link], padx=5)
entry_buscar = [Link](frame_busqueda, width=25, font=FUENTE_NORMAL)
entry_buscar.pack(side=[Link], padx=5)
def cargar_datos(filtro=""):
for fila in tabla.get_children():
[Link](fila)
conexion = conectar_db()
cursor = [Link]()
if filtro:
query = "SELECT id_proveedor, razon_social, rfc, telefono, correo FROM
Proveedores WHERE razon_social LIKE ? OR rfc LIKE ?"
[Link](query, (f"%{filtro}%", f"%{filtro}%"))
else:
[Link]("SELECT id_proveedor, razon_social, rfc, telefono, correo
FROM Proveedores")
for p in [Link]():
[Link]("", [Link], values=p)
[Link]()
btn_buscar = [Link](frame_busqueda, text="Buscar", bg=COLOR_BOTON,
fg=COLOR_BOTON_TEXTO, font=FUENTE_NORMAL, relief="flat",
command=lambda: cargar_datos(entry_buscar.get()))
btn_buscar.pack(side=[Link], padx=5)
21
btn_reset = [Link](frame_busqueda, text="Mostrar Todos",
bg=COLOR_FONDO, fg=COLOR_TEXTO, font=FUENTE_NORMAL, relief="flat",
command=lambda: [entry_buscar.delete(0, [Link]), cargar_datos()])
btn_reset.pack(side=[Link], padx=5)
# --- TABLA ---
columnas = ("id", "razon_social", "rfc", "telefono", "correo")
tabla = [Link](ventana, columns=columnas, show="headings", height=10)
[Link]("id", text="ID")
[Link]("razon_social", text="Razón Social")
[Link]("rfc", text="RFC")
[Link]("telefono", text="Teléfono")
[Link]("correo", text="Correo")
[Link]("id", width=40, anchor="center")
[Link]("razon_social", width=180)
[Link]("rfc", width=110)
[Link]("telefono", width=100)
[Link]("correo", width=180)
[Link](fill=[Link], expand=True, padx=15, pady=10)
# --- FORMULARIO Y BOTONES CRUD ---
frame_formulario = [Link](ventana, bg=COLOR_FONDO)
frame_formulario.pack(pady=10)
22
[Link](frame_formulario, text="Razón Social:", bg=COLOR_FONDO,
fg=COLOR_TEXTO, font=FUENTE_NORMAL).grid(row=0, column=0, padx=5,
pady=2)
entry_razon = [Link](frame_formulario, width=20, font=FUENTE_NORMAL)
entry_razon.grid(row=0, column=1, padx=5, pady=2)
[Link](frame_formulario, text="RFC:", bg=COLOR_FONDO,
fg=COLOR_TEXTO, font=FUENTE_NORMAL).grid(row=0, column=2, padx=5,
pady=2)
entry_rfc = [Link](frame_formulario, width=15, font=FUENTE_NORMAL)
entry_rfc.grid(row=0, column=3, padx=5, pady=2)
[Link](frame_formulario, text="Teléfono:", bg=COLOR_FONDO,
fg=COLOR_TEXTO, font=FUENTE_NORMAL).grid(row=1, column=0, padx=5,
pady=2)
entry_tel = [Link](frame_formulario, width=20, font=FUENTE_NORMAL)
entry_tel.grid(row=1, column=1, padx=5, pady=2)
[Link](frame_formulario, text="Correo:", bg=COLOR_FONDO,
fg=COLOR_TEXTO, font=FUENTE_NORMAL).grid(row=1, column=2, padx=5,
pady=2)
entry_correo = [Link](frame_formulario, width=20, font=FUENTE_NORMAL)
entry_correo.grid(row=1, column=3, padx=5, pady=2)
def agregar():
razon = entry_razon.get().strip()
if not razon:
[Link]("Atención", "La razón social es obligatoria.",
parent=ventana)
return
23
try:
conexion = conectar_db()
cursor = [Link]()
[Link]("INSERT INTO Proveedores (razon_social, rfc, telefono,
correo) VALUES (?, ?, ?, ?)",
(razon, entry_rfc.get().strip(), entry_tel.get().strip(),
entry_correo.get().strip()))
[Link]()
[Link]()
[Link]("Éxito", "Proveedor agregado correctamente.",
parent=ventana)
limpiar_formulario()
cargar_datos()
except [Link]:
[Link]("Error", "El RFC ingresado ya existe.",
parent=ventana)
def modificar():
seleccion = [Link]()
if not seleccion:
[Link]("Atención", "Selecciona un registro para
modificar.", parent=ventana)
return
id_prov = [Link](seleccion[0])['values'][0]
try:
conexion = conectar_db()
cursor = [Link]()
[Link]("UPDATE Proveedores SET razon_social=?, rfc=?,
telefono=?, correo=? WHERE id_proveedor=?",
24
(entry_razon.get().strip(), entry_rfc.get().strip(),
entry_tel.get().strip(), entry_correo.get().strip(), id_prov))
[Link]()
[Link]()
[Link]("Éxito", "Proveedor modificado correctamente.",
parent=ventana)
limpiar_formulario()
cargar_datos()
except [Link] as e:
[Link]("Error", f"No se pudo modificar: {e}",
parent=ventana)
def eliminar():
seleccion = [Link]()
if not seleccion:
[Link]("Atención", "Selecciona un registro para
eliminar.", parent=ventana)
return
id_prov = [Link](seleccion[0])['values'][0]
if [Link]("Confirmar", "¿Seguro que deseas eliminar este
proveedor?", parent=ventana):
conexion = conectar_db()
cursor = [Link]()
[Link]("DELETE FROM Proveedores WHERE id_proveedor = ?",
(id_prov,))
[Link]()
[Link]()
cargar_datos()
limpiar_formulario()
25
def al_seleccionar(event):
seleccion = [Link]()
if seleccion:
item = [Link](seleccion[0])['values']
limpiar_formulario()
entry_razon.insert(0, item[1])
entry_rfc.insert(0, item[2])
entry_tel.insert(0, str(item[3]))
entry_correo.insert(0, item[4])
def limpiar_formulario():
entry_razon.delete(0, [Link])
entry_rfc.delete(0, [Link])
entry_tel.delete(0, [Link])
entry_correo.delete(0, [Link])
[Link]("<<TreeviewSelect>>", al_seleccionar)
# Botones de Acción
frame_botones = [Link](ventana, bg=COLOR_FONDO)
frame_botones.pack(pady=10)
[Link](frame_botones, text="Agregar", bg=COLOR_BOTON,
fg=COLOR_BOTON_TEXTO, font=FUENTE_NORMAL, relief="flat", width=12,
command=agregar).pack(side=[Link], padx=5)
26
[Link](frame_botones, text="Modificar", bg=COLOR_BOTON,
fg=COLOR_BOTON_TEXTO, font=FUENTE_NORMAL, relief="flat", width=12,
command=modificar).pack(side=[Link], padx=5)
[Link](frame_botones, text="Eliminar", bg=COLOR_BOTON,
fg=COLOR_BOTON_TEXTO, font=FUENTE_NORMAL, relief="flat", width=12,
command=eliminar).pack(side=[Link], padx=5)
cargar_datos()
# ==========================================
# VENTANA ACCESO (LOGIN)
# ==========================================
def centrar_ventana(ventana, ancho, alto):
ventana.update_idletasks()
ancho_pantalla = ventana.winfo_screenwidth()
alto_pantalla = ventana.winfo_screenheight()
x = (ancho_pantalla - ancho) // 2
y = (alto_pantalla - alto) // 2
[Link](f"{ancho}x{alto}+{x}+{y}")
def iniciar_modulo_login():
global acceso_concedido
def validar_acceso():
global acceso_concedido
27
usuario = entry_usuario.get().strip()
clave = entry_clave.get().strip()
# Validación con el diccionario de usuarios
if usuario in USUARIOS_REGISTRADOS and
USUARIOS_REGISTRADOS[usuario] == clave:
acceso_concedido = True
[Link]("Acceso", f"Bienvenido, {usuario}.",
parent=ventana_login)
ventana_login.destroy()
else:
[Link]("Acceso denegado", "Usuario o clave incorrectos.",
parent=ventana_login)
def abrir_ventana_restablecer():
[Link](
"Restablecer Contraseña",
"Para restablecer la contraseña, contacta al administrador.",
parent=ventana_login
ventana_login = [Link]()
ventana_login.title("Acceso")
centrar_ventana(ventana_login, 300, 220)
ventana_login.resizable(False, False)
ventana_login.configure(bg=COLOR_FONDO)
28
lbl_acceso = [Link](ventana_login, text="ACCESO", font=FUENTE_TITULO,
bg=COLOR_FONDO, fg=COLOR_TEXTO)
lbl_acceso.pack(pady=10)
frame_login = [Link](ventana_login, bg=COLOR_FONDO)
frame_login.pack()
[Link](frame_login, text="Usuario:", bg=COLOR_FONDO,
fg=COLOR_TEXTO, font=FUENTE_NORMAL).grid(row=0, column=0, padx=5,
pady=5, sticky="e")
entry_usuario = [Link](frame_login, width=20, font=FUENTE_NORMAL)
entry_usuario.grid(row=0, column=1, padx=5, pady=5)
[Link](frame_login, text="Clave:", bg=COLOR_FONDO, fg=COLOR_TEXTO,
font=FUENTE_NORMAL).grid(row=1, column=0, padx=5, pady=5, sticky="e")
entry_clave = [Link](frame_login, width=20, show="*",
font=FUENTE_NORMAL)
entry_clave.grid(row=1, column=1, padx=5, pady=5)
btn_aceptar = [Link](ventana_login, text="Aceptar", width=12,
command=validar_acceso, bg=COLOR_BOTON, fg=COLOR_BOTON_TEXTO,
font=FUENTE_NORMAL, relief="flat")
btn_aceptar.pack(pady=5)
btn_restablecer = [Link](ventana_login, text="Restablecer Contraseña",
width=20, command=abrir_ventana_restablecer, bg=COLOR_FONDO,
fg=COLOR_ACENTO, font=FUENTE_NORMAL, relief="flat")
btn_restablecer.pack(pady=5)
ventana_login.bind('<Return>', lambda event: validar_acceso())
29
ventana_login.mainloop()
# ==========================================
# MENÚ PRINCIPAL
# ==========================================
def crear_menu_principal():
inicializar_db()
ventana_principal = [Link]()
ventana_principal.title("Sistema de Farmacia - Menú Principal")
ventana_principal.geometry("400x300")
centrar_ventana(ventana_principal, 400, 300)
ventana_principal.resizable(False, False)
ventana_principal.configure(bg=COLOR_FONDO)
[Link](ventana_principal, text="SISTEMA DE FARMACIA",
font=FUENTE_TITULO, bg=COLOR_FONDO, fg=COLOR_TEXTO,
pady=20).pack()
[Link](
ventana_principal, text="Medicamentos", font=FUENTE_NORMAL,
width=20, height=2, bg=COLOR_BOTON, fg=COLOR_BOTON_TEXTO,
relief="flat",
command=abrir_ventana_medicamentos
).pack(pady=8)
[Link](
30
ventana_principal, text="Proveedores", font=FUENTE_NORMAL,
width=20, height=2, bg=COLOR_BOTON, fg=COLOR_BOTON_TEXTO,
relief="flat",
command=abrir_ventana_proveedores
).pack(pady=8)
[Link](
ventana_principal, text="Salir", font=FUENTE_NORMAL,
width=20, bg=COLOR_FONDO, fg=COLOR_TEXTO, relief="flat",
command=ventana_principal.destroy
).pack(pady=15)
ventana_principal.mainloop()
# ==========================================
# PUNTO DE ENTRADA
# ==========================================
if __name__ == "__main__":
iniciar_modulo_login()
# Solo abre la aplicación si el login fue exitoso
if acceso_concedido:
crear_menu_principal()
31
32
33