Blog personal

Gestión de Impresos / Formularios

Muchas Administraciones Públicas y muchas empresas importantes, disponen de sistemas antiguos para facilitar que en sus portales, los ciudadanos o personal propio, inicien un proceso a través de los datos rellenados en una solicitud en formato PDF.

Se ha pagado importantes sumas de dinero a Adobe, para hacer que los mismos documentos PDF’s fuesen los formularios de entrada de los datos requeridos y su validación.

Estas plataformas, muy costosas, han dejado de ser operativas porque el dispositivo más usado por los Ciudadanos ha dejado de ser el PC y se ha extendido el uso del móvil.

No obstante, se usan documentos PDF’s para recepcionar las solicitudes y para emitir las resoluciones, dado que incorporan las firmas electrónicas de forma muy eficiente y las leyes y normativas internacionales y nacionales, los admiten como documentos fehacientes, si sus firmas son emitidas por Entidades Reconocidas.

Así pues, la propuesta es conservar los documentos PDF, pero no así utilizarlos para (formularios) la captura de sus datos.

Para entender perfectamente la solución técnica propuesta les sugiero que previamente lean el artículo que explica cómo obtener los puntos de ubicación de los campos en el documento PDF .

Ventajas de usar formularios en PDF:

  • Tanto para el Ciudadano como para los Empleados, lo que se cambia es la fotocopia del impreso a otra imagen igual, que sirve para rellenar los datos a mano o a través del navegador. No tiene costes de adaptación.

Desventajas de usar formularios en PDF:

  • Las plataformas para usar documentos PDF como formularios son muy caras y muy costoso de desarrollar las validaciones de los formularios.
  • Para usar en dispositivos de pantallas pequeñas (principalmente móviles) no es una solución adecuada.

La solución PHPRunner es una herramienta muy potente para hacer formularios, puede utilizarse en PC y en dispositivos móviles, con el mismo desarrollo y las validaciones y controles que requieren los formularios se pueden implementar muy rápidamente. Por el contrario, los documentos PDF que proporciona son simples y no se ajustan a los impresos que se utilizan en las empresas, que por otra parte, deben seguir ofreciendo el PDF para aquellos usuarios que los desean rellenar con bolígrafo. Para potenciar a PHPRunner le he incorporado el uso de las librerías FREE de SETASIGN

Aunque el ejemplo es una única aplicación, para las Administraciones que requieren un gran número de Impresos y una actualización constante de los mismos, la arquitectura de la solución no sería esta. Los impresos serían aplicaciones independientes, aunque compartirían códigos, datos e infraestructura entre ellos, facilitando así, la actualización continua de estos impresos.

Ejemplo de listado de Formularios del Ayuntamiento de Madrid

El ejemplo consta:

  • Relación de Impresos
  • Pasos (bloques) para la cumplimentación del formulario. No se utiliza la funcionalidad de STEP de PHPRunner, porque tiene problemas en la notificación de los errores.
  • Campos del formulario y sus traslación a puntos X, Y y página de la plantilla PDF.

Esto no es una solución, si no que es un ejemplo para que tú construyas TU SOLUCIÓN

El modelo de datos utilizado es:

Los códigos PHP más relevantes son:

print_pdf.php
<?php
/*
// Variables of SESSION

$_SESSION['S_forms_id'] = $data['idforms'];
$_SESSION['S_forms_code'] = $data['Code'];
$_SESSION['S_forms_name']  = $data['Name'];
$_SESSION['S_forms_table'] = $data['Table'];
$_SESSION['S_company_id'] = $data['companies_company_id'];
$_SESSION['S_dept_id'] = $data['departments_dept_id']; 
$_SESSION['S_forms_query'] = $data['Query'];
$_SESSION['S_forms_template_pdf'] = $data['TemplatePDF'];
$_SESSION['S_forms_template_pages'] = $data['TemplatePages'];
$_SESSION['S_forms_template_point_x'] = $data['TemplatePointX'];
$_SESSION['S_forms_template_point_y'] = $data['TemplatePointY'];

$_SESSION['S_forms_petition_id']
*/
// Recover Config variables
$Numeric_symbol_of_thousands = $_SESSION['config'][array_search('Numeric_symbol_of_thousands', array_column($_SESSION['config'], 'name'))][value];
$Numeric_decimal_symbol = $_SESSION['config'][array_search('Numeric_decimal_symbol', array_column($_SESSION['config'], 'name'))][value];
$Date_format = $_SESSION['config'][array_search('Date_format', array_column($_SESSION['config'], 'name'))][value];
$Date_and_time_format = $_SESSION['config'][array_search('Date_and_time_format', array_column($_SESSION['config'], 'name'))][value];
$Time_format = $_SESSION['config'][array_search('Time_format', array_column($_SESSION['config'], 'name'))][value];
$Long_Date_Format = $_SESSION['config'][array_search('Long_Date_Format', array_column($_SESSION['config'], 'name'))][value];
$date_default_timezone_set = $_SESSION['config'][array_search('date_default_timezone_set', array_column($_SESSION['config'], 'name'))][value];
$setlocale_LC_TIME = $_SESSION['config'][array_search('setlocale_LC_TIME', array_column($_SESSION['config'], 'name'))][value];

