Mini sistema de facturación - CRUD de categorías

Vamos a empezar a implementar los algoritmos de CRUD sobre las tablas que intervendrán en la facturación.

La primer tabla será la de 'categorias'. Los algoritmos de la misma los almacenaremos en una subcarpeta llamada 'categorias' para organizar los archivos del proyecto.

Crearemos dos archivos llamados 'administracion.html' y 'procesar.php':

facturación en PHP

administracion.html
<!doctype html>
<html>

<head>
  <title>Administración de categorías</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <link rel="stylesheet" href="../css/bootstrap.min.css">
  <script src="../js/jquery.min.js"></script>
  <script src="../js/popper.min.js"></script>
  <script src="../js/bootstrap.min.js"></script>

</head>

<body>

  <div class="container">
    <h1>Administracion de Categorias</h1>

    <table class="table table-striped">
      <thead>
        <tr>
          <th>Código</th>
          <th>Descripcion</th>
          <th>Edición</th>
        </tr>
      </thead>
      <tbody id="datos">
      </tbody>      
    </table>

    <button type="button" id="btnAgregar" class="btn btn-success">Agregar</button>
    <hr>
    <button type="button" id="btnFinalizar" class="btn btn-success">Finalizar</button>
  </div>

  <div class="modal fade" id="ModalEditar" tabindex="-1" role="dialog">
    <div class="modal-dialog" role="document">
      <div class="modal-content">
        <div class="modal-header">

          <button type="button" class="close" data-dismiss="modal" aria-label="Close">
            <span aria-hidden="true">×</span>
          </button>
        </div>
        <div class="modal-body">
          <input type="hidden" id="Codigo">
          <div class="form-row">
            <div class="form-group col-md-12">
              <label>Descripción:</label>
              <input type="text" id="Descripcion" class="form-control" placeholder="">
            </div>
          </div>

        </div>
        <div class="modal-footer">
          <button type="button" id="btnConfirmarAgregar" class="btn btn-success">Agregar</button>
          <button type="button" id="btnModificar" class="btn btn-success">Modificar</button>
          <button type="button" id="btnBorrar" class="btn btn-success">Borrar</button>
          <button type="button" data-dismiss="modal" class="btn btn-success">Cancelar</button>
        </div>
      </div>
    </div>
  </div>


  <!-- ModalConfirmarCancelar -->
  <div class="modal fade" id="ModalConfirmarBorrar" tabindex="-1" role="dialog">
    <div class="modal-dialog" style="max-width: 600px" role="document">
      <div class="modal-content">
        <div class="modal-header">
          <h1>Realmente quiere borrarlo?</h1>
          <button type="button" class="close" data-dismiss="modal" aria-label="Close">
            <span aria-hidden="true">×</span>
          </button>
        </div>
        <div class="modal-footer">
          <button type="button" id="btnConfirmarBorrado" class="btn btn-success">Confirmar</button>
          <button type="button" data-dismiss="modal" class="btn btn-success">Cancelar</button>
        </div>
      </div>
    </div>
  </div>


  <script>
    document.addEventListener("DOMContentLoaded", function() {

      var categoria;
      MostrarCategorias();

      //Boton que vuelve a la página principal
      $('#btnFinalizar').click(function() {
        window.location = '../index.php';
      });

      //Boton que muestra el diálogo de agregar
      $('#btnAgregar').click(function() {
        LimpiarFormulario();
        $('#btnConfirmarAgregar').show();
        $('#btnModificar').hide();
        $('#btnBorrar').hide();
        $("#ModalEditar").modal();
      });

      $('#btnConfirmarAgregar').click(function() {
        RecolectarDatosFormulario();
        if (!EntradaFormularioCorrecto())
          return;
        $("#ModalEditar").modal('hide');
        EnviarInformacion("agregar");
      });

      $('#btnBorrar').click(function() {
        $("#ModalEditar").modal('hide');
        $("#ModalConfirmarBorrar").modal();
      });


      $('#btnConfirmarBorrado').click(function() {
        $("#ModalConfirmarBorrar").modal('hide');
        RecolectarDatosFormulario();
        $("#ModalEditar").modal('hide');
        EnviarInformacion("borrar");
      });

      $('#btnModificar').click(function() {
        RecolectarDatosFormulario();
        if (!EntradaFormularioCorrecto())
          return;
        $("#ModalEditar").modal('hide');
        EnviarInformacion("modificar");
      });
      //******************************************************* 

      function MostrarCategorias() {
        $.ajax({
          type: 'GET',
          url: 'procesar.php?accion=listar',
          success: function(categorias) {
            let filas = '';
            for (let categoria of categorias) {
              filas += '<tr><td>' + categoria.codigo + '</td><td>' + categoria.descripcion + '</td>';
              filas += '<td><a class="btn btn-primary botoneditar" role="button" href="#" data-codigo="' + categoria.codigo + '">Edita?</a> </td></tr>';
            }
            $('#datos').html(filas);
            //Boton que muestra el diálogo de modificar y borrar
            $('.botoneditar').click(function() {
              $('#Codigo').val($(this).get(0).dataset.codigo);
              RecolectarDatosFormulario();
              RecuperarCategoria("recuperar");
              $('#btnConfirmarAgregar').hide();
              $('#btnModificar').show();
              $('#btnBorrar').show();
              $("#ModalEditar").modal();
            });

          },
          error: function() {
            alert("Hay un error ..");
          }
        });
      }

      //Funciones AJAX para enviar y recuperar datos del servidor
      //******************************************************* 
      function EnviarInformacion(accion) {
        $.ajax({
          type: 'POST',
          url: 'procesar.php?accion=' + accion,
          data: categoria,
          success: function(msg) {
            MostrarCategorias();
          },
          error: function() {
            alert("Hay un error ..");
          }
        });
      }

      function RecuperarCategoria(accion) {
        $.ajax({
          type: 'POST',
          url: 'procesar.php?accion=' + accion,
          data: categoria,
          success: function(datos) {
            $('#Descripcion').val(datos[0]['descripcion']);
          },
          error: function() {
            alert("Hay un error ..");
          }
        });
      }
      //******************************************************* 

      function RecolectarDatosFormulario() {
        categoria = {
          codigo: $('#Codigo').val(),
          descripcion: $('#Descripcion').val()
        };
      }

      function LimpiarFormulario() {
        $('#Codigo').val('');
        $('#Descripcion').val('');
      }

      function EntradaFormularioCorrecto() {
        if (categoria['descripcion'] == '') {
          alert("No Puede estar vacía la descripción");
          return false;
        }
        return true;
      }

    });
  </script>

