@extends('layouts.app') @section('title', $job->job_number) @section('breadcrumb'){{ isset($isTrades) && $isTrades ? 'My Jobs' : (isset($isDesigner) && $isDesigner ? 'My Jobs' : 'Jobs') }} {{ $job->job_number }}@endsection @section('content') @php $isTrades = isset($isTrades) && $isTrades; $isProcessor = isset($isProcessor) && $isProcessor; $isFactoryEmployee = isset($isFactoryEmployee) && $isFactoryEmployee; $isDesigner = isset($isDesigner) && $isDesigner; $isRestrictedRole = $isProcessor || $isFactoryEmployee; $authUser = auth()->user(); $isOfficeAdmin = $authUser->role?->name === 'office_admin'; // Tab visibility: office_admin always sees all tabs; others respect DB permissions $canSeeOverview = $isOfficeAdmin || $authUser->hasPermission('job_tabs.overview'); $canSeeWorksOrder = $isOfficeAdmin || $authUser->hasPermission('job_tabs.works_order'); $canSeePayments = $isOfficeAdmin || $authUser->hasPermission('job_tabs.payments'); $canSeeVariants = $isOfficeAdmin || $authUser->hasPermission('job_tabs.variants'); $canSeeInvoices = $isOfficeAdmin || $authUser->hasPermission('job_tabs.invoices'); $canSeeDocuments = $isOfficeAdmin || $authUser->hasPermission('job_tabs.documents'); // Default first visible tab if ($isFactoryEmployee) { $defaultTab = 'assigned-tasks'; } elseif ($isRestrictedRole) { $defaultTab = 'processor-drawings'; } elseif ($canSeeOverview) { $defaultTab = 'overview'; } elseif ($canSeeWorksOrder) { $defaultTab = 'works-order'; } elseif ($canSeePayments) { $defaultTab = 'payments'; } elseif ($canSeeVariants) { $defaultTab = 'variants'; } elseif ($canSeeInvoices) { $defaultTab = 'invoice'; } elseif ($canSeeDocuments) { $defaultTab = 'documents'; } else { $defaultTab = 'overview'; } @endphp
{{ $job->contact?->initials ?? '??' }}

{{ $job->contact?->full_name ?? 'Unknown' }}

{{ $job->stageLabel() }} @if($job->status === 'completed') Completed @endif
{{ $job->job_number }} · {{ $job->site_address }}, {{ $job->site_suburb }}
@if(!$isTrades && !$isRestrictedRole && !$isDesigner)
Edit @if(auth()->user()->role?->name === 'office_admin')
@csrf @method('DELETE')
@endif
@endif @if($isDesigner)
@if($job->quote) View Quote @else Prepare Quote @endif
@endif
@if(!$isRestrictedRole)

Job Pipeline

@php $stages = [['lead','Lead'],['consult','Consult'],['sold','Sold'],['contracts','Contracts'],['cm','Check Measure'],['processing','Processing'],['delivery','Delivery'],['installation','Install'],['completion','Complete']]; $currentIdx = array_search($job->stage, array_column($stages, 0)); @endphp @foreach($stages as $i => [$key, $label])
@if($i < $currentIdx)@else{{ $i + 1 }}@endif
{{ $label }}
@if($i < 8)
@endif @endforeach
{{-- ══════════════════════════════════════════════════════════════ PROCESSING STAGE SUB-TREE Visually branches from node 6 (Processing) in the stepper. Placed BEFORE Move to Stage so it sits inside the pipeline. Green = completed (with date), Blue = pending/in_progress. ══════════════════════════════════════════════════════════════ --}} @php $pipelineAssignments = $job->employeeTaskAssignments ?? collect(); $processingStageIdx = 5; @endphp @if($pipelineAssignments->count() > 0)
{{-- ── Vertical stem + Processing node label ── --}}
{{-- Left column: vertical line + dot aligned under step 6 --}} {{-- Right column: header + task list --}}
{{-- Header row --}}
Manufacturing {{ $pipelineAssignments->count() }} task(s)
{{-- Task rows --}}
@foreach($pipelineAssignments as $pAssign) @php $ptStatus = $pAssign->task_status ?? 'pending'; $ptDone = $ptStatus === 'completed'; $ptCompDate = $ptDone ? $pAssign->updated_at : null; $ptEmpName = $pAssign->user?->name ?? '—'; $ptEmpInit = strtoupper(substr($ptEmpName, 0, 1)); $ptTaskName = $pAssign->taskType?->name ?? '—'; @endphp
{{-- Branch dot --}}
{{-- Task card --}}
{{-- Employee avatar + name --}}
{{ $ptEmpInit }}
{{ $ptEmpName }}
· {{-- Task name --}} {{ $ptTaskName }} {{-- Status badge --}} @if($ptDone) Completed @elseif($ptStatus === 'in_progress') In Progress @elseif($ptStatus === 'paused') Paused @else Pending @endif {{-- Allocated hours --}} @if($pAssign->allocated_hours) {{ $pAssign->allocated_hours }}h allocated @endif {{-- Completion date --}} @if($ptDone && $ptCompDate) {{ $ptCompDate->format('d M Y') }} @endif
@endforeach
@endif @if(!$isTrades && !$isDesigner && in_array(auth()->user()->role?->name, ['office_admin','project_manager']))
@csrf
@endif
@endif @if(session('success'))
{{ session('success') }}
@endif @if(session('error'))
{{ session('error') }}
@endif @if($isFactoryEmployee) {{-- FACTORY EMPLOYEE: Assigned Tasks + Processor Drawing Documents tabs --}}

