Skip to content
203 changes: 199 additions & 4 deletions Controller/ListReport.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
use FacturaScripts\Core\Tools;
use FacturaScripts\Dinamic\Model\CodeModel;
use FacturaScripts\Dinamic\Lib\Informes\ReportGenerator;
use FacturaScripts\Dinamic\Model\Report;
use FacturaScripts\Dinamic\Model\ReportBoard;

/**
* Description of ListReport
Expand All @@ -31,6 +33,9 @@
*/
class ListReport extends ListController
{
/** variable para pasar la info a la vista twig */
public array $twigData = [];

public function getPageData(): array
{
$data = parent::getPageData();
Expand Down Expand Up @@ -97,15 +102,30 @@ protected function createViewsReportBoard(string $viewName = 'ListReportBoard'):
'icon' => 'fa-solid fa-wand-magic-sparkles',
'label' => 'generate',
]);

// boton del asistente
$this->addButton($viewName, [
'action' => $this->url() . '?action=custom-board-assistant',
'confirm' => false,
'icon' => 'fa-solid fa-hat-wizard',
'label' => 'generate-time-boards',
'type' => 'link'
]);
}

protected function execPreviousAction($action)
{
if ('generate-boards' === $action) {
return $this->generateBoardsAction();
}

return parent::execPreviousAction($action);
switch($action) {
case 'generate-boards':
return $this->generateBoardsAction();
case 'custom-board-assistant':
return $this->showCustomBoardAssistant();
case 'process-custom-board':
return $this->processCustomBoardAction();
default:
return parent::execPreviousAction($action);
}
}

protected function generateBoardsAction(): bool
Expand All @@ -122,4 +142,179 @@ protected function generateBoardsAction(): bool
Tools::log()->notice('items-added-correctly', ['%num%' => $total]);
return true;
}

/**
* Devuelve una lista con las tablas que tienen almenos una columna de tipo date o timestamp y array con las columnas
* Ej:
* return ['nomTabla' => ['colA', 'colB', 'colC'], ...]
*/
private function getTablesWithDate(): array
{
$tablesWithDate = [];
$tables = $this->dataBase->getTables();
foreach ($tables as $table) {
$colsWithDate = [];
$cols = $this->dataBase->getColumns($table);
foreach ($cols as $colName => $colData) {
$type = strtolower($colData['type']);

/**
* En la búsqueda mirando en los tipos que devuelve getColumns para todas las tablas he visto que;
* En mariadb (similar a sql) devuelve:
* - date
* - time
* - timestamp
* En postgresql es diferente:
* - date
* - timestamp without time zone
* - time without time zone
*/
if (in_array($type, ['date', 'timestamp', 'timestamp without time zone'])) {
$colsWithDate[] = $colName;
}
}

if (count($colsWithDate) > 0) {
$tablesWithDate[$table] = $colsWithDate;
}
}

return $tablesWithDate;
}

/**
* Crea una pizarra con varias gráficas relacionadas con un campo tipo fecha o timestamp.
* Se tiene que pasar una tabla y fecha válidos.
* Devuelve el código del tablero si está ok o false.
* Se debe usar una transaction desde fuera (por si no se crea correctamente).
*
* El nombre de la pizarra es "Tablero de $column sobre el campo de fecha $table."
* Se crearán informes con altura 250 y ancho 6 en la pizarra con los siguientes nombres:
* - "$tabla, $campo / hora" (Si es timestamp)
* - "$tabla, $campo / semana"
* - "$tabla, $campo / mese"
* - "$tabla, $campo / año"
*/
public function createDateBoard(string $table, string $column): bool|ReportBoard
{
$board = new ReportBoard();
$board->name = Tools::lang()->trans('report-board-title-date', ['%column%' => $column, '%table%' => $table]);
if (false === $board->save()) {
Tools::log()->error('error-creating-report-board');
return false;
}

$reportsToCreate = [];

// revisar si es timestamp para añadir la hora
$cols = $this->dataBase->getColumns($table);
$colType = strtolower($cols[$column]['type'] ?? '');
if (in_array($colType, ['timestamp', 'timestamp without time zone'])) {
$reportsToCreate['HOUR'] = Tools::lang()->trans('report-by-hour', ['%column%' => $column, '%table%' => $table]);
}

// añadir las semanas, meses y años
$reportsToCreate['WEEK'] = Tools::lang()->trans('report-by-week', ['%column%' => $column, '%table%' => $table]);
$reportsToCreate['MONTHS'] = Tools::lang()->trans('report-by-month', ['%column%' => $column, '%table%' => $table]);
$reportsToCreate['YEAR'] = Tools::lang()->trans('report-by-year', ['%column%' => $column, '%table%' => $table]);

$pos = 1;
foreach ($reportsToCreate as $xOp => $name) {
$report = new Report();
$report->name = $name;
$report->table = $table;
$report->xcolumn = $column;
$report->xoperation = $xOp;
$report->ycolumn = '';
$report->yoperation = '';
$report->type = Report::TYPE_BAR;

if ($report->save()) {
$board->addLine($report, $pos++);
}
}

Tools::log()->notice('report-board-title-date-created', ['%column%' => $column, '%table%' => $table]);
return $board;
}

