File: /var/www/api_matriculas/app/Exports/ComparativeReportExport.php
<?php
namespace App\Exports;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
class ComparativeReportExport implements WithMultipleSheets
{
protected $data;
public function __construct(array $data)
{
$this->data = $data;
}
public function sheets(): array
{
return [
new ComparativeIndicatorsSheet($this->data['periods'] ?? []),
new ComparativeFinancialSheet($this->data['periods'] ?? []),
new ComparativeMovementsSheet($this->data['movements'] ?? []),
];
}
}
// ─── Hoja 1: Indicadores ─────────────────────────────────────
class ComparativeIndicatorsSheet implements
\Maatwebsite\Excel\Concerns\FromArray,
\Maatwebsite\Excel\Concerns\WithHeadings,
\Maatwebsite\Excel\Concerns\WithTitle,
\Maatwebsite\Excel\Concerns\ShouldAutoSize
{
protected $periods;
public function __construct(array $periods)
{
$this->periods = $periods;
}
public function headings(): array
{
$headers = ['Indicador'];
foreach ($this->periods as $period) {
$headers[] = $period['label'] ?? '';
}
return $headers;
}
public function array(): array
{
$indicators = [
['key' => 'total', 'label' => 'Total contratos'],
['key' => 'total_students', 'label' => 'Alumnos únicos'],
['key' => 'finished', 'label' => 'Matrículas cerradas'],
['key' => 'in_course', 'label' => 'En curso'],
['key' => 'pending_payment', 'label' => 'Pendientes de pago'],
['key' => 'pending_signature', 'label' => 'Pendientes de firma'],
['key' => 'canceled', 'label' => 'Canceladas / Retiro'],
['key' => 'desistimiento_count', 'label' => 'Desistimiento'],
];
$rows = [];
foreach ($indicators as $indicator) {
$row = [$indicator['label']];
foreach ($this->periods as $period) {
$row[] = $period['stats'][$indicator['key']] ?? 0;
}
$rows[] = $row;
}
return $rows;
}
public function title(): string
{
return 'Indicadores';
}
}
// ─── Hoja 2: Financiero ──────────────────────────────────────
class ComparativeFinancialSheet implements
\Maatwebsite\Excel\Concerns\FromArray,
\Maatwebsite\Excel\Concerns\WithHeadings,
\Maatwebsite\Excel\Concerns\WithTitle,
\Maatwebsite\Excel\Concerns\ShouldAutoSize
{
protected $periods;
public function __construct(array $periods)
{
$this->periods = $periods;
}
public function headings(): array
{
$headers = ['Indicador'];
foreach ($this->periods as $period) {
$headers[] = $period['label'] ?? '';
}
return $headers;
}
public function array(): array
{
$indicators = [
['key' => 'total', 'label' => 'Total facturado'],
['key' => 'paid', 'label' => 'Total recaudado'],
['key' => 'pending', 'label' => 'Pendiente por cobrar'],
];
$rows = [];
foreach ($indicators as $indicator) {
$row = [$indicator['label']];
foreach ($this->periods as $period) {
$row[] = round($period['financial'][$indicator['key']] ?? 0);
}
$rows[] = $row;
}
return $rows;
}
public function title(): string
{
return 'Financiero';
}
}
// ─── Hoja 3: Movimientos ─────────────────────────────────────
class ComparativeMovementsSheet implements
\Maatwebsite\Excel\Concerns\FromArray,
\Maatwebsite\Excel\Concerns\WithTitle,
\Maatwebsite\Excel\Concerns\ShouldAutoSize
{
protected $movements;
public function __construct(array $movements)
{
$this->movements = $movements;
}
public function array(): array
{
$rows = [];
$headers = [
'Código', 'Alumno', 'RUT Alumno', 'Curso', 'Nivel',
'Apoderado', 'RUT Apoderado', 'Email Apoderado', 'Teléfono Apoderado',
'Estado Contrato', 'Estado Pago', 'Estado Firma',
'Matrícula Pagada', 'Código Toku',
'Total ($)', 'Pagado ($)', 'Pendiente ($)',
];
foreach ($this->movements as $movement) {
$periodTo = $movement['period_to']['label'] ?? '';
$periodFrom = $movement['period_from']['label'] ?? '';
// Sección: Nuevos ingresos
$rows[] = ["NUEVOS INGRESOS EN {$periodTo}"];
$rows[] = $headers;
foreach ($movement['nuevos_ingresos']['contracts'] ?? [] as $contract) {
$rows[] = $this->contractToRow($contract);
}
if (empty($movement['nuevos_ingresos']['contracts'])) {
$rows[] = ['Sin registros'];
}
$rows[] = ['']; // Separador
// Sección: Desistimiento
$rows[] = ["DESISTIMIENTO / RETIRO DESDE {$periodFrom}"];
$rows[] = $headers;
foreach ($movement['desistimiento']['contracts'] ?? [] as $contract) {
$rows[] = $this->contractToRow($contract);
}
if (empty($movement['desistimiento']['contracts'])) {
$rows[] = ['Sin registros'];
}
$rows[] = [''];
}
return $rows;
}
protected function contractToRow($contract)
{
$student = $contract['students'][0] ?? [];
return [
$contract['code_contract'] ?? '',
$student['full_name'] ?? '',
$student['rut'] ?? '',
$student['course'] ?? '',
$student['course_level'] ?? '',
$contract['financial_parent']['full_name'] ?? '',
$contract['financial_parent']['rut'] ?? '',
$contract['financial_parent']['email'] ?? '',
$contract['financial_parent']['mobile'] ?? '',
$contract['status_contract']['description'] ?? '',
$contract['status_payment']['description'] ?? '',
$contract['status_signature']['description'] ?? '',
($contract['matricula_paid'] ?? false) ? 'Sí' : 'No',
$contract['code_toku'] ?? '',
$contract['total_amount_clp'] ?? 0,
$contract['total_paid_clp'] ?? 0,
$contract['total_pending_clp'] ?? 0,
];
}
public function title(): string
{
return 'Movimientos';
}
}