</body>

</html>

La ejecución de la página nos genera una interfaz visual similar a:

facturación en PHP

Con un diálogo que se muestra cuando presionamos el botón de "Agregar":

facturación en PHP

o "Editar":

facturación en PHP

El segundo archivo que tenemos en la carpeta 'categorias' se llama 'procesar.php' y contiene todo el código PHP que permite actualizar, modificar y borrar datos de la tabla 'categorias'.

procesar.php
<?php
header('Content-Type: application/json');
require("../conexion.php");

$conexion = retornarConexion();

switch ($_GET['accion']) {
    case 'listar':
        $respuesta = mysqli_query($conexion, "select codigo, descripcion from categorias");
        $resultado = mysqli_fetch_all($respuesta, MYSQLI_ASSOC);
        echo json_encode($resultado);
        break;
    case 'agregar':
        $respuesta = mysqli_query($conexion, "insert into categorias(descripcion) values ('$_POST[descripcion]')");
        echo json_encode($respuesta);
        break;
    case 'recuperar':
        $respuesta = mysqli_query($conexion, "select codigo, descripcion from categorias where codigo=$_POST[codigo]");
        $resultado = mysqli_fetch_all($respuesta, MYSQLI_ASSOC);
        echo json_encode($resultado);
        break;
    case 'borrar':
        $respuesta = mysqli_query($conexion, "delete from categorias where codigo=".$_POST['codigo']);
        $respuesta = mysqli_query($conexion, "delete from productos where codigocategoria=".$_POST['codigo']);
        echo json_encode($respuesta);
        break;
    case 'modificar':
        $respuesta = mysqli_query($conexion, "update categorias set descripcion='$_POST[descripcion]' where codigo=$_POST[codigo]");
        echo json_encode($respuesta);
        break;        
}