My Assigned Tasks — {{ $job->job_number }}

Tasks assigned by the processor for this job.

@if(isset($myTaskAssignments) && $myTaskAssignments->count() > 0)
@foreach($myTaskAssignments as $assignment)
{{ $assignment->taskType?->name ?? '—' }}
Employee Task · {{ $job->job_number }}
Active
@endforeach
@if($job->status !== 'completed')
Ready to log time?
Go to your timesheet to start a timer for these tasks.
My Timesheet
@endif @else

No tasks assigned to you for this job yet.

Contact your processor to assign tasks.

@endif
@include('jobs.partials._processor_drawings_tab')
@elseif($isRestrictedRole) {{-- PROCESSOR: Employee Task Assignments + Processor Drawing Documents tabs --}}

Factory Employee Task Assignments

Assign employee tasks to factory employees for this job.

@csrf {{-- Employee select --}}
{{-- Task checkboxes --}}
@foreach($employeeTaskTypes ?? [] as $tt) @endforeach
{{-- Dynamic hours inputs — one per selected task --}}
@php $assignments = $job->employeeTaskAssignments ?? collect(); @endphp @if($assignments->count() > 0)
@foreach($assignments->groupBy('user_id') as $userId => $userAssignments) @php $emp = $userAssignments->first()->user; @endphp
{{ $emp?->initials ?? '?' }}
{{ $emp?->name ?? 'Unknown' }}
{{ $userAssignments->count() }} {{ Str::plural('task', $userAssignments->count()) }}
@foreach($userAssignments as $assignment) @php $loggedMins = \App\Models\TimeEntry::where('user_id', $assignment->user_id) ->where('job_id', $assignment->job_id) ->where('task_type_id', $assignment->task_type_id) ->whereIn('status', ['paused','completed']) ->sum('duration_minutes'); $loggedHrs = round($loggedMins / 60, 2); $pct = ($assignment->allocated_hours > 0) ? min(100, round(($loggedHrs / $assignment->allocated_hours) * 100, 1)) : null; $statusBadges = ['pending'=>'badge-gray','in_progress'=>'badge-blue','paused'=>'badge-yellow','completed'=>'badge-green']; $sb = $statusBadges[$assignment->task_status ?? 'pending'] ?? 'badge-gray'; @endphp
{{ $assignment->taskType?->name ?? '—' }} {{ ucfirst(str_replace('_',' ', $assignment->task_status ?? 'pending')) }} @if($assignment->allocated_hours) Allocated: {{ $assignment->allocated_hours }}h @endif @if($assignment->task_status != 'completed')
@csrf @method('DELETE')
@endif
@if($assignment->allocated_hours && $pct !== null)
{{ $loggedHrs }}h / {{ $assignment->allocated_hours }}h logged {{ $pct }}%
@endif
@endforeach
@endforeach
@else
No employee tasks assigned yet for this job.
@endif
@include('jobs.partials._processor_drawings_tab')
@elseif($isTrades) {{-- ── TRADES: simplified job view ──────────────────────────────────────── --}}

Job Details

Job Number
{{ $job->job_number }}
Status
{{ ucwords(str_replace('_',' ',$job->status)) }}
Project Type
{{ $job->project_type ? ucfirst($job->project_type) : '—' }}
Expected Completion
{{ $job->expected_completion?->format('d M Y') ?? '—' }}
Site Address
{{ $job->site_address ?? '—' }}
Suburb
{{ $job->site_suburb ?? '—' }}, {{ $job->site_state ?? '' }} {{ $job->site_postcode ?? '' }}
@if($job->notes)
Notes

{{ $job->notes }}

@endif
@if($job->status !== 'completed') @else
This job is completed
No further time can be logged on completed jobs.
@endif
@if($job->contact)

