Registrar nuevo cliente de sistema bancario en C - Solicitar datos y generar número de cuenta

Simular banco con C – Ejercicio resuelto

Hoy vamos a resolver un ejercicio en ANSI C, C o como lo conozcas. Se trata de simular un banco con usuarios, depósitos, retiros y administradores.

Vamos a usar archivos, structs, listas y varias cosas para este ejercicio de banco con C.

Entre las opciones tenemos el registro de usuarios, inicio de sesión, creación de administrador, inhabilitar usuarios, validar contraseñas, retirar, depositar, transferir entre usuarios, ver detalles de usuarios (incluyendo número de cuenta y saldo) entre otros.

Descripción del ejercicio

Veamos lo que el programa solicita:

Simular banco con C

El Banco “Banco Parzibyte” requiere un Software diseñado en C capaz de realizar las siguientes tareas:

Se deberá mostrar en la pantalla inicial con tres opciones:

  1. Crear usuario
  2. Ingresar usuario
  3. Ingresar administrador

Creación de Usuario

Solicitar: Nombres, Identificación, Correo Electrónico y Contraseña. Validar:

  1. Que se escriban todos los datos
  2. Que el correo electrónico cumpla con el estándar example@example.com (debe llevar un @ y después un .)
  3. Que la contraseña sea alfanumérica (que contenga números y letras y debe ser mínimo de 8 caracteres, máximo de 12).

Crear: Número de cuenta de 10 cifras generado aleatoriamente. Todo cliente iniciara con un monto de $1000

Permitir al usuario realizar las siguientes acciones luego del Ingreso. El usuario ingresara con correo y la contraseña:

  1. Retirar: El Usuario podrá retirar dinero
  2. Depositar: El Usuario podrá Depositar dinero en su cuenta
  3. Transferir: Enviar dinero a otro Usuario existente (Por número de cuenta)
  4. Detalles: Ver número de cuenta, saldo actual y nombre del Usuario.

Administrador

Existencia de un Usuario Administrador con las siguientes características:

Usuario: admin@ejemplo.com Clave: parz1byte (ya debe existir)

  1. Listar Usuarios: Este Usuario podrá ver los detalles de todas las cuentas creadas
  2. Inhabilitar / Habilitar: Podrá Inhabilitar o Habilitar un Usuario (Por número de cuenta)

Se deben almacenar los registros después de cerrar el programa, manejar archivos.

El usuario administrador debe estar guardado en el archivo para poder ingresar en cualquier momento.

Si un Usuario se encuentra Inhabilitado, no podrá ingresar a su menú.

Explicación del algoritmo

En este caso vamos a usar una cola como estructura de datos y vamos a leer archivos, ya sea para el administrador o para guardar y recuperar los usuarios.

Tendremos funciones separadas que harán un trabajo específico, por ejemplo la función que valida la contraseña o el correo electrónico.

Lo demás serán if, comprobaciones, solicitud de datos, implementación de menús, etcétera.

Administrador del banco

Administrador de sistema de banco programado con C
Administrador de sistema de banco programado con C

Para que el administrador del banco inicie sesión debemos leer el archivo que contiene las credenciales y colocar el contenido ya parseado en un struct:

int recuperarUsuarioAdministrador(struct Administrador *nodo)
{
    FILE *archivo = fopen(NOMBRE_ARCHIVO_ADMINISTRADOR, "r");
    if (archivo == NULL)
    {
        printf("No se pudo leer el archivo del administrador (%s)\n", NOMBRE_ARCHIVO_ADMINISTRADOR);
        return 0;
    }
    char bufer[MAXIMA_LONGITUD_CADENA]; // Aquí vamos a ir almacenando cada línea
    if (fgets(bufer, MAXIMA_LONGITUD_CADENA, archivo))
    {
        strtok(bufer, "\n");
        char *correo = strtok(bufer, DELIMITADOR_ADMINISTRADOR);
        char *palabraSecreta = strtok(NULL, DELIMITADOR_ADMINISTRADOR);
        strcpy(nodo->correo, correo);
        strcpy(nodo->palabraSecreta, palabraSecreta);
        return 1;
    }
    else
    {
        printf("El archivo de datos de administrador existe pero no tiene contenido\n");
        return 0;
    }
    fclose(archivo);
}

Ya después se puede autenticar, para ello solicitamos el correo y contraseña y comparamos con lo recuperado del archivo leído anteriormente.

Por cierto, en las funciones vamos a ir pasándonos varios apuntadores al administrador y a la lista de clientes o usuarios del banco en C:

int menuIngresarAdministrador(struct NodoDeCliente **apuntadorListaClientes, struct Administrador *administrador, struct Administrador *administradorExistente)
{
    char palabraSecreta[MAXIMA_LONGITUD_CADENA] = "";
    char correoElectronico[MAXIMA_LONGITUD_CADENA] = "";
    leerCorreoElectronico(correoElectronico);
    leerPalabraSecreta(palabraSecreta);
    int ok = iniciarSesionAdministrador(&administrador, administradorExistente, correoElectronico, palabraSecreta);
    if (!ok)
    {
        printf("Correo o palabra secreta incorrectos\n");
    }
    else
    {
        printf("Bienvenido, %s\n", administrador->correo);
        menuAdministrador(apuntadorListaClientes, administrador, administradorExistente);
    }
    return ok;
}

