Gestión de clientes en Veterinaria.

Bienvenidos a esta nueva practica en donde vamos a crear una aplicación de consola en PYTHON que nos servirá de aplicación de gestión de clientes en una clínica veterinaria. Esta gestión la podrás modificar y adaptar a tus necesidades.

Esta aplicación de gestión es una aplicación sencilla de gestión de clientes en los que se identificarán por su nombre y DNI y que, además estarán asciados los nombres de su mascota yla raza de la misma.

Las operciones que podrás realizar sobre la aplicación son:

● Alta de nuevo usuario.
● Baja del cliente.
● Modificación de sus datos.
● Consultas individuales.
● Consultas generales.
● Guardar.
● Salir de la aplicación.

Utilizaremos una clase principal en un archivo llamado clases.py que tendrá las clases que usaremos en nuestra aplicación. Y desde otro archivo llamado gestion_clientes.py, llamaremos y crearemos la estructura de la aplicación.

Archivo de clases.

Para representar a los clientes empezaremos creando en el archivo clases.py tres clases principales: Persona, Perro y una tercera clase que va a estar heredada de la primera clase Persona, y que llamaremos Cliente.

Será en esta clase Clientes donde llamaremos a sus propiedades para que nos devuelva los datos del cliente y su mascota.

Archivo principal clases.py.
Ya sabes que puedes usar el editor que prefieras, y yo voy a usar el VSCode porque me resulta muy cómodo su uso. Ya sabes que tienes que hacer, crear un nuevo directorio en tu escritorio y después entras desde tu VSCode a dicho directorio para que sirva como raíz del proyecto. Ahí crearás el nuevo archivo llamado clases.py.

Directorio de raíz principal de la aplicación de gestoria de clientes

Vamos a empezar creando la clase Persona. Del cliente necesitamos solo dos datos (para no hacer la aplicación muy grande); el Nombre y el DNI. Por lo tanto, al crear la clase Persona tendrá esta estructura:

class Persona:
    def __init__(self, nombre, dni):
        self.nombre = nombre
        self.dni = dni

De la clase Perro, también necesitaremos dos datos, el nombre y la raza del perro, por lo que la clase quedará:

class Perro:
    def __init__(self, nombre, raza):
        self.nombre = nombre
        self.raza = raza

Por último la clase Cliente debe de incluir a la clase Persona y al nombre del perro por lo que quedaría así:

class Cliente(Persona):
    def __init__(self, nombre, dni, perro):
        Persona.__init__(self, nombre, dni)
        self.perro = perro

Es importante que te fijes que desde la clase Cliente estoy llamando a la clase padre de Persona, y a sus atributos nombre y dni. Y además también instancio a perro.

Guarda el archivo clases.py y ahora podemos empezar con el otro archivo llamado gestion_clientes.py, que será donde actuemos sobre los datos para guardarlos y consultarlos.

Archivos de gestión de clientes.

Desde éste archivo vamos a empezar a utilizar las propiedades que hemos declarado en el anterior archivo. Basicamente lo que haré es crear una función para cada acción del programa: una función para mostrar el menú, otra función para guardar los datos, etc., etc.

Pero primero hay que importar las propiedades de las clases importando el archivo anterior.

import clases

Así unicamente importamos todas las clases y sus funciones (si las tuviese), de cada clase. Pero además necesitaremos importar otras librerías como el os, y el pickle que nos servirán para cargar y guardar los datos de la aplicación.

import clases
import os
import pickle

Formato de archivo.
Ya tienes que tener claro que cuando creamos una aplicación de PYTHON, generalmente necesitamos tener una forma de persistencia de datos. En este caso me decanto por guardar los datos en un formato binario (por eso importo la librería pickle). Además cuando creamos un formato de tipo binario, en un primer uso de la aplicación, deberá de comprobar si el archivo existe o no existe. Si no existe deberá de crear el archivo. El código que lo hace posible es:

fichero_clientes = "clientes.pkl"
datos_modificados = False
lista_clientes = []
if os.path.exists(fichero_clientes):
    with open(fichero_clientes, 'rb') as f:
        lista_clientes = pickle.load(f)

