{{-- Chart.js + Annotation plugin --}}
@php
$pd = $pageDetails; // shorthand
$imgBase = $imageBaseUrl;
$companyName = optional($case->company)->name ?? '';
$customerName = optional($case->customer)->name ?? '';
$address = optional($case->address)->address ?? '';
$identNo = $case->identification_no ?? '';
$reportNo = $case->report_no ?? '';
$cycleType = $case->type_of_cycle ?? '';
$roomType = $case->type_of_room ?? '';
$minRange = $case->min_operating_range ?? '';
$maxRange = $case->max_operating_range ?? '';
$performedOn = $case->performedOnDate ? \Carbon\Carbon::parse($case->performedOnDate)->format('d-M-Y') : '';
$nextDue = $case->next_due_date ? \Carbon\Carbon::parse($case->next_due_date)->format('d-M-Y') : '';
$preparedBy = optional($case->preparedBy)->name ?? '';
$checkedBy = optional($case->checkedBy)->name ?? '';
$reviewedBy = optional($case->reviewedBy)->name ?? '';
$approvedBy = optional($case->approvedBy)->name ?? '';
$mkt = $case->mkt ?? '';
// Helper: get image src or null
function imgSrc($images, $name, $base) {
$f = $images->get($name);
if (!$f) return null;
$path = $f->file ?? $f->path ?? ($f->name ?? '');
return $base . ltrim($path, '/');
}
@endphp
{{-- ════════════════════════════════════════════════════════════════════════
PAGE 1 — COVER / TABLE OF CONTENTS
════════════════════════════════════════════════════════════════════════ --}}
{{-- Company header --}}
{{ $companyName }}
{{ $address }}
TABLE OF CONTENTS
@php
$tocItems = [
'Objective & Identification' => '02',
'Area / Equipment Details' => '03',
$pd && $pd->ac ? 'AC Details' : null => $pd && $pd->ac ? '04' : null,
'Location Diagram' => '05',
'Schematic Diagrams' => '06',
'Isometric Views' => '07',
'Position of Data Loggers' => '08',
'Data Logger Positions Table' => '09',
$pd && ($pd->continuous_cycle_1||$pd->continuous_cycle_2||$pd->continuous_cycle_3) ? 'Continuous Operation Cycles' : null => '10',
$pd && ($pd->door_cycle_1||$pd->door_cycle_2||$pd->door_cycle_3) ? 'Door Open Test Cycles' : null => '11',
$pd && ($pd->power_cycle_1||$pd->power_cycle_2||$pd->power_cycle_3) ? 'Power Failure Cycles' : null => '12',
'Summary of Parameters' => '13',
$pd && $pd->remark ? 'Observation & Concluding Remarks' : null => $pd && $pd->remark ? '14' : null,
'MKT Analysis' => '15',
'Hot Spot / Cold Spot Diagrams' => '16',
$pd && $pd->risk ? 'Risk Analysis' : null => $pd && $pd->risk ? '17' : null,
'List of Annexures' => '18',
];
@endphp
@foreach($tocItems as $label => $page)
@if($label)
{{ $label }}
{{ $page }}
@endif
@endforeach
{{-- Report meta footer --}}
Report No: {{ $reportNo }}
Identification No: {{ $identNo }}
Date of Study: {{ $performedOn }}
{{-- ════════════════════════════════════════════════════════════════════════
PAGE 2 — TITLE / OBJECTIVE
════════════════════════════════════════════════════════════════════════ --}}
@include('reports.partials.report-header', ['title' => 'THERMAL QUALIFICATION STUDY REPORT'])
| PARTICULARS |
DETAILS |
| OBJECTIVE |
To perform Thermal Qualification Study for the area/equipment described herein and verify that the temperature distribution is within the acceptable range as per the approved protocol. |
| CUSTOMER NAME | {{ $customerName }} |
| CUSTOMER ADDRESS | {{ $address }} |
| TYPE OF ROOM / EQUIPMENT | {{ $roomType }} |
| CYCLE TYPE | {{ $cycleType }} |
| IDENTIFICATION NO. | {{ $identNo }} |
| REPORT NO. | {{ $reportNo }} |
| OPERATING RANGE | {{ $minRange }}°C to {{ $maxRange }}°C |
| DATE OF STUDY PERFORMED | {{ $performedOn }} |
| NEXT DUE DATE | {{ $nextDue }} |
@include('reports.partials.signatures')
{{-- ════════════════════════════════════════════════════════════════════════
PAGE 3 — AREA/EQUIPMENT DETAILS + INSTRUMENTATION + MAPPING
════════════════════════════════════════════════════════════════════════ --}}
@include('reports.partials.report-header', ['title' => 'AREA / EQUIPMENT DETAILS'])
| AREA / EQUIPMENT IDENTIFICATION |
| {{ $identNo }} |
{{ $roomType }} |
| {{ $minRange }}°C |
{{ $maxRange }}°C |
| {{ $case->pos1 ?? 'N/A' }} |
{{ $case->pos2 ?? 'N/A' }} |
| INSTRUMENTATION DETAILS |
| SR. NO. |
INSTRUMENT USED |
MAKE / MODEL |
CALIBRATION VALIDITY |
| 1 |
Data Logger |
Vega / VL-Series |
As per Calibration Certificate |
| MAPPING CYCLE DETAILS |
| {{ $cycleType }} |
| {{ $performedOn }} |
@include('reports.partials.signatures')
{{-- ════════════════════════════════════════════════════════════════════════
PAGE 4 — AC DETAILS (conditional)
════════════════════════════════════════════════════════════════════════ --}}
@if($pd && $pd->ac && $acDetail)
@include('reports.partials.report-header', ['title' => 'AIR CONDITIONING DETAILS'])
@php
$volArea = is_string($acDetail->volume_area) ? json_decode($acDetail->volume_area, true) : (array)$acDetail->volume_area;
$indNos = is_string($acDetail->indication_number) ? json_decode($acDetail->indication_number, true) : (array)$acDetail->indication_number;
@endphp
| A/C UNIT DETAILS |
| {{ $acDetail->ac_unit_type ?? 'N/A' }} |
{{ $acDetail->switching_type ?? 'N/A' }} |
| {{ $acDetail->installed_cooling_capacity ?? 'N/A' }} |
{{ $acDetail->cooling_units_installed ?? 'N/A' }} |
| {{ $acDetail->no_blowers_installed ?? 'N/A' }} |
{{
is_array($indNos)
? implode(', ', array_map(fn($v) => is_array($v) ? implode('', $v) : $v, $indNos))
: ($indNos ?? 'N/A')
}}
|
@if(is_array($volArea) && count($volArea))
| VOLUME / AREA DETAILS |
| # | Description | Value |
@foreach($volArea as $i => $va)
| {{ $i+1 }} |
{{ $va['description'] ?? '' }} |
{{ $va['value'] ?? '' }} |
@endforeach
@endif
@include('reports.partials.signatures')
@endif
{{-- ════════════════════════════════════════════════════════════════════════
PAGE 5 — LOCATION DIAGRAM PLACEHOLDER
════════════════════════════════════════════════════════════════════════ --}}
@include('reports.partials.report-header', ['title' => 'LOCATION DIAGRAM'])
LOCATION DIAGRAM
Attach physical map / floor plan here
{{-- ════════════════════════════════════════════════════════════════════════
PAGES 6-12 — SCHEMATIC IMAGES (up to 7)
════════════════════════════════════════════════════════════════════════ --}}
@for($s = 1; $s <= 7; $s++)
@php $src = imgSrc($images, "schematic_{$s}", $imgBase); @endphp
@if($src)
@include('reports.partials.report-header', ['title' => "SCHEMATIC DIAGRAM – {$s}"])
@endif
@endfor
{{-- ════════════════════════════════════════════════════════════════════════
ISOMETRIC IMAGES (up to 6)
════════════════════════════════════════════════════════════════════════ --}}
@for($s = 1; $s <= 6; $s++)
@php $src = imgSrc($images, "isometric_{$s}", $imgBase); @endphp
@if($src)
@include('reports.partials.report-header', ['title' => "ISOMETRIC VIEW – {$s}"])
@endif
@endfor
{{-- ════════════════════════════════════════════════════════════════════════
POSITION LOGGER IMAGES (up to 5)
════════════════════════════════════════════════════════════════════════ --}}
@for($s = 1; $s <= 5; $s++)
@php $src = imgSrc($images, "postion_logger_{$s}", $imgBase); @endphp
@if($src)
@include('reports.partials.report-header', ['title' => "POSITION OF DATA LOGGERS – {$s}"])
@endif
@endfor
{{-- ════════════════════════════════════════════════════════════════════════
DATA LOGGER POSITION TABLE (20 rows per page)
════════════════════════════════════════════════════════════════════════ --}}
@foreach($loggerPages as $pageIndex => $loggers)
@include('reports.partials.report-header', ['title' => 'DATA LOGGER POSITIONS'])
| SR. NO. |
LOGGER ID |
POSITION DESCRIPTION |
LEFT SIDE WALL (m) |
FRONT SIDE WALL (m) |
DIST. FROM GROUND (m) |
@foreach($loggers as $i => $logger)
| {{ $pageIndex * 20 + $i + 1 }} |
{{ $logger->logger_id_no }} |
{{ $logger->position }} |
{{ $logger->left_side_wall }} |
{{ $logger->front_side_wall }} |
{{ $logger->distance_from_ground }} |
@endforeach
@endforeach
{{-- ════════════════════════════════════════════════════════════════════════
CYCLE SECTIONS — STARTUP / CONTINUOUS / DOOR OPEN / POWER FAILURE
Each enabled cycle renders: 1 title page + 1 WITH AMBIENT graph + 1 WITHOUT AMBIENT graph
════════════════════════════════════════════════════════════════════════ --}}
@php
$cycleGroups = [
[
'label' => 'START UP STUDY',
'flags' => [$pd->continuous_cycle_1 ?? false, $pd->continuous_cycle_2 ?? false, $pd->continuous_cycle_3 ?? false],
'key' => 'startup',
'hasDoor' => false,
],
[
'label' => 'CONTINUOUS OPERATION',
'flags' => [$pd->continuous_cycle_1 ?? false, $pd->continuous_cycle_2 ?? false, $pd->continuous_cycle_3 ?? false],
'key' => 'continuous',
'hasDoor' => false,
],
[
'label' => 'DOOR OPEN TEST',
'flags' => [$pd->door_cycle_1 ?? false, $pd->door_cycle_2 ?? false, $pd->door_cycle_3 ?? false],
'key' => 'door',
'hasDoor' => true,
],
[
'label' => 'POWER FAILURE TEST',
'flags' => [$pd->power_cycle_1 ?? false, $pd->power_cycle_2 ?? false, $pd->power_cycle_3 ?? false],
'key' => 'power',
'hasDoor' => true,
],
];
$romanNumerals = ['I', 'II', 'III'];
@endphp
@foreach($cycleGroups as $group)
@php $anyEnabled = in_array(true, $group['flags']); @endphp
@if($anyEnabled)
{{-- Section title page --}}
{{ $group['label'] }}
TEST CYCLES
@for($cycleIdx = 0; $cycleIdx < 3; $cycleIdx++)
@if($group['flags'][$cycleIdx])
@php
$roman = $romanNumerals[$cycleIdx];
$cycleNum = $cycleIdx + 1;
$catData = $categorised[$group['key']] ?? [];
$variants = $catData[$cycleNum] ?? ['with_ambient' => null, 'without_ambient' => null];
$ttWith = $variants['with_ambient'];
$ttWithout = $variants['without_ambient'];
// Door annotations for this cycle
$doorMeta = null;
if ($group['hasDoor'] && $doorTypeTests) {
$doorMeta = $doorTypeTests->first(fn($d) => str_contains(strtoupper($d->door_open_test_name ?? ''), 'CYCLE-' . $cycleNum) || str_contains(strtoupper($d->door_open_test_name ?? ''), 'CYCLE ' . $cycleNum));
}
@endphp
{{-- Cycle title page --}}
{{ $group['label'] }}
CYCLE – {{ $roman }}
{{-- WITH AMBIENT graph page --}}
@if($ttWith && isset($chartData[$ttWith->id]))
@include('reports.partials.graph-page', [
'chartEntry' => $chartData[$ttWith->id],
'ttId' => $ttWith->id,
'variant' => 'WITH AMBIENT',
'cycleLabel' => $group['label'] . ' CYCLE – ' . $roman,
'doorMeta' => $doorMeta,
'case' => $case,
])
@endif
{{-- WITHOUT AMBIENT graph page --}}
@if($ttWithout && isset($chartData[$ttWithout->id]))
@include('reports.partials.graph-page', [
'chartEntry' => $chartData[$ttWithout->id],
'ttId' => $ttWithout->id,
'variant' => 'WITHOUT AMBIENT',
'cycleLabel' => $group['label'] . ' CYCLE – ' . $roman,
'doorMeta' => $doorMeta,
'case' => $case,
])
@endif
@endif
@endfor
@endif
@endforeach
{{-- ════════════════════════════════════════════════════════════════════════
SUMMARY OF PARAMETERS — title page
════════════════════════════════════════════════════════════════════════ --}}
{{-- Parameter summary table — 15 sensors per page, all test types --}}
@foreach($tempStats as $ttId => $stats)
@php
$ttName = collect($categorised)->flatten(2)->pluck('name', 'id')->get($ttId, "Test Type {$ttId}");
$chunks = $stats->chunk(15);
@endphp
@foreach($chunks as $chunkIdx => $chunk)
@include('reports.partials.report-header', ['title' => 'SUMMARY OF PARAMETERS'])
{{ $ttName }}
| SR. NO. |
SENSOR |
MIN (°C) |
MAX (°C) |
AVG (°C) |
STD DEV |
REMARKS |
@foreach($chunk as $i => $row)
@php
$isHot = $row->sensor === $hotSpotSensor;
$isCold = $row->sensor === $coldSpotSensor;
$rowClass = $isHot ? 'hot' : ($isCold ? 'cold' : '');
@endphp
| {{ $chunkIdx * 15 + $i + 1 }} |
{{ $row->sensor }} |
{{ number_format((float)$row->min_temp, 2) }} |
{{ number_format((float)$row->max_temp, 2) }} |
{{ number_format((float)$row->avg_temp, 2) }} |
{{ number_format((float)$row->std_temp, 4) }} |
@if($isHot)
HOT SPOT
@elseif($isCold)
COLD SPOT
@else
WITHIN RANGE
@endif
|
@endforeach
@endforeach
@endforeach
{{-- ════════════════════════════════════════════════════════════════════════
OBSERVATION & CONCLUDING REMARKS (conditional)
════════════════════════════════════════════════════════════════════════ --}}
@if($pd && $pd->remark)
@include('reports.partials.report-header', ['title' => 'OBSERVATION & CONCLUDING REMARKS'])
| OBSERVATION REMARKS |
|
{{ $case->obeservation_remark ?? '–' }}
|
| CONCLUSION |
|
{{ $case->conclusion ?? '–' }}
|
| CONCLUDING REMARK |
|
{{ $case->concluding_remark ?? '–' }}
|
@include('reports.partials.signatures')
@endif
{{-- ════════════════════════════════════════════════════════════════════════
MKT PAGE
════════════════════════════════════════════════════════════════════════ --}}
@include('reports.partials.report-header', ['title' => 'MEAN KINETIC TEMPERATURE (MKT)'])
TMKT = ΔH/R ÷ −ln[ (e−ΔH/RT1 + … + e−ΔH/RTn) / n ]
| 83.144 kJ/mol |
| 8.3144 J/mol·K |
| {{ $mkt }}°C |
The Mean Kinetic Temperature (MKT) is a single derived temperature that, if maintained over a defined period of time, would afford the same thermal challenge to a pharmaceutical product as would be experienced over a range of both higher and lower temperatures for an equivalent defined period.
{{-- ════════════════════════════════════════════════════════════════════════
HOT SPOT / COLD SPOT IMAGES
════════════════════════════════════════════════════════════════════════ --}}
@php $hotSrc = imgSrc($images, 'hot_spot', $imgBase); @endphp
@php $coldSrc = imgSrc($images, 'cold_spot', $imgBase); @endphp
@if($hotSrc)
@include('reports.partials.report-header', ['title' => 'HOT SPOT LOCATION DIAGRAM'])
@endif
@if($coldSrc)
@include('reports.partials.report-header', ['title' => 'COLD SPOT LOCATION DIAGRAM'])
@endif
{{-- ════════════════════════════════════════════════════════════════════════
RISK ANALYSIS (conditional)
════════════════════════════════════════════════════════════════════════ --}}
@if($pd && $pd->risk)
@include('reports.partials.report-header', ['title' => 'RISK ANALYSIS'])
{{ $case->risk_analysis ?? '–' }}
@endif
{{-- ════════════════════════════════════════════════════════════════════════
LIST OF ANNEXURES
════════════════════════════════════════════════════════════════════════ --}}
@include('reports.partials.report-header', ['title' => 'LIST OF ANNEXURES'])
| SR. NO. |
ANNEXURE DESCRIPTION |
REFERENCE |
@php $annexNo = 1; @endphp
| {{ $annexNo++ }} | Area / Equipment Details | Annexure – A |
@if($pd && $pd->ac)
| {{ $annexNo++ }} | AC Details | Annexure – B |
@endif
| {{ $annexNo++ }} | Schematic Diagrams | Annexure – C |
| {{ $annexNo++ }} | Isometric Views | Annexure – D |
| {{ $annexNo++ }} | Position of Data Loggers | Annexure – E |
| {{ $annexNo++ }} | Temperature Graphs | Annexure – F |
| {{ $annexNo++ }} | Summary of Parameters | Annexure – G |
| {{ $annexNo++ }} | MKT Analysis | Annexure – H |
@if($pd && $pd->risk)
| {{ $annexNo++ }} | Risk Analysis | Annexure – I |
@endif
| {{ $annexNo++ }} | Calibration Certificates of Data Loggers | Annexure – J |
@include('reports.partials.signatures')
{{-- ════════════════════════════════════════════════════════════════════════
CHART.JS INITIALISATION — runs after DOM is ready
Sets window.__chartsReady = true so Browsershot knows to capture
════════════════════════════════════════════════════════════════════════ --}}