{{-- 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
Identification No. {{ $identNo }} Type of Room / Equipment {{ $roomType }}
Operating Range (Min) {{ $minRange }}°C Operating Range (Max) {{ $maxRange }}°C
Sensor Position 1 {{ $case->pos1 ?? 'N/A' }} Sensor Position 2 {{ $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
Cycle Type {{ $cycleType }}
Date of Study {{ $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
AC Unit Type {{ $acDetail->ac_unit_type ?? 'N/A' }} Switching Type {{ $acDetail->switching_type ?? 'N/A' }}
Installed Cooling Capacity {{ $acDetail->installed_cooling_capacity ?? 'N/A' }} Cooling Units Installed {{ $acDetail->cooling_units_installed ?? 'N/A' }}
No. of Blowers Installed {{ $acDetail->no_blowers_installed ?? 'N/A' }} Indication Number(s) {{ is_array($indNos) ? implode(', ', array_map(fn($v) => is_array($v) ? implode('', $v) : $v, $indNos)) : ($indNos ?? 'N/A') }}
@if(is_array($volArea) && count($volArea)) @foreach($volArea as $i => $va) @endforeach
VOLUME / AREA DETAILS
#DescriptionValue
{{ $i+1 }} {{ $va['description'] ?? '' }} {{ $va['value'] ?? '' }}
@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}"])
Schematic {{ $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}"])
Isometric {{ $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}"])
Logger Position {{ $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']) @foreach($loggers as $i => $logger) @endforeach
SR. NO. LOGGER ID POSITION DESCRIPTION LEFT SIDE WALL (m) FRONT SIDE WALL (m) DIST. FROM GROUND (m)
{{ $pageIndex * 20 + $i + 1 }} {{ $logger->logger_id_no }} {{ $logger->position }} {{ $logger->left_side_wall }} {{ $logger->front_side_wall }} {{ $logger->distance_from_ground }}
@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 ════════════════════════════════════════════════════════════════════════ --}}

SUMMARY OF PARAMETERS

{{-- 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 }}
@foreach($chunk as $i => $row) @php $isHot = $row->sensor === $hotSpotSensor; $isCold = $row->sensor === $coldSpotSensor; $rowClass = $isHot ? 'hot' : ($isCold ? 'cold' : ''); @endphp @endforeach
SR. NO. SENSOR MIN (°C) MAX (°C) AVG (°C) STD DEV REMARKS
{{ $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 {{-- ════════════════════════════════════════════════════════════════════════ 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 ]
ΔH (Activation Energy)83.144 kJ/mol
R (Gas Constant)8.3144 J/mol·K
Calculated MKT{{ $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'])
Hot Spot
@endif @if($coldSrc)
@include('reports.partials.report-header', ['title' => 'COLD SPOT LOCATION DIAGRAM'])
Cold Spot
@endif {{-- ════════════════════════════════════════════════════════════════════════ RISK ANALYSIS (conditional) ════════════════════════════════════════════════════════════════════════ --}} @if($pd && $pd->risk)

RISK ANALYSIS

@include('reports.partials.report-header', ['title' => 'RISK ANALYSIS'])
{{ $case->risk_analysis ?? '–' }}
@endif {{-- ════════════════════════════════════════════════════════════════════════ LIST OF ANNEXURES ════════════════════════════════════════════════════════════════════════ --}}
@include('reports.partials.report-header', ['title' => 'LIST OF ANNEXURES']) @php $annexNo = 1; @endphp @if($pd && $pd->ac) @endif @if($pd && $pd->risk) @endif
SR. NO. ANNEXURE DESCRIPTION REFERENCE
{{ $annexNo++ }}Area / Equipment DetailsAnnexure – A
{{ $annexNo++ }}AC DetailsAnnexure – B
{{ $annexNo++ }}Schematic DiagramsAnnexure – C
{{ $annexNo++ }}Isometric ViewsAnnexure – D
{{ $annexNo++ }}Position of Data LoggersAnnexure – E
{{ $annexNo++ }}Temperature GraphsAnnexure – F
{{ $annexNo++ }}Summary of ParametersAnnexure – G
{{ $annexNo++ }}MKT AnalysisAnnexure – H
{{ $annexNo++ }}Risk AnalysisAnnexure – I
{{ $annexNo++ }}Calibration Certificates of Data LoggersAnnexure – J
@include('reports.partials.signatures')
{{-- ════════════════════════════════════════════════════════════════════════ CHART.JS INITIALISATION — runs after DOM is ready Sets window.__chartsReady = true so Browsershot knows to capture ════════════════════════════════════════════════════════════════════════ --}}