date_default_timezone_set($date_default_timezone_set);
setlocale(LC_TIME, $setlocale_LC_TIME);


$l_sql = $_SESSION['S_forms_query'];
$Petition_id = $_SESSION['S_forms_petition_id'];
$forms_id = $_SESSION['S_forms_id'];

// Read info of record of forms
global $conn;
$sql_1 = str_replace("#key", $Petition_id, $l_sql);
$resql_1 = db_query($sql_1,$conn);
$data=$resql_1->fetch_all(MYSQLI_ASSOC);

// get information about uploaded files
$fileArray = my_json_decode($_SESSION['S_forms_template_pdf']);
// set the source file
$template_pdf = $fileArray[0]["name"];
$TotalPagesTemplate = $_SESSION['S_forms_template_pages'];

require_once __DIR__ . '/../../ComponentCode/fpdi_2_2/autoload.php';
use setasign\Fpdi\Fpdi;
// initiate FPDI
$pdf = new Fpdi();
// add a page
$pdf->AddPage();
// set the source file
$pdf->setSourceFile($template_pdf);
// import page 1
$tplIdx = $pdf->importPage(1);
// use the imported page and place it at position 10,10 with a width of 100 mm
$pdf->useTemplate($tplIdx);

// Obtain measures from the page for the transformation of the Points
$pdf->SetXY(1, 1);
// $pdf->SetFont('Arial','',10); //  Font, type and size
// $pdf->SetTextColor(0, 96, 175); // Color in R, G, B
$w   = $pdf->GetPageWidth();
$h   = $pdf->GetPageHeight();
$wPt = $_SESSION['S_forms_template_point_x']; //  Measures in points of the page
$hPt = $_SESSION['S_forms_template_point_y']; //  Measures in points of the page
$coef_x = $wPt/$w; // X axis transformation coefficient
$coef_y = $hPt/$h; // Y axis transformation coefficient