Por cierto, el struct del administrador queda así:

struct Administrador
{
    char correo[MAXIMA_LONGITUD_CADENA];
    char palabraSecreta[MAXIMA_LONGITUD_CADENA];
};

Crear cliente

Registrar nuevo cliente de sistema bancario en C - Solicitar datos y generar número de cuenta
Registrar nuevo cliente de sistema bancario en C – Solicitar datos y generar número de cuenta

Siguiendo con la solicitud de este ejercicio de programación en C vamos a ver cómo registrar un nuevo cliente.

En este caso solicitamos los datos necesarios, generamos el número de cuenta aleatorio y agregamos un nuevo nodo a la lista de clientes. Recordemos que la lista será en realidad una cola.

void menuCrearUsuario(struct NodoDeCliente **nodo)
{
    char nombre[MAXIMA_LONGITUD_CADENA] = "";
    char identificacion[MAXIMA_LONGITUD_CADENA] = "";
    char correoElectronico[MAXIMA_LONGITUD_CADENA] = "";
    char palabraSecreta[MAXIMA_LONGITUD_CADENA] = "";
    char numeroCuenta[MAXIMA_LONGITUD_CADENA] = "";
    leerCadenaYAsegurarseDeQueNoEstaVacia(nombre, "Ingrese el nombre: ");
    leerCadenaYAsegurarseDeQueNoEstaVacia(identificacion, "Ingrese la identificacion: ");
    leerCorreoElectronico(correoElectronico);
    leerPalabraSecreta(palabraSecreta);
    rellenarCadenaConNumerosAleatorios(numeroCuenta, CANTIDAD_CIFRAS_NUMERO_CUENTA);
    agregarNodoALista(nodo, nombre, identificacion, correoElectronico, palabraSecreta, numeroCuenta, SALDO_POR_DEFECTO, ESTADO_HABILITADO);
}

Si en algunos casos no se está esperando el resultado de la función es porque estamos pasando apuntadores, así las funciones no devuelven nada, mejor modifican los parámetros. Esto es casi obligatorio al menos para las cadenas.

Operaciones del cliente en el banco

Retirar, depositar, transferir y ver detalles de cuenta bancaria - Ejercicio resuelto con C
Retirar, depositar, transferir y ver detalles de cuenta bancaria – Ejercicio resuelto con C

Ya vimos cómo agregar clientes a este sistema de banco en C pero veamos cómo hacer que inicien sesión y además hagan operaciones como retiros, depósitos y transferencias.

Para todas las operaciones vamos a modificar un nodo de la lista de clientes. Es importante saber que esta lista se carga a la RAM desde el archivo al inicio del programa, y se guarda en el archivo al final.

Por eso es que basta con modificar la lista, ya que al final será guardada en el archivo y luego recuperada en el siguiente inicio, esto nos ahorra operaciones de archivos y hace el programa más rápido pues modifica directamente la memoria.

Iniciar sesión

Hacemos lo mismo que para el administrador, pero en este caso lee la lista completa, compara el correo de cada cliente hasta encontrarlo y luego verifica las credenciales.

/*
    Recibe un apuntador a un apuntador de un NodoDeCliente en donde se desea colocar el usuario logueado, el inicio de la lista de clientes, el correo y la contraseña
    Regresa 1 o 0 indicando si el correo y la contraseña coinciden.
    Además, en caso de que el inicio de sesión sea correcto pondrá el usuario logueado en usuarioLogueado
*/
int iniciarSesionUsuario(struct NodoDeCliente **usuarioLogueado, struct NodoDeCliente *nodo, char *correoElectronico, char *palabraSecreta)
{
    while (nodo != NULL)
    {
        if (strcmp(nodo->correoElectronico, correoElectronico) == 0 && strcmp(nodo->palabraSecreta, palabraSecreta) == 0)
        {
            if (nodo->habilitado == ESTADO_DESHABILITADO)
            {
                printf("Credenciales correctas, pero el usuario esta deshabilitado\n");
                return 0;
            }
            *usuarioLogueado = nodo;
            return 1;
        }
        nodo = nodo->siguiente;
    }
    return 0;
}
int menuIngresarUsuario(struct NodoDeCliente **apuntadorListaClientes, struct NodoDeCliente *clienteLogueado)
{
    char palabraSecreta[MAXIMA_LONGITUD_CADENA] = "";
    char correoElectronico[MAXIMA_LONGITUD_CADENA] = "";
    leerCorreoElectronico(correoElectronico);
    leerPalabraSecreta(palabraSecreta);
    int ok = iniciarSesionUsuario(&clienteLogueado, *apuntadorListaClientes, correoElectronico, palabraSecreta);
    if (!ok)
    {
        printf("Correo o palabra secreta incorrectos\n");
    }
    else
    {
        printf("Bienvenido, %s\n", clienteLogueado->nombre);
        menuUsuario(apuntadorListaClientes, clienteLogueado);
    }
    return ok;
}