?>

Hay un tercer archivo que interviene llamado 'conexion.php' que no se encuentra en ésta carpeta pero se requiere para conectarse a MySQL:

<?php

function retornarConexion() {
				
    $server="localhost";
    $usuario="root";
    $clave="";
    $base="base1";
			
    $con=mysqli_connect($server,$usuario,$clave,$base) or die("problemas") ;
    mysqli_set_charset($con,'utf8'); 
    return $con;
}
?>

Listado de categorías

El archivo 'administracion.html' mediante AJAX recupera todas las categorías para ser mostradas en una tabla HTML:

      function MostrarCategorias() {
        $.ajax({
          type: 'GET',
          url: 'procesar.php?accion=listar',
          success: function(categorias) {
            let filas = '';
            for (let categoria of categorias) {
              filas += '<tr><td>' + categoria.codigo + '</td><td>' + categoria.descripcion + '</td>';
              filas += '<td><a class="btn btn-primary botoneditar" role="button" href="#" data-codigo="' + categoria.codigo + '">Edita?</a> </td></tr>';
            }
            $('#datos').html(filas);
            //Boton que muestra el diálogo de modificar y borrar
            $('.botoneditar').click(function() {
              $('#Codigo').val($(this).get(0).dataset.codigo);
              RecolectarDatosFormulario();
              RecuperarCategoria("recuperar");
              $('#btnConfirmarAgregar').hide();
              $('#btnModificar').show();
              $('#btnBorrar').show();
              $("#ModalEditar").modal();
            });

          },
          error: function() {
            alert("Hay un error ..");
          }
        });
      }

