Rapport-Laravel/app/Http/Controllers/ZenovaReportController.php

349 lines
11 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Exports\ZenovaReportExport;
use App\Helpers\ZenovaReportAccess;
use App\Http\Requests\LambdaRequest;
use Illuminate\Http\Request;
use Maatwebsite\Excel\Facades\Excel;
class ZenovaReportController extends Controller
{
public function __construct()
{
$this->middleware('auth');
$this->middleware(function ($request, $next) {
if (!ZenovaReportAccess::canView()) {
abort(403);
}
return $next($request);
});
$this->_service = 'reports';
$this->_module = 'zenova_reports';
$this->_viewname = 'zenovareport';
$this->_title = 'Glipiq & Sitazit Dashboard';
$this->_base_url = '/zenovareport';
}
public function list(Request $request)
{
return redirect('/zenovareport/dashboard');
}
public function dashboard(Request $request)
{
$level = $this->level($request);
$built = $this->build($level);
return view('zenovareport.dashboard', [
'title' => $this->_title,
'level' => $level,
'groups' => $built['groups'],
'body' => $built['body'],
'totals' => $built['totals'],
'error' => $built['error'],
]);
}
public function export(Request $request)
{
$level = $this->level($request);
$built = $this->build($level);
if ($built['error']) {
return redirect('/zenovareport/dashboard?level=' . $level)->with('error', $built['error']);
}
return Excel::download(
new ZenovaReportExport($built['groups'], $built['raw_body'], $built['raw_totals']),
'glipiq-sitazit-level-' . $level . '.xlsx'
);
}
private function level(Request $request): int
{
$level = (int) $request->input('level', 3);
return ($level >= 1 && $level <= 5) ? $level : 3;
}
private function build(int $level): array
{
$response = LambdaRequest::signedrequest(
'get',
'reports',
'zenova_reports/glipiqsitazit_report',
['level' => (string) $level],
120
);
$rows = [];
$error = null;
if (!$response || ($response->status ?? '') !== 'success') {
$error = $response->message ?? 'Unable to load the Glipiq & Sitazit report.';
} else {
$rows = is_array($response->data ?? null) ? $response->data : [];
}
$groups = $this->groups($rows);
$columns = [];
foreach ($groups as $group) {
foreach ($group['columns'] as $column) {
$columns[] = $column;
}
}
$body = [];
$rawBody = [];
$rawTotals = array_fill(0, count($columns), 0);
foreach ($rows as $row) {
$line = [];
$rawLine = [];
foreach ($columns as $index => $column) {
$raw = $this->rawValue($row, $column);
if ($column['type'] !== 'text') {
$rawTotals[$index] += $raw;
}
$rawLine[] = $raw;
$line[] = $this->formatValue($raw, $column['type']);
}
$body[] = $line;
$rawBody[] = $rawLine;
}
$totals = [];
$rawTotalLine = [];
if (!empty($rows)) {
$fsos = $this->sumKey($rows, 'Demography & Details', 'No. of FSOs');
$glipiqActive = $this->sumKey($rows, 'Demography & Details', 'Glipiq Active FSOs');
$sitazitActive = $this->sumKey($rows, 'Demography & Details', 'Sitazit Active FSOs');
foreach ($columns as $index => $column) {
if ($column['type'] === 'text') {
$label = !empty($column['is_total']) ? 'Total' : '';
$totals[] = $label;
$rawTotalLine[] = $label;
continue;
}
if ($column['key'] === 'Glipiq Active FSO %') {
$percent = $fsos ? ($glipiqActive / $fsos) * 100 : 0;
$totals[] = $this->formatValue($percent, 'percent');
$rawTotalLine[] = $percent;
continue;
}
if ($column['key'] === 'Sitazit Active FSO %') {
$percent = $fsos ? ($sitazitActive / $fsos) * 100 : 0;
$totals[] = $this->formatValue($percent, 'percent');
$rawTotalLine[] = $percent;
continue;
}
$totals[] = $this->formatValue($rawTotals[$index], $column['type']);
$rawTotalLine[] = $rawTotals[$index];
}
}
return [
'groups' => $groups,
'body' => $body,
'totals' => $totals,
'raw_body' => $rawBody,
'raw_totals' => $rawTotalLine,
'error' => $error,
];
}
private function groups(array $rows): array
{
$nameKey = 'Name of Region';
foreach ($rows as $row) {
$demo = (array) ($row->{'Demography & Details'} ?? []);
foreach (array_keys($demo) as $key) {
if (strpos($key, 'Name of ') === 0) {
$nameKey = $key;
break 2;
}
}
}
$demoColumns = $this->geoColumns($nameKey);
$currentType = strtolower(preg_replace('/^Name of /', '', $nameKey));
if (!in_array($currentType, ['zone', 'region', 'area'], true)) {
$nameColumn = $this->column($nameKey, 'Demography & Details', $nameKey, 'text');
$nameColumn['is_total'] = true;
$demoColumns[] = $nameColumn;
}
foreach ([
'No. of FSOs' => 'number',
'No. of DSMs' => 'number',
'Glipiq Active FSOs' => 'number',
'Glipiq Active FSO %' => 'percent',
'Sitazit Active FSOs' => 'number',
'Sitazit Active FSO %' => 'percent',
] as $key => $type) {
$demoColumns[] = $this->column($key, 'Demography & Details', $key, $type);
}
$dayMetrics = ['GLIPIQ Total Rx', 'ABSI Camp Count', 'Patients Screened Count', 'Sitazit Total RX'];
$periodMetrics = [
'GLIPIQ Total Rx',
'GLIPIQ New Conversion',
'ABSI Camp Count',
'Patients Screened Count',
'GLIPIQ Total POB Units',
'Sitazit Total RX',
'Sitazit New Conversions',
'Sitazit Total POB Units',
];
$groups = [
['label' => 'Demography & Details', 'tone' => 'demo', 'columns' => $demoColumns],
];
$first = isset($rows[0]) ? $rows[0] : null;
foreach ([
'day5' => 'Day 5 Status',
'day4' => 'Day 4 Status',
'day3' => 'Day 3 Status',
'day2' => 'Day 2 Status',
] as $section => $title) {
$groups[] = [
'label' => $this->periodLabel($title, $this->sectionField($first, $section, 'date')),
'tone' => 'day',
'columns' => $this->metricColumns($section, $dayMetrics),
];
}
$groups[] = [
'label' => $this->periodLabel('Day 1 / Yesterday', $this->sectionField($first, 'day1', 'date')),
'tone' => 'yesterday',
'columns' => $this->metricColumns('day1', $dayMetrics),
];
$groups[] = [
'label' => $this->periodLabel('Today', $this->sectionField($first, 'today', 'date')),
'tone' => 'today',
'columns' => $this->metricColumns('today', $periodMetrics),
];
$groups[] = [
'label' => $this->periodLabel('MTD', $this->sectionField($first, 'mtd', 'period')),
'tone' => 'mtd',
'columns' => $this->metricColumns('mtd', $periodMetrics),
];
$groups[] = [
'label' => $this->periodLabel('YTD', $this->sectionField($first, 'ytd', 'period')),
'tone' => 'ytd',
'columns' => $this->metricColumns('ytd', $periodMetrics),
];
return $groups;
}
private function geoColumns($nameKey)
{
$currentType = preg_replace('/^Name of /', '', $nameKey);
$columns = [];
foreach (['Zone', 'Region', 'Area'] as $type) {
if (strcasecmp($currentType, $type) === 0) {
$column = $this->column($type, 'Demography & Details', $nameKey, 'text');
$column['is_total'] = true;
$columns[] = $column;
continue;
}
$columns[] = $this->column($type, 'parent_positions', $type, 'text');
}
return $columns;
}
private function column(string $label, string $section, string $key, string $type): array
{
return [
'label' => $label,
'section' => $section,
'key' => $key,
'type' => $type,
];
}
private function metricColumns(string $section, array $metrics): array
{
$columns = [];
foreach ($metrics as $metric) {
$columns[] = $this->column($metric, $section, $metric, 'number');
}
return $columns;
}
private function periodLabel(string $title, string $period): string
{
return $period !== '' ? $title . ' (' . $period . ')' : $title;
}
private function sectionField($row, $section, $field)
{
if (!is_object($row) || !isset($row->{$section}) || !is_object($row->{$section})) {
return '';
}
$value = $row->{$section}->{$field} ?? '';
return $value === null ? '' : (string) $value;
}
private function rawValue($row, array $column)
{
if ($column['section'] === 'parent_positions') {
$parents = (array) ($row->parent_positions ?? []);
foreach ($parents as $key => $parentValue) {
if (strcasecmp((string) $key, 'Country') === 0) {
continue;
}
if (strcasecmp((string) $key, $column['key']) === 0) {
return ($parentValue === null || $parentValue === '') ? '' : (string) $parentValue;
}
}
return '';
}
$section = $row->{$column['section']} ?? null;
$value = is_object($section) ? ($section->{$column['key']} ?? null) : null;
if ($column['type'] === 'text') {
return ($value === null || $value === '') ? '-' : (string) $value;
}
return is_numeric($value) ? (float) $value : 0;
}
private function sumKey(array $rows, string $section, string $key): float
{
$total = 0;
foreach ($rows as $row) {
$value = $row->{$section}->{$key} ?? 0;
if (is_numeric($value)) {
$total += (float) $value;
}
}
return $total;
}
private function formatValue($value, $type)
{
if ($type === 'text') {
return (string) $value;
}
$number = (float) $value;
if ($type === 'percent') {
return number_format($number, 2) . '%';
}
if (floor($number) == $number) {
return number_format($number, 0);
}
return number_format($number, 2);
}
}