La página principal para la confección de la factura se encuentra en el archivo 'facturacion.php'. Inmediatamente ingresamos a la página se muestra una interfaz visual similar a:

Se muestra el número de factura a emitir, la fecha de emisión de la factura, el control select para buscar el cliente a quien se le facturará. En la parte inferior disponemos de dos botones, uno para agregar productos y otro para finalizar la factura.
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");
  $con = retornarConexion();
  $consulta = mysqli_query($con, "insert into facturas() values ()")
    or die(mysqli_error($con));
  $codigofactura = mysqli_insert_id($con);
  ?>
  <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
              $consulta = mysqli_query($con, "select codigo, nombre from clientes")
                or die(mysqli_error($con));
              $clientes = mysqli_fetch_all($consulta, MYSQLI_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
              $consulta = mysqli_query($con, "select codigo, descripcion, precio from productos")
                or die(mysqli_error($con));
              $productos = mysqli_fetch_all($consulta, MYSQLI_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>
Cuando se carga la página se genera en forma automática el número de factura:
  <?php
  require("conexion.php");
  $con = retornarConexion();
  $consulta = mysqli_query($con, "insert into facturas() values ()")
    or die(mysqli_error($con));
  $codigofactura = mysqli_insert_id($con);
  ?>
Ejecutamos un comando SQL insert sin indicar valores, luego se genera y carga solo el campo 'codigo', dejando para después la actualización de los campos 'fecha' y 'codigocliente'.
Mostramos el código de factura en un control input desactivo, con el objetivo que el usuario no lo pueda modificar:
            <input type="text" disabled class="form-control" id="CodigoFactura" value="<?php echo $codigofactura; ?>">
Mediante un control HTML 'select' mostramos todos los clientes para que el usuario lo pueda seleccionar:
        <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
              $consulta = mysqli_query($con, "select codigo, nombre from clientes")
                or die(mysqli_error($con));
              $clientes = mysqli_fetch_all($consulta, MYSQLI_ASSOC);
              echo "<option value='0'>Seleccionar Cliente</option>";
              foreach ($clientes as $cli) {
                echo "<option value='" . $cli['codigo'] . "'>" . $cli['nombre'] . "</option>";
              }
              ?>
            </select>
          </div>
        </div>
Cuando se presiona el botón 'Agregar producto' se activa el diálogo donde debemos seleccionar el producto y la cantidad del mismo:

El evento del botón es:
      $('#btnAgregarProducto').click(function() {
        LimpiarFormulario();
        $("#Cantidad").val("1");
        $("#ModalProducto").modal();
      });
Llamamos a la funcón de 'LimpiarFormulario' para borrar datos de selecciones previas, fijamos la cantidad de productos en uno y hacemos visible el diálogo.
Cuando presionamos el botón del diálogo 'Agregar a la factura' se dispara el evento:
      $('#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");
      });
Recuperamos los datos del formulario, ocultamos el diálogo, controlamos que haya cargado un valor en la cantidad de productos y llamamos finalmente a la función 'EnviarInformaciónProducto' pasando el parámetro de "agregar".
La función de EnviarInformacionProducto se comunica mediante AJAX al servidor para que se agregue el producto seleccionado:
      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 ..");
          }
        });
      }
Si pasamos la acción 'agregar' luego el archivo 'procesar.php' se ejecuta:
<?php
header('Content-Type: application/json');
require("conexion.php");
$conexion = retornarConexion();
switch ($_GET['accion']) {
    case 'agregar':
        //Recuperamos el precio del producto
        $respuesta = mysqli_query($conexion, "select precio from productos where codigo=".$_POST['codigoproducto']);
        $reg=mysqli_fetch_array($respuesta);
        $respuesta = mysqli_query($conexion, "insert into detallefactura(codigofactura,codigoproducto,cantidad,precio) values ($_GET[codigofactura],$_POST[codigoproducto],$_POST[cantidad],$reg[precio])");
        echo json_encode($respuesta);
        break;
    case 'confirmarfactura':
        $respuesta = mysqli_query($conexion, "update facturas set
                                                fecha='$_POST[fecha]',
                                                codigocliente=$_POST[codigocliente]
                                              where codigo=$_GET[codigofactura]");
        echo json_encode($respuesta);        
        break;
    case 'confirmardescartarfactura':
        $respuesta = mysqli_query($conexion, "delete from facturas where codigo=$_GET[codigofactura]");
        $respuesta = mysqli_query($conexion, "delete from detallefactura where codigofactura=$_GET[codigofactura]");
        echo json_encode($respuesta);        
}
?>
Inmediatamente el servidor nos informa que el producto fue agregado se ejectua la función 'RecuperarDetalle':
    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 ..");
        }
      });
    }