Client

{{ $job->contact->initials }}
{{ $job->contact->full_name }}
{{ $job->contact->company ?? 'Individual' }}
@if($job->contact->phone) {{ $job->contact->phone }} @endif
@endif
@else {{-- ── FULL VIEW for non-trades (includes designer) ──────────────────────── --}} @if(in_array(auth()->user()->role?->name, ['office_admin','project_manager']) && $job->status !== 'completed')

Assigned Trades

Assign trades workers to this job. They will see it in their job list and can log time against it.

@if($job->tradeUsers->count())
@foreach($job->tradeUsers as $tu)
{{ $tu->initials }}
{{ $tu->name }}
@csrf @method('DELETE')
@endforeach
@else

No trades workers assigned yet.

@endif
@csrf
@endif
@if($canSeeOverview) @endif @if($canSeeWorksOrder) @endif @if($canSeePayments) @endif @if($canSeeVariants) @endif @if($canSeeInvoices) @endif @if($canSeeDocuments) @endif @if(auth()->user()->role->name == 'processor') @endif @if(auth()->user()->role->name == 'factory_employee') @endif
@if($canSeeOverview)

Job Details

Project Type
{{ $job->project_type ? ucfirst($job->project_type) : '—' }}
Design Style
{{ $job->design_style ?? '—' }}
Rooms
{{ $job->num_rooms ?? '—' }}
Source
{{ $job->source ?? '—' }}
Sale Date
{{ $job->sale_date?->format('d M Y') ?? '—' }}
Expected Completion
{{ $job->expected_completion?->format('d M Y') ?? '—' }}
@if($job->designer)
Designer
{{ $job->designer->name }}
@endif

Team

Consultant
{{ $job->consultant?->name ?? '—' }}
Project Manager
{{ $job->manager?->name ?? '—' }}
Site Address
{{ $job->site_address ?? '—' }}
Suburb
{{ $job->site_suburb ?? '—' }}, {{ $job->site_state ?? '' }} {{ $job->site_postcode ?? '' }}
@if($job->description)

Description

{{ $job->description }}

@endif @if($job->notes)

Notes

{{ $job->notes }}

@endif @if($job->next_action)
Next Action

{{ $job->next_action }}

@endif @if(isset($allTimeEntries) && $allTimeEntries->count() > 0)

Time Logged

Total hours logged {{ number_format($allTimeEntries->sum('duration_minutes') / 60, 1) }}h
@endif
@if(auth()->user()->role->id == 2 || auth()->user()->role->id== 10 || auth()->user()->role->id == 3)

Job Value

${{ number_format($job->job_value ?? 0) }}
Total job value
@foreach([['Deposit (30%)', ($job->job_value??0)*0.3],['CM (20%)',($job->job_value??0)*0.2],['Delivery (20%)',($job->job_value??0)*0.2],['Completion (30%)',($job->job_value??0)*0.3]] as [$lbl,$amt])
{{ $lbl }} ${{ number_format($amt) }}
@endforeach
@if($job->contact)

Client

{{ $job->contact->initials }}
{{ $job->contact->full_name }}
{{ $job->contact->company ?? 'Individual' }}
@if($job->contact->email) {{ $job->contact->email }} @endif @if($job->contact->phone) {{ $job->contact->phone }} @endif View full profile →
@endif @if($job->warranty_expiry)

Warranty

Expires {{ $job->warranty_expiry->format('d M Y') }}
{{ $job->warranty_expiry->diffForHumans() }}
@endif
@endif
@php $isAdmin = auth()->user()->role?->name === 'office_admin'; $tasks = \App\Models\Task::with(['assignee','creator']) ->where('job_id', $job->id) ->when(!$isAdmin, fn($q) => $q->where('assigned_to', auth()->id())) ->orderByRaw("FIELD(status,'to_do','in_progress','done')") ->orderBy('due_date') ->get(); @endphp @include('tasks.job_tasks', ['tasks' => $tasks, 'jobId' => $job->id, 'isAdmin' => $isAdmin])
@endif @if($canSeeWorksOrder)

Works Orders

Scope-of-works documents with trade task lines for this job

@if(in_array(auth()->user()->role?->name, ['office_admin','project_manager','accounts'])) New Works Order @endif
@forelse($job->worksOrders as $wo)
{{ $wo->order_number }} {{ $wo->statusLabel() }}
@if($wo->scope_of_works)

{{ Str::limit($wo->scope_of_works, 120) }}

@else

No scope documented yet