El código anterior muestra las variables globales que vamos a utilizar como por ejemplo la variable fichero_clientes que designa el nombre y tipo de archivo que vamos a crear. La siguiente datos_modificados, se utiliza para saber si hay cambios en los datos del cliente (por eso se pone a False). Cuando se modifique algún valor del cliente pasará a True. La variable lista_clientes[] almacenará la lista de objetos Cliente con la que, originalmente vacía, se va a trabajar.

Con el método exits(), de os.path, estamos comprobando que el archivo de soporte de datos exista. Si existe lo abriremos con un identificador f, y en un modo 'rb' que implica que será una operació de lectura (read), sobre un archivo binario (binary). Por eso utilizamos un método load() y dump(), que se usan en el módulo pickle. Si no existe, la estructura condicional lo creará cuando guardemos el proyecto.

Funciones del programa.

Vamos a empezar con las funciones de presentación del sistema. Para ello, la más básica es que nos muestra el menú de opciones.

def mostrar_opciones():
    print("\n")
    print("1- ALTA")
    print("2- BAJA")
    print("3- MODIFICACIÓN")
    print("4- CONSULTA_CLIENTE")
    print("5- CONSULTA GLOBAL")
    print("6- GUARDAR")
    print("7- SALIR")
    print("8- LADRAR")
    opcion = int(input("Introduzca una opción: "))
    print("\n")
return opcion

Empezaremos a crear las funciones en orden de presentación según el menú de mostrar_opciones().

alta_cliente()
Esta función nos facilitará el alta de un nuevo cliente. En la primera línea se declara una variable global datos_modificados que nos servirá para conocer si existe un cliente o no.

def alta_cliente():
    global datos_modificados
    print("Por favor introduzca los siguientes datos:")
    dni =input("DNI: ")
    if obtener_cliente(dni)==None:
        nombre_cliente = input("Nombre del cliente: ")
        nombre_perro = input("Nombre del perro: ")
        raza = input("Raza: ")
        perro = clases.Perro(nombre_perro, raza)
        cliente = clases.Cliente(nombre_cliente, dni, perro)
        lista_clientes.append(cliente) print("Cliente dado de alta!!")
        datos_modificados=True
    else:
        print("Ya existe un cliente con el DNI " + dni + "-------")

Para dar de alta al cliente necesitamos proporcionar un nombre y un DNI de dicho cliente. Como no queremos que se repita un mismo cliente, si introducimos un DNI que ya esté en nuestro archivo dentro de la variable fichero_clientes, aparecerá un mensaje de que dicho cliente ya existe. Si no existe, entonces podremos guardar dicho cliente cargando la estructura condicional del IF, pidiendo introducir los datos del cliente y que, por defecto cogerá valores alfanuméricos. El registro se introducirá con la instrucción lista_clientes.append(cliente), a la par que modificaremos el valor de datos_modificados al pasarlo a True.

baja()
También se declara una variable global datos_modificados=False. En esta función se da el caso contrario al anterior: si no existe el usuario no se podrá eliminar y aparecerá un mensaje correspondiente a la acción. En caso contrario, la condición ELSE, utiliza el método remove(), para eliminarlo del archivo de clientes.

def baja_cliente():
    global datos_modificados
    dni = input("DNI del cliente a dar de baja: ")
    cliente = obtener_cliente(dni)
    if cliente == None:
        print("----El cliente con DNI " + dni + ", no existe----")
    else:
        lista_clientes.remove(cliente)
        print("---CLIENTE BORRADO---")
        datos_modificados = True

Modificación del cliente.
Esta función es una función que seencarga de modificar los datos del cliente dado de alta. En dicha función lo primero que se hace es declarar la variable global datos_modificados para utilizar la configuración anterior el programa. Después preguntamos por el DNI del usuario con el fin de comprobar si existe el cliente o no existe. Y si existe, proceder a su modificación, pidiendo igual que en la función de alta, los datos del cliente en cuestión. Por eso utilizamos los condicionales con lógica negada. Para terminar, pasamos la variable global a True.

