Mini sistema de facturación - Otras variantes en la aplicación

Haremos una serie de modificaciones a nuestra aplicación de facturación luego de haber visto la estructura fundamental en los conceptos anteriores, ésto nos servirá para identificar que partes de la aplicación se deben modificar.

Algoritmos a implementar.

  1. Modificar el acceso a datos utilizando la librería PDO.

    Hay que hacer cambios en todos los archivos que accedemos a datos de MySQL.

    conexion.php
    <?php
    
    function retornarConexion() {
        $server="localhost";
        $usuario="root";
        $clave="";
        $base="base1";
        return new PDO("mysql:dbname=$base;host=$server", "$usuario","$clave", array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8")); 
    }
    
    ?>
    

    En la carpeta 'categorias' debemos modificar:

    procesar.php
    <?php
    header('Content-Type: application/json');
    require("../conexion.php");
    
    $pdo = retornarConexion();
    
    switch ($_GET['accion']) {
        case 'listar':
            $sql = $pdo->prepare("select codigo, descripcion from categorias");
            $sql->execute();
            $resultado = $sql->fetchAll(PDO::FETCH_ASSOC);
            echo json_encode($resultado);
            break;
    
        case 'agregar':
            $sql = $pdo->prepare("insert into categorias(descripcion) values (:descripcion)");
            $respuesta = $sql->execute(array("descripcion" => $_POST['descripcion']));
            echo json_encode($respuesta);
            break;
    
        case 'recuperar':
            $sql = $pdo->prepare("select codigo,descripcion from categorias where codigo=:codigo");
            $sql->execute(array("codigo" => $_POST['codigo']));
            $resultado = $sql->fetchAll(PDO::FETCH_ASSOC);
            echo json_encode($resultado);
            break;
    
        case 'borrar':
            $sql = $pdo->prepare("delete from categorias where codigo=:codigo");
            $sql->execute(array("codigo" => $_POST['codigo']));
            $sql = $pdo->prepare("delete from productos where codigocategoria=:codigo");
            $resultado = $sql->execute(array("codigo" => $_POST['codigo']));
            echo json_encode($resultado);
            break;
    
        case 'modificar':
            $sql = $pdo->prepare("update categorias set descripcion=:descripcion where codigo=:codigo");
            $respuesta = $sql->execute(array(
                "descripcion" => $_POST['descripcion'],
                "codigo" => $_POST['codigo']
            ));
            echo json_encode($respuesta);
            break;
    }
    

    En la carpeta 'clientes' debemos modificar:

    procesar.php
    <?php
    header('Content-Type: application/json');
    require("../conexion.php");
    
    $pdo = retornarConexion();
    
    switch ($_GET['accion']) {
        case 'listar':
            $sql = $pdo->prepare("select codigo, nombre, telefono, mail, direccion from clientes");
            $sql->execute();
            $resultado = $sql->fetchAll(PDO::FETCH_ASSOC);
            echo json_encode($resultado);
            break;
    
        case 'agregar':
            $sql = $pdo->prepare("insert into clientes(nombre,telefono,mail,direccion) values (:nombre,:telefono,:mail,:direccion)");
            $respuesta = $sql->execute(array(
                "nombre" => $_POST['nombre'],
                "telefono" => $_POST['telefono'],
                "mail" => $_POST['mail'],
                "direccion" => $_POST['direccion']
            ));
            echo json_encode($respuesta);
            break;
    
        case 'recuperar':
            $sql = $pdo->prepare("select codigo, nombre, telefono, mail, direccion from clientes where codigo=:codigo");
            $sql->execute(array("codigo" => $_POST['codigo']));
            $resultado = $sql->fetchAll(PDO::FETCH_ASSOC);
            echo json_encode($resultado);
            break;
    
        case 'borrar':
            $sql = $pdo->prepare("delete from clientes where codigo=:codigo");
            $resultado = $sql->execute(array("codigo" => $_POST['codigo']));
            echo json_encode($resultado);
            break;
    
        case 'modificar':
            $sql = $pdo->prepare("update clientes
                                    set nombre=:nombre,
                                        telefono=:telefono,
                                        mail=:mail,
                                        direccion=:direccion
                                    where codigo=:codigo");
            $respuesta = $sql->execute(array(
                "nombre" => $_POST['nombre'],
                "telefono" => $_POST['telefono'],
                "mail" => $_POST['mail'],
                "direccion" => $_POST['direccion'],
                "codigo" => $_POST['codigo']
            ));
            echo json_encode($respuesta);
            break;
    }
    

    En la carpeta 'productos' debemos modificar:

    procesar.php
    <?php
    header('Content-Type: application/json');
    require("../conexion.php");
    
    $pdo = retornarConexion();
    
    switch ($_GET['accion']) {
        case 'listar':
            $sql = $pdo->prepare("select 
                                    pro.codigo as codigo,
                                    pro.descripcion descripcion,
                                    cat.descripcion descripcioncategoria,
                                    precio
                                  from productos as pro
                                  join categorias as cat on cat.codigo=pro.codigocategoria");
            $sql->execute();
            $resultado = $sql->fetchAll(PDO::FETCH_ASSOC);
            echo json_encode($resultado);
            break;
    
        case 'agregar':
            $sql = $pdo->prepare("insert into productos(descripcion,precio,codigocategoria) values (:descripcion,:precio,:codigocategoria)");
            $respuesta = $sql->execute(array(
                "descripcion" => $_POST['descripcion'],
                "precio" => $_POST['precio'],
                "codigocategoria" => $_POST['codigocategoria']
            ));
            echo json_encode($respuesta);
            break;
    
        case 'recuperar':
            $sql = $pdo->prepare("select codigo, descripcion, precio, codigocategoria from productos where codigo=:codigo");
            $sql->execute(array("codigo" => $_POST['codigo']));
            $resultado = $sql->fetchAll(PDO::FETCH_ASSOC);
            echo json_encode($resultado);
            break;
    
        case 'borrar':
            $sql = $pdo->prepare("delete from productos where codigo=:codigo");
            $resultado = $sql->execute(array("codigo" => $_POST['codigo']));
            echo json_encode($resultado);
            break;
    
        case 'modificar':
            $sql = $pdo->prepare("update productos set descripcion=:descripcion,
                                                       precio=:precio,
                                                       codigocategoria=:codigocategoria
                                                   where codigo=:codigo");
            $respuesta = $sql->execute(array(
                "descripcion" => $_POST['descripcion'],
                "precio" => $_POST['precio'],
                "codigocategoria" => $_POST['codigocategoria'],
                "codigo" => $_POST['codigo']
            ));
            echo json_encode($respuesta);
            break;
    
        case 'listarcategorias':
            $sql = $pdo->prepare("select codigo, descripcion from categorias");
            $sql->execute();
            $resultado = $sql->fetchAll(PDO::FETCH_ASSOC);
            echo json_encode($resultado);
            break;
    }
    

    En la carpeta raiz del proyecto debemos modificar:

    procesar.php
    <?php
    
    
    header('Content-Type: application/json');
    require("conexion.php");
    
    $pdo = retornarConexion();
    
    switch ($_GET['accion']) {
        case 'agregar':
            //Recuperamos el precio del producto
            $sql = $pdo->prepare("select precio from productos where codigo=:codigoproducto");
            $sql->execute(array("codigoproducto"=>$_POST['codigoproducto']));
            $reg = $sql->fetch(PDO::FETCH_ASSOC);
    
            $sql = $pdo->prepare("insert into detallefactura(codigofactura,codigoproducto,cantidad,precio) values (:codigofactura,:codigoproducto,:cantidad,:precio)");
            $respuesta = $sql->execute(array("codigofactura" => $_GET['codigofactura'],
                                             "codigoproducto"=> $_POST['codigoproducto'],
                                             "cantidad"=> $_POST['cantidad'],
                                             "precio"=> $reg['precio']
                                            ));
            echo json_encode($respuesta);
            break;
    
        case 'confirmarfactura':
            $sql = $pdo->prepare("update facturas set
                                         fecha=:fecha,
                                         codigocliente=:codigocliente
                                         where codigo=:codigofactura");
            $respuesta = $sql->execute(array(
                "fecha" => $_POST['fecha'],
                "codigocliente" => $_POST['codigocliente'],
                "codigofactura" => $_GET['codigofactura']
            ));
            echo json_encode($respuesta);
            
            break;
        case 'confirmardescartarfactura':
            $sql = $pdo->prepare("delete from facturas where codigo=:codigofactura");
            $sql->execute(array("codigofactura" => $_GET['codigofactura']));
            $sql = $pdo->prepare("delete from detallefactura where codigofactura=:codigofactura");
            $respuesta = $sql->execute(array("codigofactura" => $_GET['codigofactura']));
            echo json_encode($respuesta);        
    
    }
    
    index.php
    <!doctype html>
    <html lang="es">
    
    <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">
        <ul class="nav mt-2">
          <li class="nav-item">
            <a class="nav-link" href="#">Facturación</a>
          </li>
          <li class="nav-item dropdown">
            <a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#">Administración</a>
            <div class="dropdown-menu">
              <a class="dropdown-item" href="categorias/administracion.html">Mantenimiento de categorías</a>
              <a class="dropdown-item" href="productos/administracion.html">Mantenimiento de productos</a>
              <a class="dropdown-item" href="clientes/administracion.html">Mantenimiento de clientes</a>
            </div>
          </li>
        </ul>
    
        <?php
        require("conexion.php");
        $pdo = retornarConexion();
        $sql = $pdo->prepare(
          "select 
                  fact.codigo as codigo,
                  date_format(fecha,'%d/%m/%Y') as fecha,
                  nombre,
                  round(sum(deta.precio*deta.cantidad),2) as importefactura
              from facturas as fact 
              join clientes as cli on cli.codigo=fact.codigocliente
              join detallefactura as deta on deta.codigofactura=fact.codigo
              group by deta.codigofactura
              order by codigo desc"
        );
        $sql->execute();
        $filas = $sql->fetchAll(PDO::FETCH_ASSOC);
        ?>
        <h1>Facturas emitidas</h1>
        <table class="table table-striped">
          <thead>
            <tr>
              <th>Factura</th>
              <th>Cliente</th>
              <th>Fecha</th>
              <th class="text-right">Importe</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            <?php
            foreach ($filas as $fila) {
              ?>
              <tr>
                <td><?php echo $fila['codigo'] ?></td>
                <td><?php echo $fila['nombre'] ?></td>
                <td><?php echo $fila['fecha'] ?></td>
                <td class="text-right"><?php echo '$' . number_format($fila['importefactura'], 2, ',', '.'); ?></td>
                <td class="text-right">
                  <a class="btn btn-primary btn-sm botonimprimir" role="button" href="#" data-codigo="<?php echo $fila['codigo'] ?>">Imprime?</a>
                  <a class="btn btn-primary btn-sm botonborrar" role="button" href="#" data-codigo="<?php echo $fila['codigo'] ?>">Borra?</a>
                </td>
              </tr>
            <?php
            }
            ?>
          </tbody>
        </table>
        <button type="button" id="btnNuevaFactura" class="btn btn-success">Emitir factura</button>
      </div>
    
      <!-- ModalConfirmarBorrar -->
      <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 borrar la factura?</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() {
    
          $('#btnNuevaFactura').click(function() {
            window.location = 'facturacion.php';
          });
    
          var codigofactura;
    
          $('.botonborrar').click(function() {
            codigofactura = $(this).get(0).dataset.codigo;
            $("#ModalConfirmarBorrar").modal();
          });
    
          $('#btnConfirmarBorrado').click(function() {
            window.location = 'borrarfactura.php?codigofactura=' + codigofactura;
          });
    
          $('.botonimprimir').click(function() {
            window.open('pdffactura.php?' + '&codigofactura=' + $(this).get(0).dataset.codigo, '_blank');
          });
    
        });
      </script>
    
    </body>
    
    </html>
    
    borrarfactura.php
    <?php
    
    require("conexion.php");
    
    $pdo = retornarConexion();
    $sql = $pdo->prepare("delete from facturas where codigo=:codigofactura");
    $sql->execute(array("codigofactura" => $_GET['codigofactura']));
    $sql = $pdo->prepare("delete from detallefactura where codigofactura=:codigofactura");
    $resultado = $sql->execute(array("codigofactura" => $_GET['codigofactura']));
    
    header('location:index.php');
    
    borrarproductodetalle.php
    <?php
    header('Content-Type: application/json');
    require("conexion.php");
    
    
    $pdo = retornarConexion();
    $sql = $pdo->prepare("delete from detallefactura where codigo=:codigo");
    $resultado = $sql->execute(array("codigo" => $_GET['codigo']));
    echo json_encode($resultado);
    
    ?>
    
    facturacion.php
    <!doctype html>
    <html>
    
    <head>
      <title>Facturación</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>
    
      <?php
      require("conexion.php");
      $pdo = retornarConexion();
      $sql = $pdo->prepare("insert into facturas() values ()");
      $sql->execute();
      $codigofactura = $pdo->lastInsertId();
      ?>
    
    
      <div class="container">
        <div class="row mt-4">
          <div class="col-md">
    
            <div class="form-group row">
              <label for="CodigoFactura" class="col-lg-3 col-form-label">Número de factura:</label>
              <div class="col-lg-3">
                <input type="text" disabled class="form-control" id="CodigoFactura" value="<?php echo $codigofactura; ?>">
              </div>
            </div>
    
    
            <div class="form-group row">
              <label for="Fecha" class="col-lg-3 col-form-label">Fecha de emisión:</label>
              <div class="col-lg-3">
                <input type="date" class="form-control" id="Fecha">
              </div>
            </div>
    
            <div class="form-group row">
              <label for="CodigoCliente" class="col-lg-3 col-form-label">Cliente:</label>
              <div class="col-lg-3">
                <select class="form-control" id="CodigoCliente">
                  <?php
                  $sql = $pdo->prepare("select codigo, nombre from clientes");
                  $sql->execute();
                  $clientes = $sql->fetchAll(PDO::FETCH_ASSOC);
                  echo "<option value='0'>Seleccionar Cliente</option>";
                  foreach ($clientes as $cli) {
                    echo "<option value='" . $cli['codigo'] . "'>" . $cli['nombre'] . "</option>";
                  }
                  ?>
                </select>
              </div>
            </div>
    
    
          </div>
        </div>
    
    
        <div class="row mt-4">
          <div class="col-md">
            <table class="table table-striped">
              <thead>
                <tr>
                  <th>Código de Artículo</th>
                  <th>Descripción</th>
                  <th class="text-right">Cantidad</th>
                  <th class="text-right">Precio Unitario</th>
                  <th class="text-right">Total</th>
                  <th class="text-right"></th>
                </tr>
              </thead>
              <tbody id="DetalleFactura">
    
              </tbody>
            </table>
            <button type="button" id="btnAgregarProducto" class="btn btn-success">Agregar Producto</button>
            <button type="button" id="btnTerminarFactura" class="btn btn-success">Terminar Factura</button>
          </div>
        </div>
    
      </div>
    
    
    
      <!-- ModalProducto(Agregar) -->
      <div class="modal fade" id="ModalProducto" 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">
    
              <div class="form-group">
                <label>Producto:</label>
                <select class="form-control" id="CodigoProducto">
                  <?php
                  $sql = $pdo->prepare("select codigo, descripcion, precio from productos");
                  $sql->execute();
                  $productos = $sql->fetchAll(PDO::FETCH_ASSOC);
                  foreach ($productos as $pro) {
                    echo "<option value='" . $pro['codigo'] . "'>" . $pro['descripcion'] . '  ($' . $pro['precio'] . ")</option>";
                  }
                  ?>
                </select>
              </div>
    
              <div class="form-row">
                <div class="form-group col-md-12">
                  <label>Cantidad:</label>
                  <input type="number" id="Cantidad" class="form-control" placeholder="" min="1">
                </div>
              </div>
    
    
            </div>
            <div class="modal-footer">
              <button type="button" id="btnConfirmarAgregarProducto" class="btn btn-success">Agregar a la factura</button>
              <button type="button" data-dismiss="modal" class="btn btn-success">Cancelar</button>
            </div>
          </div>
        </div>
      </div>
    
    
      <!-- ModalFinFactura -->
      <div class="modal fade" id="ModalFinFactura" tabindex="-1" role="dialog">
        <div class="modal-dialog" style="max-width: 600px" role="document">
          <div class="modal-content">
            <div class="modal-header">
              <h1>Acciones</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="btnConfirmarFactura" class="btn btn-success">Confirmar Factura</button>
              <button type="button" id="btnConfirmarImprimirFactura" class="btn btn-success">Confirmar e Imprimir Factura</button>
              <button type="button" id="btnConfirmarDescartarFactura" class="btn btn-success">Descartar la Factura</button>
            </div>
          </div>
        </div>
      </div>
    
    
      <!-- ModalConfirmarBorrar -->
      <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 producto;
          var cliente;
    
          document.getElementById('Fecha').valueAsDate = new Date();
    
          //Boton que muestra el diálogo de agregar producto
          $('#btnAgregarProducto').click(function() {
            LimpiarFormulario();
            $("#Cantidad").val("1");
            $("#ModalProducto").modal();
          });
    
          //Boton que agrega el producto al detalle
          $('#btnConfirmarAgregarProducto').click(function() {
            RecolectarDatosFormulario();
            $("#ModalProducto").modal('hide');
            if ($("#Cantidad").val() == "") { //Controlamos que no esté vacío la cantidad de productos
              alert('no puede estar vacío la cantidad de productos.');
              return;
            }
            EnviarInformacionProducto("agregar");
          });
    
          //Boton terminar factura
          $('#btnTerminarFactura').click(function() {
            $("#ModalFinFactura").modal();
          });
    
          //Boton confirmar factura
          $('#btnConfirmarFactura').click(function() {
            if ($('#CodigoCliente').val() == 0) {
              alert('Debe seleccionar un cliente');
              return;
            }
            RecolectarDatosCliente();
            EnviarInformacionFactura("confirmarfactura");
          });
    
          //Boton que descarta la factura generada borrando tanto en la tabla de facturas como detallefactura
          $('#btnConfirmarDescartarFactura').click(function() {
            RecolectarDatosCliente();
            EnviarInformacionFactura("confirmardescartarfactura");
          });
    
          //Boton confirmar factura y ademas genera pdf
          $('#btnConfirmarImprimirFactura').click(function() {
            if ($('#CodigoCliente').val() == 0) {
              alert('Debe seleccionar un cliente');
              return;
            }
            RecolectarDatosCliente();
            EnviarInformacionFacturaImprimir("confirmarfactura");
          });
    
          function RecolectarDatosFormulario() {
            producto = {
              codigoproducto: $('#CodigoProducto').val(),
              cantidad: $('#Cantidad').val()
            };
          }
    
          function RecolectarDatosCliente() {
            cliente = {
              codigocliente: $('#CodigoCliente').val(),
              fecha: $('#Fecha').val()
            };
          }
    
          //Funciones AJAX para enviar y recuperar datos del servidor
          //******************************************************* 
          function EnviarInformacionProducto(accion) {
            $.ajax({
              type: 'POST',
              url: 'procesar.php?accion=' + accion + '&codigofactura=' + <?php echo $codigofactura ?>,
              data: producto,
              success: function(msg) {
                RecuperarDetalle();
              },
              error: function() {
                alert("Hay un error ..");
              }
            });
          }
    
          function EnviarInformacionFactura(accion) {
            $.ajax({
              type: 'POST',
              url: 'procesar.php?accion=' + accion + '&codigofactura=' + <?php echo $codigofactura ?>,
              data: cliente,
              success: function(msg) {
                window.location = 'index.php';
              },
              error: function() {
                alert("Hay un error ..");
              }
            });
          }
    
          function EnviarInformacionFacturaImprimir(accion) {
            $.ajax({
              type: 'POST',
              url: 'procesar.php?accion=' + accion + '&codigofactura=' + <?php echo $codigofactura ?>,
              data: cliente,
              success: function(msg) {
                window.open('pdffactura.php?' + '&codigofactura=' + <?php echo $codigofactura ?>, '_blank');
                window.location = 'index.php';
              },
              error: function() {
                alert("Hay un error ..");
              }
            });
          }
    
          function LimpiarFormulario() {
            $('#Cantidad').val('');
          }
    
        });
    
        //Se ejecuta cuando se presiona un boton de borrar un item del detalle
        var cod;
    
        function borrarItem(coddetalle) {
          cod = coddetalle;
          $("#ModalConfirmarBorrar").modal();
        }
    
        $('#btnConfirmarBorrado').click(function() {
          $("#ModalConfirmarBorrar").modal('hide');
          $.ajax({
            type: 'POST',
            url: 'borrarproductodetalle.php?codigo=' + cod,
            success: function(msg) {
              RecuperarDetalle();
            },
            error: function() {
              alert("Hay un error ..");
            }
          });
        });
    
        function RecuperarDetalle() {
          $.ajax({
            type: 'GET',
            url: 'recuperardetalle.php?codigofactura=' + <?php echo $codigofactura ?>,
            success: function(datos) {
              document.getElementById('DetalleFactura').innerHTML = datos;
            },
            error: function() {
              alert("Hay un error ..");
            }
    
          });
    
        }
      </script>
    </body>
    
    </html>
    
    recuperardetalle.php
    <?php 
      require("conexion.php");
    
      $pdo = retornarConexion();
      $sql = $pdo->prepare("select pro.codigo as codigo,
                                   descripcion,
                                   round(deta.precio,2) as precio,
                                   cantidad,
                                   round(deta.precio*cantidad,2) as preciototal,
                                   deta.codigo as coddetalle
                               from detallefactura as deta
                               join productos as pro on pro.codigo=deta.codigoproducto
                               where codigofactura=:codigofactura");
      $sql->execute(array("codigofactura"=>$_GET['codigofactura']));
      $resultado = $sql->fetchAll(PDO::FETCH_ASSOC);
    
      $pago=0;
      foreach ($resultado as $fila) {
          echo "<tr>";
          echo "<td>$fila[codigo]</td>";
          echo "<td>$fila[descripcion]</td>";      
          echo "<td class=\"text-right\">$fila[cantidad]</td>";            
          echo "<td class=\"text-right\">$fila[precio]</td>";
          echo "<td class=\"text-right\">$fila[preciototal]</td>";
          echo '<td class="text-right"><a class="btn btn-primary" onclick="borrarItem('.$fila['coddetalle'].')" role="button" href="#" id="'.$fila['coddetalle'].'">Borra?</a></td>';
          echo "</tr>";      
          $pago=$pago+$fila['preciototal'];
      }
      echo "<tr>";
      echo "<td></td>";
      echo "<td></td>";      
      echo "<td></td>";            
      echo "<td class=\"text-right\"><strong>Importe total</strong></td>";              
      echo "<td class=\"text-right\"><strong>".number_format(round($pago,2),2,'.','')."</strong></td>";
      echo "<td></td>";            
      echo "</tr>";
    
    ?>
    
    pdffactura.php
    <?php
    require('fpdf/fpdf.php');
    require("conexion.php");
    $pdo = retornarConexion();
    
    $fpdf = new FPDF('P', 'mm', 'letter', true);
    $fpdf->AddPage('portrait', 'letter');
    $fpdf->SetMargins(10, 30, 20, 20);
    cabecera($fpdf, $pdo);
    piedepagina($fpdf);
    
    titulosdetalle($fpdf);
    imprimirdetalle($fpdf, $pdo);
    
    $fpdf->OutPut();
    
    
    function cabecera($fpdf, $pdo)
    {
        $fpdf->SetFillColor(116, 92, 151);
        $fpdf->Rect(0, 0, 220, 50, 'F');
        $fpdf->SetFont('Arial', 'B', 15);
        $fpdf->SetTextColor(255, 255, 255);
        $fpdf->Image('imagenes/logo.png', 10, 1);
        
        $sql = $pdo->prepare("select nombre,
                                     date_format(fecha,'%d/%m/%Y') as fecha
                                 from facturas as fact
                                 join clientes as cli on cli.codigo=fact.codigocliente
                                 where fact.codigo=:codigofactura");
        $sql->execute(array("codigofactura" => $_GET['codigofactura']));
        $resultado = $sql->fetch(PDO::FETCH_ASSOC);
    
        $fpdf->SetFont('Arial', 'B', 10);
        $fpdf->SetY(5);
        $fpdf->SetX(100);
        $fpdf->Cell(0, 5, "Cliente : ".$resultado['nombre'], 0, 0, 'L', 1);
        $fpdf->SetY(10);
        $fpdf->SetX(100);
        $fpdf->Cell(0, 5, "Fecha de emisión : ".$resultado['fecha'], 0, 0, 'L', 1);
    }
    
    function piedepagina($fpdf)
    {
        $fpdf->SetFillColor(116, 92, 151);
        $fpdf->Rect(0, 250, 220, 50, 'F');
        $fpdf->SetY(-28);
        $fpdf->SetFont('Arial', '', 12);
        $fpdf->SetTextColor(0, 0, 0);
        $fpdf->SetX(120);
        $fpdf->Write(5, 'Gracias por su compra.');
    }
    
    function titulosdetalle($fpdf)
    {
        $fpdf->SetY(60);
        $fpdf->SetTextColor(255, 255, 255);
        $fpdf->SetFillColor(79, 78, 77);
        $fpdf->Cell(30, 10, 'Código', 0, 0, 'C', 1);
        $fpdf->Cell(70, 10, 'Descripción', 0, 0, 'L', 1);
        $fpdf->Cell(20, 10, 'Cantidad', 0, 0, 'C', 1);
        $fpdf->Cell(40, 10, 'Precio', 0, 0, 'R', 1);
        $fpdf->Cell(30, 10, 'Total', 0, 0, 'R', 1);
    }
    
    function imprimirdetalle($fpdf, $pdo)
    {
        $sql = $pdo->prepare("select pro.codigo as codigo,
                                     descripcion,
                                     round(deta.precio,2) as precio,
                                     cantidad,
                                     round(deta.precio*cantidad,2) as preciototal,
                                     deta.codigo as coddetalle
                                from detallefactura as deta
                                join productos as pro on pro.codigo=deta.codigoproducto
                                where codigofactura=:codigofactura");
        $sql->execute(array("codigofactura" => $_GET['codigofactura']));
        $resultado = $sql->fetchAll(PDO::FETCH_ASSOC);
    
        $fpdf->SetTextColor(0, 0, 0);
        $fpdf->SetFillColor(255, 255, 255);
        $fpdf->SetFont('times', '', 12);
        $fpdf->SetY(70);
        $fpdf->SetLineWidth(0.2);
        $pago=0;
        $item=0;
        foreach ($resultado as $fila) {
            $fpdf->Cell(30, 10, $fila['codigo'], 1, 0, 'C', 1);
            $fpdf->Cell(70, 10, $fila['descripcion'], 1, 0, 'L', 1);
            $fpdf->Cell(20, 10, $fila['cantidad'], 1, 0, 'R', 1);
            $fpdf->Cell(40, 10, '$'.number_format($fila['precio'],2,',','.'), 1, 0, 'R', 1);
            $fpdf->Cell(30, 10, '$'.number_format($fila['preciototal'],2,',','.'), 1, 0, 'R', 1);
            $fpdf->Ln();
            $pago=$pago+$fila['preciototal'];
            $item++;
            if ($item==16) {
                $fpdf->AddPage('portrait', 'letter');
                $fpdf->SetMargins(10, 30, 20, 20);
                cabecera($fpdf, $pdo);
                piedepagina($fpdf);            
                titulosdetalle($fpdf);
                $fpdf->SetTextColor(0, 0, 0);
                $fpdf->SetFillColor(255, 255, 255);
                $fpdf->SetFont('Arial', '', 12);
                $fpdf->SetY(70);
                $fpdf->SetLineWidth(0.2);        
                $item=0;
            }
        }
        $fpdf->SetFont('Arial', 'B', 15);
        $fpdf->Cell(190, 20, "Importe Total : $".number_format($pago,2,',','.'), 1, 0, 'R', 1);
    }