Por cierto, aquí también se verifica si el cliente ha sido deshabilitado por el administrador.

Retirar y depositar dinero

Este par de funciones me gustaron mucho, ya que basta con crear una que se puede usar para retirar y depositar solo cambiando el signo del número.

Por ejemplo, he programado únicamente la función de retirar dinero que busca dentro de la lista y en caso de encontrar resta el saldo.

int retirarDinero(struct NodoDeCliente *nodo, char *numeroCuenta, double cantidad)
{
    while (nodo != NULL)
    {
        if (strcmp(nodo->numeroCuenta, numeroCuenta) == 0)
        {
            if (nodo->saldo >= cantidad)
            {
                nodo->saldo = nodo->saldo - cantidad;
                return 1;
            }
            else
            {
                return 0;
            }
        }
        nodo = nodo->siguiente;
    }
    return 0;
}

int depositarDinero(struct NodoDeCliente *nodo, char *numeroCuenta, double cantidad)
{
    return retirarDinero(nodo, numeroCuenta, -cantidad);
}

Pero si te fijas, para le caso de depositar dinero simplemente invoco a la función que retira pero pasándole la cantidad negativa, así al restar algo negativo se vuelve positivo.

Nota: fíjate en que las funciones reciben un número de cuenta, así pueden usarse para cualquier cliente.

Transferir dinero

Esta función igualmente me gustó mucho porque solo vamos a invocar a las 2 funciones anteriores, cambiando obviamente el número de cuenta de origen y de destino.

Por lo tanto este sistema de simulación de banco con lenguaje C está usando métodos que ayudan a escribir poco código y reutilizarlo:

int transferirDinero(struct NodoDeCliente *nodo, char *cuentaOrigen, char *cuentaDestino, double cantidad)
{
    int retiroExitoso = retirarDinero(nodo, cuentaOrigen, cantidad);
    if (retiroExitoso)
    {
        depositarDinero(nodo, cuentaDestino, cantidad);
        return 1;
    }
    else
    {
        return 0;
    }
}

Con esto nos aseguramos de que todo esté validado, pues al transferir invocamos a la función que retira dinero, misma que verificará que no queden saldos negativos.

Detalles de cuenta y listado de usuarios

Ahora veamos 2 funciones que imprimen datos. La que lista los clientes simplemente recorre la estructura de datos nodo por nodo e imprime con printf en modo de tabla:

void listarUsuarios(struct NodoDeCliente *nodo)
{
    imprimirLineaSeparadora();
    printf("|%*s|%*s|%*s|%*s|%*s|%*s|%*s|\n",
           LONGITUD_TABLA, "Nombre", LONGITUD_TABLA, "Identificacion", LONGITUD_TABLA, "Correo", LONGITUD_TABLA, "Palabra secreta", LONGITUD_TABLA, "No. Cuenta", LONGITUD_TABLA, "Saldo", LONGITUD_TABLA, "Habilitado");
    imprimirLineaSeparadora();
    while (nodo != NULL)
    {
        printf("|%*s|%*s|%*s|%*s|%*s|%*lf|%*s|\n",
               LONGITUD_TABLA, nodo->nombre, LONGITUD_TABLA, nodo->identificacion, LONGITUD_TABLA, nodo->correoElectronico, LONGITUD_TABLA, nodo->palabraSecreta, LONGITUD_TABLA, nodo->numeroCuenta, LONGITUD_TABLA, nodo->saldo, LONGITUD_TABLA, nodo->habilitado == ESTADO_HABILITADO ? "Si" : "No");
        imprimirLineaSeparadora();
        nodo = nodo->siguiente;
    }
}

Y la que imprime los detalles de la cuenta del usuario es la siguiente:

void imprimirDetallesDeCuenta(struct NodoDeCliente *nodo, char *numeroCuenta)
{
    while (nodo != NULL)
    {
        if (strcmp(nodo->numeroCuenta, numeroCuenta) == 0)
        {
            printf("Detalles de cuenta\nNumero de cuenta: %s\nSaldo actual: %.2lf\nNombre: %s\n", nodo->numeroCuenta, nodo->saldo, nodo->nombre);
            return; // Encontramos al cliente. No necesitamos seguir buscando
        }
        nodo = nodo->siguiente;
    }
    printf("Cliente no encontrado\n");
}

En todos los casos recorremos toda la lista hasta encontrar al usuario. Si bien esto es un poco lento, nos ahorra memoria y funciones para obtener un apuntador a un usuario o cosas de esas.

Poniendo todo junto

Recuerda que debe existir el siguiente archivo con el mismo nombre y contenido en donde ejecutes el programa:

admin@ejemplo.com,parz1byte

Anteriormente te mostré las funciones más importantes para este sistema de banco en ANSI C, ahora veamos el código completo que incluye los métodos para solicitar datos, validar, etcétera.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <unistd.h>