La función es llamada inmediatamente luego de ser cargada la página HTML por completo:

    document.addEventListener("DOMContentLoaded", function() {

      var categoria;
      MostrarCategorias();

Agregar categoría

Cuando se presiona el botón "Agregar" se dispara el evento click siguiente, donde borramos los datos del formulario HTML, hacemos visible el botón de confirmar y ocultamos los botones de borrar y editar. Finalmente llamamos a la función 'modal' para que se haga visible el diálogo:

    $('#btnAgregar').click(function() {
      LimpiarFormulario();
      $('#btnConfirmarAgregar').show();
      $('#btnModificar').hide();
      $('#btnBorrar').hide();
      $("#ModalEditar").modal();
    });

Una vez que el operador ingresa la descripción de la categoría y presiona el botón de 'Confirmar' se dispara la función donde se recuperan los datos del diálogo, se controla que la descripción no esté vacía y finalmente se llama a la función 'EnviarInformación' para que se agregue una fila en la tabla 'categorias':

    //Botones que permiten agregar, borrar y modificar una fila de la tabla.
    $('#btnConfirmarAgregar').click(function() {
      RecolectarDatosFormulario();
      if (!EntradaFormularioCorrecto())
        return;
      $("#ModalEditar").modal('hide');
      EnviarInformacion("agregar");
    });

La función que recupera los datos del formulario crea un objeto llamado 'categoria' (variable global definida previamente):

    function RecolectarDatosFormulario() {
      categoria = {
        codigo: $('#Codigo').val(),
        descripcion: $('#Descripcion').val()
      };
    }

La función 'EnviarInformacion' mediante AJAX envía los datos del formulario almacenados en la variable 'categoria', además luego llamamos a la función 'MostrarCategorias' para que se actualice la tabla HTML con la nueva categoría ingresada:

      function EnviarInformacion(accion) {
        $.ajax({
          type: 'POST',
          url: 'procesar.php?accion=' + accion,
          data: categoria,
          success: function(msg) {
            MostrarCategorias();
          },
          error: function() {
            alert("Hay un error ..");
          }
        });
      }

El archivo 'procesar.php' recibe por parámetro 'GET' la acción 'agregar' y por POST la descripción de la categoría a insertar:

	<?php
	header('Content-Type: application/json');
	require("../conexion.php");

	$conexion = retornarConexion();

	switch ($_GET['accion']) {
		case 'listar':
			$respuesta = mysqli_query($conexion, "select codigo, descripcion from categorias");
			$resultado = mysqli_fetch_all($respuesta, MYSQLI_ASSOC);
			echo json_encode($resultado);
			break;
		case 'agregar':
			$respuesta = mysqli_query($conexion, "insert into categorias(descripcion) values ('$_POST[descripcion]')");
			echo json_encode($respuesta);
			break;

Editar categoría

Cuando se presiona el botón 'Editar' de una categoría se dispara la función:

    $('.botoneditar').click(function() {
      $('#Codigo').val($(this).get(0).dataset.codigo);
      RecolectarDatosFormulario();
      RecuperarCategoria("recuperar");
      $('#btnConfirmarAgregar').hide();
      $('#btnModificar').show();
      $('#btnBorrar').show();
      $("#ModalEditar").modal();
    });

Recuperamos el código de la categoría almacenado en 'data-codigo' en el HTML mediante la sintaxis:

      $('#Codigo').val($(this).get(0).dataset.codigo);

Mediante AJAX recuperamos los datos del servidor de la categoría seleccionada:

      RecuperarCategoria("recuperar");

El archivo 'accion.php' retorna los datos de la categoría a editar:

    case 'recuperar':
        $respuesta = mysqli_query($conexion, "select codigo, descripcion from categorias where codigo=$_POST[codigo]");
        $resultado = mysqli_fetch_all($respuesta, MYSQLI_ASSOC);
        echo json_encode($resultado);
        break;

Borrar categoría

Una vez que el operador presionó el botón de 'Editar' tiene las opciones de borrar o modificar la categoría. Si presiona el botón de 'Borrar' se ejecuta la función:

    $('#btnBorrar').click(function() {   
      $("#ModalEditar").modal('hide'); 
      $("#ModalConfirmarBorrar").modal();
    });

Se procede a ocultar el diálogo actual y activar un nuevo diálogo que permita confirma el borrado de la categoría:

facturación en PHP

Si presiona 'Confirmar' se ejecuta la función:

    $('#btnConfirmarBorrado').click(function() {  
      $("#ModalConfirmarBorrar").modal('hide');
      RecolectarDatosFormulario();
      $("#ModalEditar").modal('hide');
      EnviarInformacion("borrar");
    });

En ésta función nos comunicamos con el servidor mediante AJAX, donde se procede a eliminar la fila de la tabla:

    case 'borrar':
        $respuesta = mysqli_query($conexion, "delete from categorias where codigo=".$_POST['codigo']);
        $respuesta = mysqli_query($conexion, "delete from productos where codigocategoria=".$_POST['codigo']);
        echo json_encode($respuesta);
        break;

Si borramos una categoría procedemos también a borrar todos los productos de dicha categoría.

Modificar categoría

Si presiona el botón de 'Modificar' se ejecuta la función:

      $('#btnModificar').click(function() {
        RecolectarDatosFormulario();
        if (!EntradaFormularioCorrecto())
          return;
        $("#ModalEditar").modal('hide');
        EnviarInformacion("modificar");
      });

Donde recolectamos los datos del diálogo, verificamos llamando a la función 'EntradaFormularioCorrecto' que se haya cargado el dato de la descripción y en caso afirmativo ocultamos el diálogo y procedemos a comunicarnos con el servidor llamando a 'EnviarInformacion("modificar")'.

En el servidor se ejecuta el comando SQL 'update':

    case 'modificar':
        $respuesta = mysqli_query($conexion, "update categorias set descripcion='$_POST[descripcion]' where codigo=$_POST[codigo]");
        echo json_encode($respuesta);
        break;