middleware('auth'); $this->_service = 'reports'; $this->_module = 'gennovadc_reports'; $this->_viewname = 'gennovadcreport'; $this->_title = 'My Dc Reports'; $this->_base_url = '/gennovadcreports'; } public function export(Request $request) { $hierids = $request->input('filter_hier', []); $type = $request->input('type', 0); $month = $request->input('month', date('F Y', strtotime('now'))); if ($type == 'monthsummary') { $monthlyResponse = LambdaRequest::signedrequest('get', 'reports', 'gennovadc_reports/monthly_summary', ['month' => $month, 'hierarchy_ids' => json_encode($hierids)]); $rows = []; $totals = []; $headers = []; $rawHeaders = []; if (!empty($monthlyResponse->data->item) && is_array($monthlyResponse->data->item)) { foreach ($monthlyResponse->data->item as $item) { $rawHeaders = array_unique(array_merge($rawHeaders, array_keys((array) $item))); } } usort($rawHeaders, function ($a, $b) { return $a === 'product_name' ? -1 : ($b === 'product_name' ? 1 : 0); }); $headers = array_map(function ($key) { return ucwords(str_replace('_', ' ', $key)); }, $rawHeaders); foreach ($monthlyResponse->data->item as $item) { $row = []; foreach ($rawHeaders as $header) { $value = $item->$header ?? ''; $row[] = $value; if (is_numeric($item->$header ?? null) && $header !== 'product_name' && $header !== 'percent_ach') { $totals[$header] = ($totals[$header] ?? 0) + $item->$header; } } $rows[] = $row; } $totalRow = []; foreach ($rawHeaders as $header) { if ($header === 'product_name') { $totalRow[] = 'Total'; } elseif ($header === 'percent_ach' && isset($totals['units_plan']) && $totals['units_plan'] > 0 && isset($totals['units_ach'])) { $totalRow[] = round(($totals['units_ach'] / $totals['units_plan']) * 100) . '%'; } else { $totalRow[] = $totals[$header] ?? ''; } } $rows[] = $totalRow; $excelData = []; $excelData[] = $headers; $excelData = array_merge($excelData, $rows); return Excel::download(new InvoicesExport($excelData), $type . '-report.xlsx'); } elseif ($type == 'weeksummary') { $weeklyResponse = LambdaRequest::signedrequest('get', 'reports', 'gennovadc_reports/weekly_summary', ['month' => $month, 'hierarchy_ids' => json_encode($hierids)]); $weeklyData = $weeklyResponse->data->item ?? []; $weeklySummary = []; $weeklyTotals = []; if (!empty($weeklyData)) { $firstItem = (array) $weeklyData[0]; foreach ($firstItem as $key => $value) { $label = ucwords(str_replace(['_', '-'], ' ', $key)); $weeklySummary[] = [ 'label' => $label, 'key' => $key, ]; if (is_numeric($value)) { $weeklyTotals[$key] = 0; } } foreach ($weeklyData as $item) { foreach ($weeklyTotals as $key => $_) { $weeklyTotals[$key] += $item->$key ?? 0; } } } $excelData = []; $excelData[] = array_column($weeklySummary, 'label'); foreach ($weeklyData as $row) { $rowData = []; foreach ($weeklySummary as $col) { $val = $row->{$col['key']} ?? ''; $rowData[] = is_numeric($val) ? (float) $val : $val; } $excelData[] = $rowData; } if (!empty($weeklyData)) { $totalRow = []; foreach ($weeklySummary as $col) { if ($col['key'] === 'product_name') { $totalRow[] = 'Total'; } elseif ($col['key'] === 'percent_ach') { $totalRow[] = $weeklyTotals['month_plan'] > 0 ? round(($weeklyTotals['units_ach'] / $weeklyTotals['month_plan']) * 100) . '%' : '0.00%'; } else { $totalRow[] = $weeklyTotals[$col['key']] ?? 0; } } $excelData[] = $totalRow; } return Excel::download(new InvoicesExport($excelData), 'weekly-summary.xlsx'); } elseif ($type == 'centersummary') { $centerResponse = LambdaRequest::signedrequest('get', 'reports', 'gennovadc_reports/center_summary', ['month' => $month, 'hierarchy_ids' => json_encode($hierids)]); $centerSummarySubmission = $centerResponse->data->item ?? []; $centerTotals = $centerResponse->data->total ?? null; $centerSummary = []; $excelData = []; if (!empty($centerSummarySubmission)) { $firstItem = (array) $centerSummarySubmission[0]; foreach ($firstItem as $key => $val) { $label = ucwords(str_replace(['_', '-'], ' ', $key)); $centerSummary[] = [ 'label' => $label, 'key' => $key, ]; } $excelData[] = array_column($centerSummary, 'label'); foreach ($centerSummarySubmission as $row) { $rowData = []; foreach ($centerSummary as $col) { $val = $row->{$col['key']} ?? ''; $rowData[] = is_numeric($val) ? (float) $val : $val; } $excelData[] = $rowData; } if ($centerTotals) { $totalRow = []; foreach ($centerSummary as $index => $col) { if ($index === 0) { $totalRow[] = 'Total'; continue; } $key = $col['key']; if ($key === 'percent_ach') { $plan = $centerTotals->centers_plan ?? 0; $ach = $centerTotals->centers_ach ?? 0; $percent = $plan > 0 ? round(($ach / $plan) * 100) : 0; $totalRow[] = $percent . '%'; } else { $val = $centerTotals->{$key} ?? 0; $totalRow[] = (float) $val; } } $excelData[] = $totalRow; } } return Excel::download(new InvoicesExport($excelData), 'center-summary.xlsx'); } elseif ($type == 'centertrendsummary') { $centerTrendResponse = LambdaRequest::signedrequest('get', 'reports', 'gennovadc_reports/center_trend_summary', ['hierarchy_ids' => json_encode($hierids)]); $centerTrendData = $this->trendReportDataArray($centerTrendResponse); $centerTrendSummarySubmission = $centerTrendData['item'] ?? []; $centerTrendTotals = (array) ($centerTrendData['total'] ?? []); $centerTrendSummary = $this->buildTrendSummaryColumns($centerTrendData); $excelData = []; $excelData[] = array_column($centerTrendSummary, 'name'); // header row // Data rows foreach ($centerTrendSummarySubmission as $row) { $rowData = []; $rowArr = (array) json_decode(json_encode($row), true); foreach ($centerTrendSummary as $col) { $val = $rowArr[$col['key']] ?? ''; $rowData[] = $val; } $excelData[] = $rowData; } // Total row if (!empty($centerTrendSummarySubmission)) { $totalRow = ['Total']; foreach (array_slice($centerTrendSummary, 1) as $col) { $val = $centerTrendTotals[$col['key']] ?? 0; $totalRow[] = $val; } $excelData[] = $totalRow; } return Excel::download(new InvoicesExport($excelData), 'center-trend-summary.xlsx'); } elseif ($type == 'unittrendsummary') { $unitTrendResponse = LambdaRequest::signedrequest('get', 'reports', 'gennovadc_reports/unit_trend_summary', ['hierarchy_ids' => json_encode($hierids)]); $unitTrendData = $this->trendReportDataArray($unitTrendResponse); $unitTrendSummarySubmission = $unitTrendData['item'] ?? []; $unitTrendSummary = $this->buildTrendSummaryColumns($unitTrendData); $unitTrendTotals = $this->trendReportTotals($unitTrendData, $unitTrendSummarySubmission, $unitTrendSummary); $excelData = []; $excelData[] = array_column($unitTrendSummary, 'name'); foreach ($unitTrendSummarySubmission as $row) { $rowData = []; $rowArr = (array) json_decode(json_encode($row), true); foreach ($unitTrendSummary as $col) { $val = $rowArr[$col['key']] ?? ''; $rowData[] = is_numeric($val) ? (float) $val : $val; } $excelData[] = $rowData; } if (!empty($unitTrendSummarySubmission)) { $totalRow = ['Total']; foreach (array_slice($unitTrendSummary, 1) as $col) { $val = $unitTrendTotals[$col['key']] ?? 0; $totalRow[] = (float) $val; } $excelData[] = $totalRow; } return Excel::download(new InvoicesExport($excelData), 'unit-trend-summary.xlsx'); } elseif ($type == 'transplantpenetration') { $response = LambdaRequest::signedrequest( 'get', 'reports', 'gennovadc_reports/transplant_penetration', ['month' => $month, 'hierarchy_ids' => json_encode($hierids)] ); $items = $response->data->transplant_penetration ?? []; $flatKeys = [ 'Transplant Type', 'Monthly Expected no. of Transplant', 'Gennova Share Dennovo Plan', 'Gennova Share Switch Plan', 'Gennova Share Graftsol Tx Plan', 'Total Actual Transplants', ]; $weekGroups = [ 'Gennova Share Dennovo Actual', 'Gennova Share Switch Actual', 'Gennova Share Graftsol Tx Actual', ]; $weeks = ['Week-1', 'Week-2', 'Week-3', 'Week-4']; $headerRow1 = $flatKeys; $headerRow2 = array_fill(0, count($flatKeys), ''); foreach ($weekGroups as $group) { $headerRow1[] = $group; $headerRow1 = array_merge($headerRow1, array_fill(0, count($weeks) - 1, '')); foreach ($weeks as $week) { $headerRow2[] = $week; } } $excelData = [$headerRow1, $headerRow2]; foreach ($items as $row) { $line = []; foreach ($flatKeys as $key) { $line[] = $this->reportCellValue($row, $key); } foreach ($weekGroups as $group) { foreach ($weeks as $week) { $line[] = $this->reportCellValue($row, $group, $week); } } $excelData[] = $line; } return Excel::download(new InvoicesExport($excelData), 'transplant-penetration.xlsx'); } elseif ($type == 'transplantsummary') { $response = LambdaRequest::signedrequest( 'get', 'reports', 'gennovadc_reports/transplant_summary', ['month' => $month, 'hierarchy_ids' => json_encode($hierids)] ); $items = $response->data->transplant_summary ?? ($response->data->item ?? []); $layout = $this->transplantSummaryTableLayout(); $headerRow1 = []; $headerRow2 = []; foreach ($layout['flat'] as $col) { $headerRow1[] = $col['label']; $headerRow2[] = ''; } foreach ($layout['groups'] as $group) { foreach ($group['columns'] as $i => $col) { $headerRow1[] = $i === 0 ? $group['name'] : ''; $headerRow2[] = $col['label']; } } $excelData = [$headerRow1, $headerRow2]; foreach ($items as $row) { $line = []; foreach ($layout['flat'] as $col) { $line[] = $this->reportCellValue($row, $col['key']); } foreach ($layout['groups'] as $group) { foreach ($group['columns'] as $col) { $line[] = $this->reportCellValue($row, $col['key']); } } $excelData[] = $line; } return Excel::download(new InvoicesExport($excelData), 'transplant-summary.xlsx'); } elseif ($type == 'activitysummary') { $response = LambdaRequest::signedrequest( 'get', 'reports', 'gennovadc_reports/activity_summary', ['month' => $month, 'hierarchy_ids' => json_encode($hierids)] ); $items = $response->data->activity_summary ?? ($response->data->item ?? []); $columns = $this->buildActivitySummaryColumns($items); $excelData = []; $excelData[] = array_column($columns, 'label'); foreach ($items as $row) { $line = []; foreach ($columns as $col) { $line[] = $col['child'] === null ? $this->reportCellValue($row, $col['parent']) : $this->reportCellValue($row, $col['parent'], $col['child']); } $excelData[] = $line; } return Excel::download(new InvoicesExport($excelData), 'activity-summary.xlsx'); } else { } } public function dashboard(Request $request) { // $permissions = json_decode(auth()->user()->permissions); // auth()->user()->permissions; // hierfilter $hierids = $request->input('filter_hier', []); // echo "
"; print_r($hierids); exit;
        // month
        $month = $request->input('month', date('F Y', strtotime('now')));

        // if(in_array('all_data_access', $permissions)){
        //     $monthlyResponse = LambdaRequest::signedrequest('get', 'reports', 'gennovadc_reports/monthly_summary', ['month' => $month, 'hierarchy_ids' => json_encode('1655447961-8182461d-8ae6-49f3-9317-0475db5d4da3')]);
        // }else{
            $monthlyResponse = LambdaRequest::signedrequest('get', 'reports', 'gennovadc_reports/monthly_summary', ['month' => $month, 'hierarchy_ids' => json_encode($hierids)]);
        // }
        
        
        $monthSummary = [];
        $numericKeys = [];

        if (!empty($monthlyResponse->data->item)) {
            $firstItem = (array) $monthlyResponse->data->item[0];
            foreach ($firstItem as $key => $val) {
                $monthSummary[] = ['name' => ucwords(str_replace('_', ' ', $key)), 'key' => $key];
                if ($key !== 'product_name' && is_numeric($val)) {
                    $numericKeys[] = $key;
                }
            }
        }

        $totals = [];
        foreach ($numericKeys as $key) {
            $totals[$key] = 0;
        }

        foreach ($monthlyResponse->data->item as $item) {
            foreach ($numericKeys as $key) {
                $totals[$key] += $item->{$key} ?? 0;
            }
        }

        // week
        $weeklyResponse = LambdaRequest::signedrequest('get', 'reports', 'gennovadc_reports/weekly_summary', ['month' => $month, 'hierarchy_ids' => json_encode($hierids)]);
        $weeklyData = $weeklyResponse->data->item ?? [];
        $weeklySummary = [];
        $weeklyTotals = [];
        if (!empty($weeklyData)) {
            $firstItem = (array) $weeklyData[0];

            foreach ($firstItem as $key => $value) {
                $label = ucwords(str_replace(['_', '-'], ' ', $key));

                $weeklySummary[] = [
                    'label' => $label,
                    'key' => $key,
                ];

                if (is_numeric($value)) {
                    $weeklyTotals[$key] = 0;
                }
            }

            foreach ($weeklyData as $item) {
                foreach ($weeklyTotals as $key => $_) {
                    $weeklyTotals[$key] += $item->$key ?? 0;
                }
            }
        }

        // center
        $centerResponse = LambdaRequest::signedrequest('get', 'reports', 'gennovadc_reports/center_summary', ['month' => $month, 'hierarchy_ids' => json_encode($hierids)]);
        $centerSummarySubmission = $centerResponse->data->item ?? [];
        $centerTotals = $centerResponse->data->total ?? null;

        $centerSummary = [];

        if (!empty($centerSummarySubmission)) {
            $firstItem = (array) $centerSummarySubmission[0];
            foreach ($firstItem as $key => $val) {
                $label = ucwords(str_replace(['_', '-'], ' ', $key));
                $centerSummary[] = ['name' => $label, 'key' => $key];
            }
        }

        // centertrend
        $centerTrendResponse = LambdaRequest::signedrequest('get', 'reports', 'gennovadc_reports/center_trend_summary', ['hierarchy_ids' => json_encode($hierids)]);
        $centerTrendData = $this->trendReportDataArray($centerTrendResponse);
        $centerTrendSummarySubmission = $centerTrendData['item'] ?? [];
        $centerTrendTotals = (array) ($centerTrendData['total'] ?? []);
        $centerTrendSummary = $this->buildTrendSummaryColumns($centerTrendData);

        $unitTrendResponse = LambdaRequest::signedrequest('get', 'reports', 'gennovadc_reports/unit_trend_summary', ['hierarchy_ids' => json_encode($hierids)]);
        $unitTrendData = $this->trendReportDataArray($unitTrendResponse);
        $unitTrendSummarySubmission = $unitTrendData['item'] ?? [];
        $unitTrendSummary = $this->buildTrendSummaryColumns($unitTrendData);
        $unitTrendTotals = $this->trendReportTotals($unitTrendData, $unitTrendSummarySubmission, $unitTrendSummary);

        // transplant penetration
        $transplantPenetrationResponse = LambdaRequest::signedrequest(
            'get',
            'reports',
            'gennovadc_reports/transplant_penetration',
            ['month' => $month, 'hierarchy_ids' => json_encode($hierids)]
        );
        $transplantPenetrationSubmission = $transplantPenetrationResponse->data->transplant_penetration ?? [];

        // transplant summary
        $transplantSummaryResponse = LambdaRequest::signedrequest(
            'get',
            'reports',
            'gennovadc_reports/transplant_summary',
            ['month' => $month, 'hierarchy_ids' => json_encode($hierids)]
        );
        $transplantSummarySubmission = $transplantSummaryResponse->data->transplant_summary
            ?? ($transplantSummaryResponse->data->item ?? []);

        $transplantSummaryLayout = $this->transplantSummaryTableLayout();
        $transplantSummaryFlat = $transplantSummaryLayout['flat'];
        $transplantSummaryGroups = $transplantSummaryLayout['groups'];

        // activity summary
        $activitySummaryResponse = LambdaRequest::signedrequest(
            'get',
            'reports',
            'gennovadc_reports/activity_summary',
            ['month' => $month, 'hierarchy_ids' => json_encode($hierids)]
        );
        $activitySummarySubmission = $activitySummaryResponse->data->activity_summary
            ?? ($activitySummaryResponse->data->item ?? []);

        $activitySummaryColumns = $this->buildActivitySummaryColumns($activitySummarySubmission);

        $permissions = json_decode(auth()->user()->permissions);
        
        if(in_array('all_data_access', $permissions)){
            
             $response = LambdaRequest::signedrequest(
            'get',
            'ums',
            'hierarchy/hierarchy_below_me',
            [
                'partition' => 'rapport-gennovadc',
                'hierarchy_id' => 'root'
            ]
            );

        }else{
           
           $response = LambdaRequest::signedrequest(
            'get',
            'ums',
            'hierarchy/hierarchy_below_me',
            [
                'partition' => 'rapport-gennovadc',
                'hierarchy_id' => []
            ]
        );
        }
        

        $hierarchies = $response->data->hierarchies ?? [];

        // $hierarchies = array_filter($hierarchies, function ($h) {
        //     return (int)$h->level !== 1;
        // });

        usort($hierarchies, function ($a, $b) {
            return $b->level <=> $a->level;
        });

        //echo '
'; print_r(['month' => $month, 'hierarchy_ids' => json_encode($hierids)]); print_r($transplantPenetrationSubmission); exit;
        // dd($hierarchies);
        return view($this->_viewname . '.dashboard', [
            'title' => 'My Dc Dashboard',
            'month' => $month,
            'filter_hier' => $hierarchies,

            'monthsummary' => $monthSummary,
            'monthsummarysubmission' => $monthlyResponse->data->item ?? [],
            'monthTotals' => $totals,

            'weeklysummarysubmission' => $weeklyResponse->data->item ?? [],
            'weeklysummary' => $weeklySummary,
            'weeklyTotals' => $weeklyTotals,

            'centersummarysubmission' => $centerSummarySubmission,
            'centersummary' => $centerSummary,
            'centerTotals' => $centerTotals,

            'centertrendsummarysubmission' => $centerTrendSummarySubmission,
            'centertrendsummary' => $centerTrendSummary,
            'centerTrendTotals' => $centerTrendTotals,

            'unittrendsummarysubmission' => $unitTrendSummarySubmission,
            'unittrendsummary' => $unitTrendSummary,
            'unitTrendTotals' => $unitTrendTotals,

            'transplantPenetrationSubmission' => $transplantPenetrationSubmission,

            'transplantSummarySubmission' => $transplantSummarySubmission,
            'transplantSummaryFlat' => $transplantSummaryFlat,
            'transplantSummaryGroups' => $transplantSummaryGroups,

            'activitySummarySubmission' => $activitySummarySubmission,
            'activitySummaryColumns' => $activitySummaryColumns,
        ]);
    }

    /** Normalize Lambda/API response to data array (handles nested body). */
    private function trendReportDataArray($response): array
    {
        if (!$response) {
            return [];
        }
        if (isset($response->body)) {
            $body = $response->body;
            if (is_string($body)) {
                $body = json_decode($body, true);
            } else {
                $body = json_decode(json_encode($body), true);
            }
            return is_array($body) ? ($body['data'] ?? []) : [];
        }
        if (isset($response->data)) {
            return json_decode(json_encode($response->data), true) ?: [];
        }
        return [];
    }

    /** Current month first, previous 11 (matches reports API rolling window). */
    private function rolling12MonthColumns(): array
    {
        $months = [];
        $cursor = now()->startOfMonth();
        for ($i = 0; $i < 12; $i++) {
            $d = $cursor->copy()->subMonths($i);
            $months[] = [
                'key' => strtoupper($d->format('M')) . '_' . $d->format('Y'),
                'label' => $d->format('M Y'),
            ];
        }
        return $months;
    }

    private function isLegacyFiscalMonthKey(string $key): bool
    {
        return (bool) preg_match('/^[A-Z]{3}$/', $key);
    }

    /** Use API months when present and year-aware; otherwise rolling 12 from today. */
    private function resolveTrendMonthColumns(array $data): array
    {
        $months = $data['months'] ?? [];
        if (is_array($months) && count($months) > 0) {
            $first = (array) ($months[0] ?? []);
            $firstKey = $first['key'] ?? '';
            if ($firstKey !== '' && !$this->isLegacyFiscalMonthKey($firstKey)) {
                return $months;
            }
        }
        return $this->rolling12MonthColumns();
    }

    /** Table columns for center / unit trend summary. */
    private function buildTrendSummaryColumns(array $data): array
    {
        $columns = [['name' => 'Product Name', 'key' => 'product_name']];
        foreach ($this->resolveTrendMonthColumns($data) as $month) {
            $month = (array) $month;
            if (empty($month['key'])) {
                continue;
            }
            $columns[] = [
                'name' => $month['label'] ?? $this->trendMonthKeyLabel($month['key']),
                'key' => $month['key'],
            ];
        }
        return $columns;
    }

    /** Totals row: use API total when present, else sum submission rows. */
    private function trendReportTotals(array $data, array $submission, array $columns): array
    {
        $apiTotal = $data['total'] ?? null;
        if (is_array($apiTotal) && !empty($apiTotal)) {
            return $apiTotal;
        }
        $totals = [];
        foreach (array_slice($columns, 1) as $col) {
            $totals[$col['key']] = 0;
        }
        foreach ($submission as $item) {
            $itemArr = (array) json_decode(json_encode($item), true);
            foreach (array_slice($columns, 1) as $col) {
                $totals[$col['key']] += $itemArr[$col['key']] ?? 0;
            }
        }
        return $totals;
    }

    private function trendMonthKeyLabel(string $key): string
    {
        if (preg_match('/^([A-Z]{3})_(\d{4})$/', $key, $m)) {
            $ts = strtotime($m[1] . ' 1 ' . $m[2]);
            if ($ts) {
                return date('M Y', $ts);
            }
        }
        return $key;
    }

    private function reportCellValue($row, string $key, ?string $nestedKey = null)
    {
        if ($nestedKey === null) {
            if (is_object($row) && isset($row->{$key})) {
                return $row->{$key};
            }
            if (is_array($row) && array_key_exists($key, $row)) {
                return $row[$key];
            }
            return '';
        }

        $parent = $this->reportCellValue($row, $key);
        if (is_object($parent) && isset($parent->{$nestedKey})) {
            return $parent->{$nestedKey};
        }
        if (is_array($parent) && array_key_exists($nestedKey, $parent)) {
            return $parent[$nestedKey];
        }

        return '';
    }

    private function transplantSummaryTableLayout(): array
    {
        return [
            'flat' => [
                ['key' => 'Position Codes', 'label' => 'Position Co'],
                ['key' => 'Total Transplants Plan', 'label' => 'Total Transplants Expected'],
                ['key' => 'Total Transplants Actual', 'label' => 'Total Transplants Actual'],
                ['key' => 'Gennova Share Denovo Plan', 'label' => 'Gennova Share Denovo plan'],
                ['key' => 'Gennova Share Denovo Actual', 'label' => 'Gennova Share Denovo Actual'],
                ['key' => 'Gennova Share Switch Plan', 'label' => 'Gennova Share Switch plan'],
                ['key' => 'Gennova Share Switch Actual', 'label' => 'Gennova Share Switch Actual'],
                ['key' => 'Gennova Share Graftsol Tx Plan', 'label' => 'Gennova Share Graftsol Tx plan'],
                ['key' => 'Gennova Share Graftsol Tx Actual', 'label' => 'Gennova Share Graftsol Tx Actual'],
            ],
            'groups' => [
                [
                    'name' => 'Kidney Transplant',
                    'columns' => [
                        ['key' => 'Kidney Tx Actual', 'label' => 'Kidney Tx Actual'],
                        ['key' => 'Kidney Gennova Share Denovo Actual', 'label' => 'Gennova Share Denovo Actual'],
                        ['key' => 'Kidney Gennova Share Switch Actual', 'label' => 'Gennova Share Switch Actual'],
                        ['key' => 'Kidney Gennova Share Graftsol Tx Actual', 'label' => 'Gennova Share Graftsol Tx Actual'],
                    ],
                ],
                [
                    'name' => 'Liver Transplant',
                    'columns' => [
                        ['key' => 'Liver Tx Actual', 'label' => 'Liver Tx Actual'],
                        ['key' => 'Liver Gennova Share Denovo Actual', 'label' => 'Gennova Share Denovo Actual'],
                        ['key' => 'Liver Gennova Share Switch Actual', 'label' => 'Gennova Share Switch Actual'],
                        ['key' => 'Liver Gennova Share Graftsol Tx Actual', 'label' => 'Gennova Share Graftsol Tx Actual'],
                    ],
                ],
                [
                    'name' => 'Cardioplegia',
                    'columns' => [
                        ['key' => 'Cardioplegia Plan', 'label' => 'Cardioplegia Expected'],
                        ['key' => 'Cardioplegia Actual', 'label' => 'Cardioplegia Actual'],
                        ['key' => 'Gennova Share Graftsol Cardioplegia', 'label' => 'Gennova Share Graftsol Cardioplegia'],
                    ],
                ],
            ],
        ];
    }

    private function buildActivitySummaryColumns($submission): array
    {
        if (empty($submission)) {
            return [];
        }

        $hiddenCols = ['Position_id', 'Position_owner'];
        $first = (array) ($submission[0] ?? []);
        $flatCols = [];
        $nestedCols = [];

        $fmtLabel = function (string $s): string {
            $s = str_replace('_', ' ', $s);
            $s = preg_replace('/\s+/', ' ', trim($s)) ?: '';

            return ucwords(strtolower($s));
        };

        foreach ($first as $key => $val) {
            if (in_array($key, $hiddenCols, true)) {
                continue;
            }
            if (is_object($val) || is_array($val)) {
                foreach ((array) $val as $subKey => $_) {
                    $nestedCols[] = [
                        'label' => $fmtLabel($key) . ' - ' . $fmtLabel((string) $subKey),
                        'parent' => $key,
                        'child' => $subKey,
                    ];
                }
            } else {
                $flatCols[] = [
                    'label' => $fmtLabel($key),
                    'parent' => $key,
                    'child' => null,
                ];
            }
        }

        $preferred = ['Product Name', '8. Activity', 'Activity', 'Month Plan', 'Month Actl', 'Month Actual', 'Month Plan '];
        $ordered = [];

        foreach ($preferred as $p) {
            foreach ($flatCols as $i => $c) {
                if (($c['label'] ?? '') === $p) {
                    $ordered[] = $c;
                    unset($flatCols[$i]);
                    break;
                }
            }
        }

        $months = [];
        $rest = [];
        foreach ($flatCols as $c) {
            $label = (string) ($c['label'] ?? '');
            if (preg_match('/^[A-Za-z]{3}-\d{2}$/', $label)) {
                $months[] = $c;
            } else {
                $rest[] = $c;
            }
        }

        usort($months, function ($a, $b) {
            $al = (string) ($a['label'] ?? '');
            $bl = (string) ($b['label'] ?? '');
            $ad = \DateTime::createFromFormat('M-y', $al);
            $bd = \DateTime::createFromFormat('M-y', $bl);
            $at = $ad ? $ad->getTimestamp() : 0;
            $bt = $bd ? $bd->getTimestamp() : 0;

            return $bt <=> $at;
        });

        return array_values(array_merge($ordered, $rest, $months, $nestedCols));
    }

}