#define MAXIMA_LONGITUD_CADENA 1000
#define NOMBRE_ARCHIVO_CLIENTES "clientes.txt"
#define NOMBRE_ARCHIVO_ADMINISTRADOR "administrador.txt"
#define DELIMITADOR_CLIENTES ","
#define DELIMITADOR_ADMINISTRADOR ","
#define ESTADO_HABILITADO 1
#define ESTADO_DESHABILITADO 0
#define LONGITUD_TABLA -18
#define SALDO_POR_DEFECTO 1000.00
#define CANTIDAD_CIFRAS_NUMERO_CUENTA 10

struct NodoDeCliente
{
    char nombre[MAXIMA_LONGITUD_CADENA];
    char identificacion[MAXIMA_LONGITUD_CADENA];
    char correoElectronico[MAXIMA_LONGITUD_CADENA];
    char palabraSecreta[MAXIMA_LONGITUD_CADENA];
    char numeroCuenta[MAXIMA_LONGITUD_CADENA];
    double saldo;
    int habilitado;
    struct NodoDeCliente *siguiente;
};

struct Administrador
{
    char correo[MAXIMA_LONGITUD_CADENA];
    char palabraSecreta[MAXIMA_LONGITUD_CADENA];
};

void consumirNuevaLinea(void)
{
    int c;
    do
    {
        c = getchar();
    } while (c != EOF && c != '\n');
}

void agregarNodoALista(struct NodoDeCliente **nodo, char *nombre, char *identificacion, char *correoElectronico, char *palabraSecreta, char *numeroCuenta, double saldo, int habilitado)
{
    struct NodoDeCliente *nuevoNodo = malloc(sizeof(struct NodoDeCliente));
    strcpy(nuevoNodo->nombre, nombre);
    strcpy(nuevoNodo->identificacion, identificacion);
    strcpy(nuevoNodo->correoElectronico, correoElectronico);
    strcpy(nuevoNodo->palabraSecreta, palabraSecreta);
    strcpy(nuevoNodo->numeroCuenta, numeroCuenta);
    nuevoNodo->saldo = saldo;
    nuevoNodo->habilitado = habilitado;
    nuevoNodo->siguiente = NULL;
    if ((*nodo) == NULL)
    {
        *nodo = nuevoNodo;
    }
    else
    {
        agregarNodoALista(&(*nodo)->siguiente, nombre, identificacion, correoElectronico, palabraSecreta, numeroCuenta, saldo, habilitado);
    }
}

void imprimirLineaSeparadora()
{

    int i;
    for (i = 0; i < 7; i++)
    {
        printf("+");
        int x;
        for (x = 0; x < abs(LONGITUD_TABLA); x++)
        {
            printf("-");
        }
    }
    printf("+\n");
}

void listarUsuarios(struct NodoDeCliente *nodo)
{
    imprimirLineaSeparadora();
    printf("|%*s|%*s|%*s|%*s|%*s|%*s|%*s|\n",
           LONGITUD_TABLA, "Nombre", LONGITUD_TABLA, "Identificacion", LONGITUD_TABLA, "Correo", LONGITUD_TABLA, "Palabra secreta", LONGITUD_TABLA, "No. Cuenta", LONGITUD_TABLA, "Saldo", LONGITUD_TABLA, "Habilitado");
    imprimirLineaSeparadora();
    while (nodo != NULL)
    {
        printf("|%*s|%*s|%*s|%*s|%*s|%*lf|%*s|\n",
               LONGITUD_TABLA, nodo->nombre, LONGITUD_TABLA, nodo->identificacion, LONGITUD_TABLA, nodo->correoElectronico, LONGITUD_TABLA, nodo->palabraSecreta, LONGITUD_TABLA, nodo->numeroCuenta, LONGITUD_TABLA, nodo->saldo, LONGITUD_TABLA, nodo->habilitado == ESTADO_HABILITADO ? "Si" : "No");
        imprimirLineaSeparadora();
        nodo = nodo->siguiente;
    }
}

// Lee la lista de clientes y crea el archivo
void guardarLista(struct NodoDeCliente *nodo)
{
    FILE *archivo = fopen(NOMBRE_ARCHIVO_CLIENTES, "w");
    if (archivo == NULL)
    {
        printf("No se pudo abrir el archivo\n");
        return;
    }

    while (nodo != NULL)
    {
        fprintf(archivo, "%s%s%s%s%s%s%s%s%s%s%0.2lf%s%d\n",
                nodo->nombre,
                DELIMITADOR_CLIENTES,
                nodo->identificacion,
                DELIMITADOR_CLIENTES,
                nodo->correoElectronico,
                DELIMITADOR_CLIENTES,
                nodo->palabraSecreta,
                DELIMITADOR_CLIENTES,
                nodo->numeroCuenta,
                DELIMITADOR_CLIENTES,
                nodo->saldo,
                DELIMITADOR_CLIENTES,
                nodo->habilitado);
        nodo = nodo->siguiente;
    }
    fclose(archivo);
}