$sql_1 = "
SELECT * FROM form_fields WHERE forms_idforms = $forms_id AND NumberPageTemplate <> 0 order by NumberPageTemplate, idform_fields
";
// All Field => forms_idforms, Name, Type, Length, IsNumber, IsDecimal, NumberDecimal, Font, FontSize, FontStyle, FontColor, Align, NumberPageTemplate, PointX, PointY, RightMargin, Description
$resql_1 = db_query($sql_1,$conn);
$fields=$resql_1->fetch_all(MYSQLI_ASSOC);
// Loop to complete values
for ($i = 0; $i < count($fields); $i++) {
// Align
    switch ($fields[$i][Align]) {
    case 1:
        $fields[$i][Align] = 'R' ;
        break;
    case 2:
        $fields[$i][Align] = 'C' ;
        break;
    default:
        $fields[$i][Align] = 'L' ;
        break;
		}
// FontStyle
    switch ($fields[$i][FontStyle]) {
    case 1:
        $fields[$i][FontStyle] = 'B' ;
        break;
    case 2:
        $fields[$i][FontStyle] = 'I' ;
        break;
    case 3:
        $fields[$i][FontStyle] = 'U' ;
        break;
    default:
        $fields[$i][FontStyle] = '' ;
        break;
		}
}
// Loop to control template pages
for ($page = 1; $page <= $TotalPagesTemplate; $page++) {
    foreach ($fields as $field) {
		//  Fields = forms_idforms, Name, Type, Length, IsNumber, IsDecimal, NumberDecimal, Font, FontSize, FontStyle, FontColor, Align, NumberPageTemplate, PointX, PointY, RightMargin, Description
		if ( $field['NumberPageTemplate'] == $page ) { // Field is of page of Tamplate
                    $pdf->SetXY($field['PointX']/$coef_x, $field['PointY']/$coef_y); // Positioning on the page
                    $pdf->SetMargins($field['PointX']/$coef_x,5,$field['RightMargin']/$coef_x);
                    $pdf->SetFont($field['Font'],$field['FontStyle'],$field['FontSize']); //  Font, type and size
											$FontColor = explode(",", $field['FontColor']);										  
                    $pdf->SetTextColor($FontColor[0],$FontColor[1],$FontColor[2]); // Color in R, G, B
 			
                    $Name = $field['Name'];
                    $Value = $data[0][$Name];
                    $Value = iconv("UTF-8", "ISO-8859-1//TRANSLIT", $Value); // Convert UTf8
                    // FontStyle
                    switch ($field[Type]) {
                    case 0: // Char
													$pdf->Cell(0,0,$Value,0,1,$field[Align]);
                        break;
                    case 1: // Num
                        $Value = number_format($Value, $field[NumberDecimal],$Numeric_decimal_symbol,$Numeric_symbol_of_thousands);
													$pdf->Cell(0,0,$Value,0,1,$field[Align]);
                        break;
                    case 2: // Integer
													$pdf->Cell(0,0,$Value,0,1,$field[Align]);
                        break;
                    case 3: // Date
                        // $date = date_create($Value);
                        // $Value = date_format($date, $Date_format);
													$Value = strftime($Date_format, strtotime($Value));
													$pdf->Cell(0,0,$Value,0,1,$field[Align]);
                        break;
                    case 4: // Time
                        // $date = date_create($Value);
                        // $Value = date_format($date, $Time_format);
													$Value = strftime($Time_format, strtotime($Value));
													$pdf->Cell(0,0,$Value,0,1,$field[Align]);
                        break;
                     case 5: // DateTime
                        // $date = date_create($Value);
                        // $Value = date_format($date, $Date_and_time_format);
													$Value = strftime($Date_and_time_format, strtotime($Value));
													$pdf->Cell(0,0,$Value,0,1,$field[Align]);
                        break;   
                     case 6: // Date Long
                        // $date = date_create($Value);
                        // $Value = date_format($date, $Long_Date_Format);
                        $Value = strftime($Long_Date_Format, strtotime($Value));
													$pdf->Cell(0,0,$Value,0,1,$field[Align]);
                        break;   
                     case 7: // Boolean
                        $pdf->SetFont('ZapfDingbats',$field['FontStyle'],$field['FontSize']); //  Font, type and size
                        If ($Value == 1) {$Value = '4';} else {$Value = '';} // 'l' Punto negro
													$pdf->Cell(0,0,$Value,0,1,$field[Align]);
                        break;   
                     case 8: // Memo
													$pdf->Write(5, $Value);
                        break;   
                    default:
													$pdf->Cell(0,0,$Value,0,1,$field[Align]);
                        }

		}

	}
        if ($page <> $TotalPagesTemplate) {
            //  adding the second page of the template
            $tplIdx2 = $pdf->importPage($page+1);
            $s = $pdf->getTemplatesize($tplIdx2);
            $pdf->AddPage('', $s);
            $pdf->useImportedPage($tplIdx2);
        }
}
$pdf->Output('I','forms.pdf');
/*
// --------------------  foot to save the new PDF document ------------------
$temp_file = tempnam(sys_get_temp_dir(), 'PDF');
$pdf->Output('F',$temp_file);

// ------------------ Operation with file result -------------------------------------------
$documento = file_get_contents($temp_file);
unlink($temp_file);  // delete file tmp
header("Content-Disposition: attachment; filename= forms.pdf");
header('Content-Type: application/pdf');
echo $documento;
*/


?>

capture_sql_fields.php

<?php
$data = $button->getCurrentRecord();

// From the form selection
$l_idforms = $data['idforms'];
$l_code  = $data['Code'];
$l_name  = $data['Name'];
$l_table = $data['Table'];
$l_sql = $data['Query'];

global $conn;
// Delete fields of Query
$sql_1 = "delete FROM form_fields WHERE forms_idforms = $l_idforms";
$resql_1 = db_query($sql_1,$conn);
// Select fields of Query
$sql_1 = str_replace("#key", "1", $l_sql);
$resql_1 = db_query($sql_1,$conn);
$data2=$resql_1->fetch_all(MYSQLI_ASSOC);
//
$fields = array_keys($data2[0]);
foreach ($fields as $field) {
// Insert fields of query    
   $sql_1 = "
    Insert into form_fields
    (forms_idforms, Name)
    values ($l_idforms,'$field')";
    $resql_1 = db_query($sql_1,$conn);
}
?>

He utilizado un formulario de una Administración Pública de Madrid, para que fuese un caso real.

Tiene 2 páginas. En la segunda también dispone de campos.

DEMO. Disponéis de esta URL https://fhumanes.com/forms/ , por si lo deseáis probar (está en Español e Inglés). Claves de acceso «admin/admin»

También os dejo el proyecto (PHPRunner 10.2), el modelo de datos y un ejemplo de la Base de datos. Os dejo el fichero que va en el directorio “FILES” y que es la plantilla PDF del ejemplo.

Para cualquier duda o consulta, os dejo mi cuenta de email [email protected]