La función 'RecuperarDetalle' ejecuta el algoritmo contenido en el archivo 'recuperardetalle.php':
<?php 
  require("conexion.php");
  $conexion = retornarConexion();
  
  $datos = mysqli_query($conexion, "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=$_GET[codigofactura]") or die(mysqli_error($conexion));
  $resultado = mysqli_fetch_all($datos, MYSQLI_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>";
?>
La función recuperar detalle modifica la tabla HTML donde se muestran todos los productos seleccionados hasta ese momento:
        success: function(datos) {
          document.getElementById('DetalleFactura').innerHTML = datos;
        },
En pantalla podemos ver todos los productos seleccionados y sus cantidades:

En cualquier momento podemos eliminar un producto de la factura presionando el botón 'Borra?', en dicha situación se dispara la función:
    //Se ejecuta cuando se presiona un boton de borrar un item del detalle
    var cod;
    function borrarItem(coddetalle) {
      cod = coddetalle;
      $("#ModalConfirmarBorrar").modal();
    }
Se nos muestra un diálogo para confirma su eliminación:

En caso de confirma su eliminación se ejecuta la función:
    $('#btnConfirmarBorrado').click(function() {
      $("#ModalConfirmarBorrar").modal('hide');
      $.ajax({
        type: 'POST',
        url: 'borrarproductodetalle.php?codigo=' + cod,
        success: function(msg) {
          RecuperarDetalle();
        },
        error: function() {
          alert("Hay un error ..");
        }
      });
    });
Donde se informa al servidor el código del detalle de factura a eliminar, dicha acción la ejecuta la página 'borrarproductodetalle.php':
<?php
header('Content-Type: application/json');
require("conexion.php");
$conexion = retornarConexion();
$respuesta = mysqli_query($conexion, "delete from detallefactura where codigo=".$_GET['codigo']);
echo json_encode($respuesta);
?>
Cuando se presiona el botón 'Terminar factura' se muestra un diálogo que nos permite:

Confirmar factura:
      $('#btnConfirmarFactura').click(function() {
        if ($('#CodigoCliente').val() == 0) {
          alert('Debe seleccionar un cliente');
          return;
        }
        RecolectarDatosCliente();
        EnviarInformacionFactura("confirmarfactura");
      });
Donde se comunica con el servidor mediante AJAX para dejar firme la factura generada:
    case 'confirmarfactura':
        $respuesta = mysqli_query($conexion, "update facturas set
                                                fecha='$_POST[fecha]',
                                                codigocliente=$_POST[codigocliente]
                                              where codigo=$_GET[codigofactura]");
        echo json_encode($respuesta);        
        break;
Confirmar e imprimir factura (similar al primer botón, con la salvedad que se agrega la llamada a la generación del PDF de la factura):
      $('#btnConfirmarImprimirFactura').click(function() {
        if ($('#CodigoCliente').val() == 0) {
          alert('Debe seleccionar un cliente');
          return;
        }
        RecolectarDatosCliente();
        EnviarInformacionFacturaImprimir("confirmarfactura");
      });
En la función 'EnviarInformacionFacturaImprimir' se llama a la página que genera el PDF:
      function EnviarInformacionFacturaImprimir(accion) {
        $.ajax({
          type: 'POST',
          url: 'procesar.php?accion=' + accion + '&codigofactura=' + ,
          data: cliente,
          success: function(msg) {
            window.open('pdffactura.php?' + '&codigofactura=' + , '_blank');
            window.location = 'index.php';
          },
          error: function() {
            alert("Hay un error ..");
          }
        });
      }
Por último el botón de 'Descartar la factura' dispara el evento:
      $('#btnConfirmarDescartarFactura').click(function() {
        RecolectarDatosCliente();
        EnviarInformacionFactura("confirmardescartarfactura");
      });
Se comunica con el servidor para que borre la factura actual y todos los productos añadidos hasta el momento:
    case 'confirmardescartarfactura':
        $respuesta = mysqli_query($conexion, "delete from facturas where codigo=$_GET[codigofactura]");
        $respuesta = mysqli_query($conexion, "delete from detallefactura where codigofactura=$_GET[codigofactura]");
        echo json_encode($respuesta);