// Lee el archivo de texto y llena la lista de clientes
void recuperarLista(struct NodoDeCliente **nodo)
{
    FILE *archivo = fopen(NOMBRE_ARCHIVO_CLIENTES, "r");
    if (archivo == NULL)
    {
        // Fallar silenciosamente, tal vez es la primera ejecución y no hay clientes
        return;
    }
    char bufer[MAXIMA_LONGITUD_CADENA]; // Aquí vamos a ir almacenando cada línea
    double saldo = 0;
    while (fgets(bufer, MAXIMA_LONGITUD_CADENA, archivo))
    {
        strtok(bufer, "\n");
        char *nombre = strtok(bufer, DELIMITADOR_CLIENTES);
        char *identificacion = strtok(NULL, DELIMITADOR_CLIENTES);
        char *correoElectronico = strtok(NULL, DELIMITADOR_CLIENTES);
        char *palabraSecreta = strtok(NULL, DELIMITADOR_CLIENTES);
        char *numeroCuenta = strtok(NULL, DELIMITADOR_CLIENTES);
        char *saldoComoCadena = strtok(NULL, DELIMITADOR_CLIENTES);
        char *habilitadoComoCadena = strtok(NULL, DELIMITADOR_CLIENTES);
        sscanf(saldoComoCadena, "%lf", &saldo);
        int habilitado = strtol(habilitadoComoCadena, NULL, 10);
        agregarNodoALista(nodo, nombre, identificacion, correoElectronico, palabraSecreta, numeroCuenta, saldo, habilitado);
    }
    fclose(archivo);
}

int retirarDinero(struct NodoDeCliente *nodo, char *numeroCuenta, double cantidad)
{
    while (nodo != NULL)
    {
        if (strcmp(nodo->numeroCuenta, numeroCuenta) == 0)
        {
            if (nodo->saldo >= cantidad)
            {
                nodo->saldo = nodo->saldo - cantidad;
                return 1;
            }
            else
            {
                return 0;
            }
        }
        nodo = nodo->siguiente;
    }
    return 0;
}

int depositarDinero(struct NodoDeCliente *nodo, char *numeroCuenta, double cantidad)
{
    return retirarDinero(nodo, numeroCuenta, -cantidad);
}

int transferirDinero(struct NodoDeCliente *nodo, char *cuentaOrigen, char *cuentaDestino, double cantidad)
{
    int retiroExitoso = retirarDinero(nodo, cuentaOrigen, cantidad);
    if (retiroExitoso)
    {
        depositarDinero(nodo, cuentaDestino, cantidad);
        return 1;
    }
    else
    {
        return 0;
    }
}

void imprimirDetallesDeCuenta(struct NodoDeCliente *nodo, char *numeroCuenta)
{
    while (nodo != NULL)
    {
        if (strcmp(nodo->numeroCuenta, numeroCuenta) == 0)
        {
            printf("Detalles de cuenta\nNumero de cuenta: %s\nSaldo actual: %.2lf\nNombre: %s\n", nodo->numeroCuenta, nodo->saldo, nodo->nombre);
            return; // Encontramos al cliente. No necesitamos seguir buscando
        }
        nodo = nodo->siguiente;
    }
    printf("Cliente no encontrado\n");
}

void cambiarEstadoHabilitadoDeUsuario(struct NodoDeCliente *nodo, char *numeroCuenta, int nuevoEstado)
{
    while (nodo != NULL)
    {
        if (strcmp(nodo->numeroCuenta, numeroCuenta) == 0)
        {
            nodo->habilitado = nuevoEstado;
            return;
        }
        nodo = nodo->siguiente;
    }
    printf("Usuario no encontrado\n");
}

void deshabilitarUsuario(struct NodoDeCliente *nodo, char *numeroCuenta)
{
    cambiarEstadoHabilitadoDeUsuario(nodo, numeroCuenta, ESTADO_DESHABILITADO);
}

void habilitarUsuario(struct NodoDeCliente *nodo, char *numeroCuenta)
{
    cambiarEstadoHabilitadoDeUsuario(nodo, numeroCuenta, ESTADO_HABILITADO);
}

int recuperarUsuarioAdministrador(struct Administrador *nodo)
{
    FILE *archivo = fopen(NOMBRE_ARCHIVO_ADMINISTRADOR, "r");
    if (archivo == NULL)
    {
        printf("No se pudo leer el archivo del administrador (%s)\n", NOMBRE_ARCHIVO_ADMINISTRADOR);
        return 0;
    }
    char bufer[MAXIMA_LONGITUD_CADENA]; // Aquí vamos a ir almacenando cada línea
    if (fgets(bufer, MAXIMA_LONGITUD_CADENA, archivo))
    {
        strtok(bufer, "\n");
        char *correo = strtok(bufer, DELIMITADOR_ADMINISTRADOR);
        char *palabraSecreta = strtok(NULL, DELIMITADOR_ADMINISTRADOR);
        strcpy(nodo->correo, correo);
        strcpy(nodo->palabraSecreta, palabraSecreta);
        return 1;
    }
    else
    {
        printf("El archivo de datos de administrador existe pero no tiene contenido\n");
        return 0;
    }
    fclose(archivo);
}