def modificacion_cliente():
    global datos_modificados
    dni = input("DNI del cliente a modificar? ")
    cliente = obtener_cliente(dni)
    if cliente==None:
        print("---El cliente con DNI " + dni + ", no existe-----")
    else:
        print("Por favor, rellena los siguientes datos:")
        nombre_cliente = input("Nombre del cliente: ")
        if nombre_cliente != "":
            cliente.nombre = nombre_cliente
            nombre_perro = input("Nombre del Perro: ")
        if nombre_perro != "":
            cliente.perro.nombre = nombre_perro
            raza = input("Tipo de raza: ")
        if raza != "":
            cliente.perro.raza = raza
        print("----CLIENTE MODIFICADO---")
        datos_modificados = True

Consulta de cliente.
Tanto para la consulta como las consultas de todos los clientes, se crean dos funciones que son sencillitas. Tenemos que, en la primera función llamar al cliente por su DNI y que nos muestre los datos correspondientes a dicho cliente. Sin embargo en la función general de clientes, lo que hago es crear una lista y cargar todos los clientes en esa lista, para después llamarla. Estas son las funciones:

def informacion_cliente():
    dni = input("Introduce el DNI del cliente a consultar: ")
    cliente = obtener_cliente(dni)
    if cliente ==None:
        print("----El cliente con DNI " + dni + ", no existe----")
    else:
        print("-----CLIENTE:-----" + "\nNombre: " + cliente.nombre + "\nDNI: " + cliente.dni + "\nNombre de perro: " + cliente.perro.nombre + "\nRaza: " + cliente.perro.raza)

def informacion_clientes():
    tabla = []
    for cliente in lista_clientes:
        print("-----CLIENTE:-----" + "\nNombre: " + cliente.nombre + "\nDNI: " + cliente.dni + "\nNombre de perro: " + cliente.perro.nombre + "\nRaza: " + cliente.perro.raza + "\n")
    pausa = input("Pulsa una letra para continuar")

Guardar.
Esta función se encargará de almacenar la lista de clientes actual en el fichero de clientes. Por eso utilizo la función open() en modo de escritura binaria (wb). Y eso lo creo dentro de una estructura condicional with usando un alias filestream. Aquí es donde utilizo la función dump(), del módulo pickle. Por último se asigna la variable global datos_modificados a False para que no nos pregunte si queremos guardar los cambios realizados (porque lo estamos haciendo explicitamente).

def guardar():
    global datos_modificados
    with open(fichero_clientes, 'wb') as filestream:
        pickle.dump(lista_clientes, filestream)
    print("Información del cliente guardada!")
    datos_modificados = False

Y con esto quedaría casi por finalizada la aplicación. Eso si, nos quedaría llamar a la función de mostrar opciones que podrías hacerlo con un bucle while y crear la estructura para el caso de que se pulse otro número se salga de la aplicación.

Menú principal.

Para la creación del menú es simple crear el menú que llamará a las funciones que hemos creado anteriormente. También he decidido guardar en cada acción de modificación o crear nuevo registro al nuevo cliente como puedes ver a continuación.

Creación de un menú con un bucle while

Como puedes ver el buble WHILE se asigna a TRUE para que se ejecute continuadamente. La variable opcion se asigna a la variable mostrar_opciones(), que si no te acuerdas era la variable que permitía cargar el menú principal. Cuando seleccionas un valor, se ejecutará la función definida en dicho valor.

Solo hay que comentar que, si realizamos cualquier cambio de la aplicación y salimos sin haberle pulsado el menú de guardar antes de salir, ejecutará el mensaje de que si queremos guardar los cambios. Se realiza esta forma para evitar que el usuario que modifica o cree un nuevo registro sin haberle dado a guardar previamente, se pueda realizar la acción antes de salir.

Bien espero que te hay gustado esta aplicación en la que has trabajado con orientación a objetos y has guardado datos en un archivo local. Ya te puedes descargar el proyecto de la aplicación en mi GITHUB.