protected function processCustomBoardAction(): bool
{
$table = $this->request->queryOrInput('selectedTable', '');
$column = $this->request->queryOrInput('selectedColumn', '');

if (empty($table) || empty($column)) {
Tools::log()->error('missing-parameters');
return false;
}

if (false === $this->dataBase->tableExists($table)) {
Tools::log()->error('table-not-found', ['%tableName%' => $table]);
return false;
}

// revisar que exista la columna
$tableCols = $this->dataBase->getColumns($table);
if (false === array_key_exists($column, $tableCols)) {
Tools::log()->error('column-not-found', ['%columnName%' => $column, '%tableName%' => $table]);
return false;
}

// revisar que sea tipo date la columna
if (false === in_array(strtolower($tableCols[$column]['type']), ['date', 'timestamp', 'timestamp without time zone'])) {
Tools::log()->error('column-not-date', ['%columnName%' => $column, '%tableName%' => $table]);
return false;
}

// Está todo ok, procesar la petición con los tados recibidos:
$db = $this->db();
$db->beginTransaction();
$newBoard = $this->createDateBoard($table, $column);
if (false === $newBoard) {
$db->rollback();
Tools::log()->error('error-creating-report-board');
return false;
}

// aceptar la transacción y redirigir al panel
$db->commit();
$this->redirect($newBoard->url('edit'));

return true;
}

/**
* Muestra el asistente para escoger columnas date y timestamp de las tablas
*
* 2 fases:
* 1. Tabla a escoger
* 2. Columna de la tabla
*/
protected function showCustomBoardAssistant()
{
// preparar el formulario
$tablesWithDate = $this->getTablesWithDate();

// tabla de tablas
$tables = array_keys($tablesWithDate); // recoger solo claves
$this->twigData['tables'] = array_combine($tables, $tables); // combine para que sean mismo key/value

$selectedTable = $this->request->queryOrInput('selectedTable', '');
if (!empty($selectedTable)) {
// comprobar que la tabla existe
if (false === $this->dataBase->tableExists($selectedTable)) {
Tools::log()->error('table-not-found', ['%tableName%' => $selectedTable]);
return false;
}

// asignar en el twig tabla seleccionada
$this->twigData['selectedTable'] = $selectedTable;

// mostrar columnas que son date o datetime
$columns = $tablesWithDate[$selectedTable];
$this->twigData['columns'] = array_combine($columns, $columns); // combine para que sean mismo key/value
}

$this->setTemplate('CustomBoardAssistant');
}
}
8 changes: 8 additions & 0 deletions Lib/ReportChart/Chart.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ protected function getSqlMySQL(Report $report): string
. "' ELSE '" . Tools::lang()->trans('does-not-have-a-value') . "' END";
break;

case 'HOUR':
$xCol = "DATE_FORMAT(" . $report->xcolumn . ", '%H')";
break;

case 'DAY':
$xCol = "DATE_FORMAT(" . $report->xcolumn . ", '%Y-%m-%d')";
break;
Expand Down Expand Up @@ -198,6 +202,10 @@ protected function getSqlPostgreSQL(Report $report): string
. "' ELSE '" . Tools::lang()->trans('does-not-have-a-value') . "' END";
break;

case 'HOUR':
$xCol = "to_char(" . $report->xcolumn . ", 'HH24')";
break;