void imprimirDetallesAdministrador(struct Administrador *administrador)
{
    printf("Correo: '%s'\nPalabra secreta: '%s'\n", administrador->correo, administrador->palabraSecreta);
}

/*
    Recibe un apuntador a un apuntador de un NodoDeCliente en donde se desea colocar el usuario logueado, el inicio de la lista de clientes, el correo y la contraseña
    Regresa 1 o 0 indicando si el correo y la contraseña coinciden.
    Además, en caso de que el inicio de sesión sea correcto pondrá el usuario logueado en usuarioLogueado
*/
int iniciarSesionUsuario(struct NodoDeCliente **usuarioLogueado, struct NodoDeCliente *nodo, char *correoElectronico, char *palabraSecreta)
{
    while (nodo != NULL)
    {
        if (strcmp(nodo->correoElectronico, correoElectronico) == 0 && strcmp(nodo->palabraSecreta, palabraSecreta) == 0)
        {
            if (nodo->habilitado == ESTADO_DESHABILITADO)
            {
                printf("Credenciales correctas, pero el usuario esta deshabilitado\n");
                return 0;
            }
            *usuarioLogueado = nodo;
            return 1;
        }
        nodo = nodo->siguiente;
    }
    return 0;
}

int iniciarSesionAdministrador(struct Administrador **administradorLogueado, struct Administrador *administradorExistente, char *correoElectronico, char *palabraSecreta)
{
    if (strcmp(administradorExistente->correo, correoElectronico) == 0 && strcmp(administradorExistente->palabraSecreta, palabraSecreta) == 0)
    {
        *administradorLogueado = administradorExistente;
        return 1;
    }
    return 0;
}

void leerCadenaYAsegurarseDeQueNoEstaVacia(char destino[MAXIMA_LONGITUD_CADENA], char *mensaje)
{
    while (strlen(destino) <= 0)
    {
        printf("%s", mensaje);
        fgets(destino, MAXIMA_LONGITUD_CADENA, stdin);
        destino[strcspn(destino, "\r\n")] = 0;
    }
}

double leerCantidadYAsegurarseDeQueNoEsNegativa(char *mensaje)
{
    double cantidad;
    while (1)
    {
        printf("%s", mensaje);
        scanf("%lf", &cantidad);
        consumirNuevaLinea();
        if (cantidad > 0)
        {
            return cantidad;
        }
        else
        {
            printf("La cantidad debe ser mayor a 0\n");
        }
    }
    return cantidad;
}

int indiceDeCaracterEnCadena(char *cadena, char caracter)
{
    int indice = 0;
    while (cadena[indice] != '\0')
    {
        char actual = cadena[indice];
        if (actual == caracter)
        {
            return indice;
        }
        indice++;
    }
    return -1;
}

int ultimoIndiceDeCaracterEnCadena(char *cadena, char caracter)
{
    int indice = strlen(cadena) - 1;
    while (indice >= 0)
    {
        char actual = cadena[indice];
        if (actual == caracter)
        {
            return indice;
        }
        indice--;
    }
    return -1;
}

int esCorreoElectronico(char correo[MAXIMA_LONGITUD_CADENA])
{
    int indicePunto = indiceDeCaracterEnCadena(correo, '.');
    int indiceArroba = indiceDeCaracterEnCadena(correo, '@');
    if (indicePunto == -1 || indiceArroba == -1)
    {
        return 0;
    }

    if (indicePunto != ultimoIndiceDeCaracterEnCadena(correo, '.'))
    {
        return 0;
    }

    if (indiceArroba != ultimoIndiceDeCaracterEnCadena(correo, '@'))
    {
        return 0;
    }

    if (indicePunto < indiceArroba)
    {
        return 0;
    }
    return 1;
}

void leerCorreoElectronico(char destino[MAXIMA_LONGITUD_CADENA])
{
    while (1)
    {
        leerCadenaYAsegurarseDeQueNoEstaVacia(destino, "Ingrese el correo electronico: ");
        if (esCorreoElectronico(destino))
        {
            return;
        }
        else
        {
            printf("El correo debe contener un . y un @ en la forma example@example.com\n");
            strcpy(destino, "");
        }
    }
}

int contieneAlMenosUnNumero(char cadena[MAXIMA_LONGITUD_CADENA])
{
    int indice = 0;
    while (cadena[indice] != '\0')
    {
        char actual = cadena[indice];
        if (isdigit(actual))
        {
            return 1;
        }
        indice++;
    }
    return 0;
}

int contieneAlMenosUnaLetra(char cadena[MAXIMA_LONGITUD_CADENA])
{
    int indice = 0;
    while (cadena[indice] != '\0')
    {
        char actual = cadena[indice];
        if (isalpha(actual))
        {
            return 1;
        }
        indice++;
    }
    return 0;
}