@endif
@if($wo->issued_date)Issued {{ $wo->issued_date->format('d M Y') }}@endif @if($wo->target_completion)Target {{ $wo->target_completion->format('d M Y') }}@endif @if($wo->items->count() > 0) {{ $wo->items->where('status','done')->count() }}/{{ $wo->items->count() }} tasks @endif
@if($wo->items->count() > 0) @php $pct = $wo->completionPct(); @endphp
{{ $pct }}%
@endif View →
@empty
No works orders yet
@if(in_array(auth()->user()->role?->name, ['office_admin','project_manager','accounts'])) Create first works order @endif
@endforelse @if($job->productionOrders->count() > 0)

Production / Manufacturing Orders {{ $job->productionOrders->count() }}

@foreach($job->productionOrders as $po)
{{ $po->order_number ?? ('PO-'.str_pad($po->id,4,'0',STR_PAD_LEFT)) }} {{ ucfirst(str_replace('_',' ',$po->status ?? 'pending')) }}
{{ $po->description ?? 'Production order' }}
Supplier: {{ $po->supplier ?? '—' }}@if($po->due_date) · Due: {{ \Carbon\Carbon::parse($po->due_date)->format('d M Y') }}@endif
@if($po->cost)
${{ number_format($po->cost) }}
@endif
@endforeach
@endif
@endif @if($canSeePayments)

Payment Schedule

@php $payments = [ ['Deposit (30%)', 'deposit_paid', ($job->job_value??0)*0.30, '#2563eb'], ['Check Measure (20%)', 'cm_paid', ($job->job_value??0)*0.20, '#7c3aed'], ['Delivery (20%)', 'delivery_paid', ($job->job_value??0)*0.20, '#d97706'], ['Final Payment (30%)', 'final_paid', ($job->job_value??0)*0.30, '#16a34a'], ]; @endphp
@foreach($payments as [$lbl, $field, $amt, $color])
{{ $lbl }}
${{ number_format($amt) }}
@if(auth()->user()->role?->name === 'office_admin')
@csrf @method('PATCH')
@endif
@endforeach

Payment Summary

@php $paid = collect(['deposit_paid','cm_paid','delivery_paid','final_paid']) ->filter(fn($f) => $job->$f) ->map(fn($f) => match($f) { 'deposit_paid' => ($job->job_value??0)*0.30, 'cm_paid' => ($job->job_value??0)*0.20, 'delivery_paid' => ($job->job_value??0)*0.20, 'final_paid' => ($job->job_value??0)*0.30, default => 0 })->sum(); $outstanding = ($job->job_value ?? 0) - $paid; $paidPct = ($job->job_value ?? 0) > 0 ? ($paid / $job->job_value) * 100 : 0; @endphp
Total Job Value${{ number_format($job->job_value ?? 0) }}
Received${{ number_format($paid) }}
Outstanding${{ number_format($outstanding) }}
Collection Progress{{ round($paidPct) }}%
@endif @if($canSeeVariants)

Job Variants

Track quote options presented to the client.

@if(in_array(auth()->user()->role?->name, ['office_admin','project_manager','sales_consultant','accounts'])) @endif
@if(isset($variantRevenue) && $job->variants->where('status','accepted')->count())
{{ $job->variants->where('status','accepted')->count() }} accepted variant(s) adding ${{ number_format($variantRevenue, 2) }} to job revenue
@endif @forelse($job->variants->sortByDesc('created_at') as $variant)
{{ ucfirst($variant->status) }}

{{ $variant->name }}

@if($variant->price_adjustment != 0)
{{ $variant->price_adjustment > 0 ? '+' : '' }}${{ number_format(abs($variant->price_adjustment), 2) }}
@endif
@if($variant->description)

{{ $variant->description }}

@endif @if($variant->status === 'pending' && in_array(auth()->user()->role?->name, ['office_admin','project_manager','sales_consultant']))
@csrf
@csrf
@endif
@empty

No variants yet for this job.

@endforelse

Add Variant

@csrf
@endif @if($canSeeInvoices)
@forelse($job->jobInvoices as $inv)
{{ $inv->invoice_number ?? 'No Invoice #' }} {{ $inv->invoice_date?->format('d M Y') ?? '—' }}
${{ number_format($inv->invoice_amount, 2) }}
@if($inv->note)

{{ $inv->note }}

@endif
@if(in_array(auth()->user()->role?->name, ['office_admin','project_manager']))
@csrf @method('DELETE')
@endif
@empty

No invoices recorded yet.

@endforelse @if(in_array(auth()->user()->role?->name, ['office_admin','project_manager','accounts']))

Add Invoice

@csrf
@endif
@endif @if($canSeeDocuments) @endif
@include('jobs.partials._processor_drawings_tab')
@endif {{-- end non-trades / processor view --}}
@endsection