case 'DAY':
$xCol = "to_char(" . $report->xcolumn . ", 'YY-MM-DD')";
break;
Expand Down
28 changes: 27 additions & 1 deletion Translation/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@
"expenses-pending-payment": "Unpaid expenses",
"featured": "Featured",
"fractional-payment-corporation-tax": "Fractional payment Corporate Tax",
"generate-time-boards": "Generate time boards",
"generate": "Generate",
"group-by-months": "Group by months",
"group-by-hour": "Group by hour",
"has-a-value": "Has a value",
"income-book": "Income ledger",
"income-book-description": "Registers all issued invoices",
Expand Down Expand Up @@ -242,5 +245,28 @@
"active-customers": "Active customers",
"active-customers-year": "Active customers this year",
"inactive-customers": "Deregistered customers",
"total-customers": "Total customers"
"total-customers": "Total customers",
"field-can-not-be-null": "The %fieldName% field cannot be empty.",
"table-not-found": "Table %tableName% not found.",
"no-data-found": "No data found.",
"step-1-title": "Step 1: Select the table",
"step-1-desc": "Choose the database table on which you want to generate the report. Only tables containing date fields appear.",
"step-2-title": "Step 2: Select the column",
"step-2-desc": "You have selected the table %table%. Now choose the main column for the report. Only date type columns appear.",
"column-not-found": "Column %columnName% not found in table %tableName%.",
"column-not-date": "Column %columnName% in table %tableName% is not a date type.",
"report-date-wizard": "Date report wizard",
"back": "Back",
"finish": "Finish",
"next": "Next",
"step-x-of-y": "Step %step% of %total%",
"column": "Column",
"table": "Table",
"report-board-title-date": "Board of %column% on date field %table%",
"report-board-title-date-created": "Board of %column% on date field %table% created successfully.",
"report-by-hour": "%table%, %column% / hour",
"report-by-week": "%table%, %column% / week",
"report-by-month": "%table%, %column% / month",
"report-by-year": "%table%, %column% / year",
"error-creating-report-board": "Error creating report board."
}
28 changes: 27 additions & 1 deletion Translation/es_ES.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@
"expenses-pending-payment": "Gastos pendientes de pago",
"featured": "Destacado",
"fractional-payment-corporation-tax": "Pago fraccionado Imp. Sociedades",
"generate-time-boards": "Generar tableros por fecha",
"generate": "Generar",
"group-by-months": "Agrupar por meses",
"group-by-hour": "Agrupar por hora",
"has-a-value": "Tiene valor",
"income-book": "Libro de ingresos",
"income-book-description": "Registra todas las facturas emitidas",
Expand Down Expand Up @@ -242,5 +245,28 @@
"active-customers": "Clientes activos",
"active-customers-year": "Clientes activos este año",
"inactive-customers": "Clientes dados de baja",
"total-customers": "Clientes totales"
"total-customers": "Clientes totales",
"field-can-not-be-null": "El campo %fieldName% no puede estar vacío.",
"table-not-found": "No se ha encontrado la tabla %tableName%.",
"no-data-found": "No se han encontrado datos.",
"step-1-title": "Paso 1: Selecciona la tabla",
"step-1-desc": "Elige la tabla de la base de datos sobre la que quieres generar el informe. Solo aparecen las tablas que contienen campos de fecha.",
"step-2-title": "Paso 2: Selecciona la columna",
"step-2-desc": "Has seleccionado la tabla %table%. Ahora elige la columna principal para el informe. Solo aparecen las columnas de tipo fecha.",
"column-not-found": "No se ha encontrado la columna %columnName% en la tabla %tableName%.",
"column-not-date": "La columna %columnName% de la tabla %tableName% no es de tipo fecha.",
"report-date-wizard": "Asistente de informes por fecha",
"back": "Volver",
"finish": "Finalizar",
"next": "Siguiente",
"step-x-of-y": "Paso %step% de %total%",
"column": "Columna",
"table": "Tabla",
"report-board-title-date": "Tablero de %column% sobre el campo de fecha %table%",
"report-board-title-date-created": "Tablero de %column% sobre el campo de fecha %table% creado correctamente.",
"report-by-hour": "%table%, %column% / hora",
"report-by-week": "%table%, %column% / semana",
"report-by-month": "%table%, %column% / mes",
"report-by-year": "%table%, %column% / año",
"error-creating-report-board": "Error al crear la pizarra de informes."
}
Loading