int esPalabraSecretaValida(char palabraSecreta[MAXIMA_LONGITUD_CADENA])
{
    if (strlen(palabraSecreta) < 8 || strlen(palabraSecreta) > 12)
    {
        return 0;
    }
    if (!contieneAlMenosUnaLetra(palabraSecreta) || !contieneAlMenosUnNumero(palabraSecreta))
    {
        return 0;
    }
    return 1;
}

void leerPalabraSecreta(char destino[MAXIMA_LONGITUD_CADENA])
{
    while (1)
    {
        leerCadenaYAsegurarseDeQueNoEstaVacia(destino, "Ingrese la palabra secreta: ");
        if (!esPalabraSecretaValida(destino))
        {
            printf("La palabra secreta debe contener letras, numeros y medir entre 8 y 12 caracteres\n");
            strcpy(destino, "");
        }
        else
        {
            return;
        }
    }
}

int aleatorio_en_rango(int minimo, int maximo)
{
    return minimo + rand() / (RAND_MAX / (maximo - minimo + 1) + 1);
}

void rellenarCadenaConNumerosAleatorios(char destino[MAXIMA_LONGITUD_CADENA], int cantidadCaracteres)
{
    int contador = 0;
    static char banco[] = "0123456789";
    while (contador < cantidadCaracteres)
    {
        char aleatorio = banco[aleatorio_en_rango(0, strlen(banco) - 1)];
        destino[contador] = aleatorio;
        contador++;
    }
    destino[contador] = '\0';
}

void menuCrearUsuario(struct NodoDeCliente **nodo)
{
    char nombre[MAXIMA_LONGITUD_CADENA] = "";
    char identificacion[MAXIMA_LONGITUD_CADENA] = "";
    char correoElectronico[MAXIMA_LONGITUD_CADENA] = "";
    char palabraSecreta[MAXIMA_LONGITUD_CADENA] = "";
    char numeroCuenta[MAXIMA_LONGITUD_CADENA] = "";
    leerCadenaYAsegurarseDeQueNoEstaVacia(nombre, "Ingrese el nombre: ");
    leerCadenaYAsegurarseDeQueNoEstaVacia(identificacion, "Ingrese la identificacion: ");
    leerCorreoElectronico(correoElectronico);
    leerPalabraSecreta(palabraSecreta);
    rellenarCadenaConNumerosAleatorios(numeroCuenta, CANTIDAD_CIFRAS_NUMERO_CUENTA);
    agregarNodoALista(nodo, nombre, identificacion, correoElectronico, palabraSecreta, numeroCuenta, SALDO_POR_DEFECTO, ESTADO_HABILITADO);
}

void menuUsuario(struct NodoDeCliente **apuntadorListaClientes, struct NodoDeCliente *clienteLogueado)
{
    int eleccion = 0;
    while (eleccion != 5)
    {
        printf("1. Retirar\n2. Depositar\n3. Transferir\n4. Detalles\n5. Salir\nElige: ");
        scanf("%d", &eleccion);
        consumirNuevaLinea();
        if (eleccion == 1)
        {
            double cantidad = leerCantidadYAsegurarseDeQueNoEsNegativa("Ingresa la cantidad para retirar: ");
            int ok = retirarDinero(*apuntadorListaClientes, clienteLogueado->numeroCuenta, cantidad);
            if (ok)
            {
                printf("Retiro correcto.\n");
                imprimirDetallesDeCuenta(*apuntadorListaClientes, clienteLogueado->numeroCuenta);
            }
            else
            {
                printf("Saldo insuficiente\n");
            }
        }
        else if (eleccion == 2)
        {
            double cantidad = leerCantidadYAsegurarseDeQueNoEsNegativa("Ingresa la cantidad para retirar: ");
            int ok = depositarDinero(*apuntadorListaClientes, clienteLogueado->numeroCuenta, cantidad);
            if (ok)
            {
                printf("Deposito correcto.\n");
                imprimirDetallesDeCuenta(*apuntadorListaClientes, clienteLogueado->numeroCuenta);
            }
            else
            {
                printf("Error depositando\n");
            }
        }
        else if (eleccion == 3)
        {
            char numeroCuenta[MAXIMA_LONGITUD_CADENA] = "";
            leerCadenaYAsegurarseDeQueNoEstaVacia(numeroCuenta, "Ingresa el numero de cuenta del beneficiario: ");
            double cantidad = leerCantidadYAsegurarseDeQueNoEsNegativa("Ingresa la cantidad para transferir: ");
            int ok = transferirDinero(*apuntadorListaClientes, clienteLogueado->numeroCuenta, numeroCuenta, cantidad);
            if (ok)
            {
                printf("Transferencia correcta.\n");
                imprimirDetallesDeCuenta(*apuntadorListaClientes, clienteLogueado->numeroCuenta);
            }
            else
            {
                printf("Imposible transferir. Saldo insuficiente o cuenta inexistente\n");
            }
        }
        else if (eleccion == 4)
        {
            imprimirDetallesDeCuenta(*apuntadorListaClientes, clienteLogueado->numeroCuenta);
        }
    }
}

void menuHabilitarODeshabilitar(struct NodoDeCliente **apuntadorListaClientes, struct Administrador *administradorLogueado, struct Administrador *administradorExistente)
{
    char numeroCuenta[MAXIMA_LONGITUD_CADENA] = "";
    leerCadenaYAsegurarseDeQueNoEstaVacia(numeroCuenta, "Ingresa el numero de cuenta del usuario: ");
    int eleccion = 0;
    while (eleccion != 3)
    {
        printf("1. Habilitar\n2. Deshabilitar\n3. Volver\nElige: ");
        scanf("%d", &eleccion);
        consumirNuevaLinea();
        if (eleccion == 1)
        {
            habilitarUsuario(*apuntadorListaClientes, numeroCuenta);
            return;
        }
        else if (eleccion == 2)
        {
            deshabilitarUsuario(*apuntadorListaClientes, numeroCuenta);
            return;
        }
    }
}

void menuAdministrador(struct NodoDeCliente **apuntadorListaClientes, struct Administrador *administradorLogueado, struct Administrador *administradorExistente)
{
    int eleccion = 0;
    while (eleccion != 3)
    {
        printf("1. Listar usuarios\n2. Inhabilitar o habilitar\n3. Salir\nElige: ");
        scanf("%d", &eleccion);
        consumirNuevaLinea();
        if (eleccion == 1)
        {
            listarUsuarios(*apuntadorListaClientes);
        }
        else if (eleccion == 2)
        {
            menuHabilitarODeshabilitar(apuntadorListaClientes, administradorLogueado, administradorExistente);
        }
    }
}

int menuIngresarUsuario(struct NodoDeCliente **apuntadorListaClientes, struct NodoDeCliente *clienteLogueado)
{
    char palabraSecreta[MAXIMA_LONGITUD_CADENA] = "";
    char correoElectronico[MAXIMA_LONGITUD_CADENA] = "";
    leerCorreoElectronico(correoElectronico);
    leerPalabraSecreta(palabraSecreta);
    int ok = iniciarSesionUsuario(&clienteLogueado, *apuntadorListaClientes, correoElectronico, palabraSecreta);
    if (!ok)
    {
        printf("Correo o palabra secreta incorrectos\n");
    }
    else
    {
        printf("Bienvenido, %s\n", clienteLogueado->nombre);
        menuUsuario(apuntadorListaClientes, clienteLogueado);
    }
    return ok;
}
int menuIngresarAdministrador(struct NodoDeCliente **apuntadorListaClientes, struct Administrador *administrador, struct Administrador *administradorExistente)
{
    char palabraSecreta[MAXIMA_LONGITUD_CADENA] = "";
    char correoElectronico[MAXIMA_LONGITUD_CADENA] = "";
    leerCorreoElectronico(correoElectronico);
    leerPalabraSecreta(palabraSecreta);
    int ok = iniciarSesionAdministrador(&administrador, administradorExistente, correoElectronico, palabraSecreta);
    if (!ok)
    {
        printf("Correo o palabra secreta incorrectos\n");
    }
    else
    {
        printf("Bienvenido, %s\n", administrador->correo);
        menuAdministrador(apuntadorListaClientes, administrador, administradorExistente);
    }
    return ok;
}

void menuPrincipal(struct NodoDeCliente **nodo, struct NodoDeCliente *clienteLogueado, struct Administrador *administradorExistente, struct Administrador *administradorLogueado)
{

    int eleccion = 0;
    while (eleccion != 4)
    {
        printf("1. Crear usuario\n2. Ingresar usuario\n3. Ingresar administrador\n4. Salir\nElige: ");
        scanf("%d", &eleccion);
        consumirNuevaLinea();
        if (eleccion == 1)
        {
            menuCrearUsuario(nodo);
        }
        else if (eleccion == 2)
        {
            menuIngresarUsuario(nodo, clienteLogueado);
        }
        else if (eleccion == 3)
        {
            menuIngresarAdministrador(nodo, administradorLogueado, administradorExistente);
        }
    }
}

int main()
{
    srand(getpid());
    struct Administrador *administradorExistente = malloc(sizeof(struct Administrador));
    struct Administrador *administradorLogueado = NULL;
    struct NodoDeCliente *apuntadorListaClientes = NULL;
    struct NodoDeCliente *clienteLogueado = NULL;
    if (!recuperarUsuarioAdministrador(administradorExistente))
    {
        printf("No se pudo recuperar el usuario administrador. Imposible iniciar la aplicacion\n");
        return 0;
    }
    recuperarLista(&apuntadorListaClientes);
    menuPrincipal(&apuntadorListaClientes, clienteLogueado, administradorExistente, administradorLogueado);
    guardarLista(apuntadorListaClientes);
    return 0;
}

Compila como un encanto en Windows con GCC y me imagino que funciona en DevC++ y cosas de esas, aunque yo siempre recomiendo un compilador actualizado y compilar manualmente con: gcc -Wall banco.c -o banco.exe para luego ejecutar con ./banco.exe

Para terminar te dejo con más tutoriales de C en mi blog.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.

1 comentario en “Simular banco con C – Ejercicio resuelto”

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *