@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 = 'processor-drawings';
} 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')
@endif
@endif
@if($isDesigner || $isOfficeAdmin)
@endif
@if(!$isRestrictedRole)
Job Pipeline
@php
$stages = [['lead','Lead'],['consult','Consult'],['quote','Quotes'],['contracts','Contracts'],['sold','Sold'],['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 < 9)
@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']))
@endif
@endif
@if(session('success'))
{{ session('success') }}
@endif
@if(session('error'))
{{ session('error') }}
@endif
@if($isFactoryEmployee)
{{-- FACTORY EMPLOYEE: Assigned Tasks + Processor Drawing Documents tabs --}}
Processor Drawing Documents
@include('jobs.partials._processor_drawings_tab')
@elseif($isRestrictedRole)
{{-- PROCESSOR: Employee Task Assignments + Processor Drawing Documents tabs --}}
Manufacture
@if($job->sent_to_manufacture)
Sent to manufacture by {{ $job->sentToManufactureBy?->name ?? 'Unknown' }}
on {{ $job->sent_to_manufacture_at?->format('d M Y, g:i A') }}.
Factory employees can now see and work on this job.
@else
When ready, send this job to the factory floor. Factory employees will be notified and can start their assigned tasks.
@endif
@if(!$job->sent_to_manufacture)
Send To Manufacture
@else
Already Sent
@endif
@if($job->sent_to_manufacture)
Manufacture Status
@php
$empAssignments = $job->employeeTaskAssignments->groupBy('user_id');
@endphp
@if($empAssignments->count() > 0)
@foreach($empAssignments as $userId => $assignments)
@php $emp = $assignments->first()->user; @endphp
{{ $emp?->initials ?? '?' }}
{{ $emp?->name ?? 'Unknown' }}
@foreach($assignments as $a)
@php
$badge = match($a->task_status) {
'completed' => 'badge-green',
'in_progress' => 'badge-blue',
'paused' => 'badge-yellow',
default => 'badge-gray',
};
@endphp
{{ $a->taskType?->name }} — {{ ucfirst(str_replace('_',' ',$a->task_status)) }}
@endforeach
@endforeach
@else
No task assignments yet. Factory employees will see this job based on their configured tasks.
@endif
@endif
{{-- Confirmation popup --}}
Send To Manufacture?
Job {{ $job->job_number }}
This will make the job visible to all factory employees and automatically create task assignments based on each employee's configured tasks. This action cannot be undone.
Cancel
Processor Drawing Documents
@include('jobs.partials._processor_drawings_tab')
@elseif($isTrades)
{{-- ── TRADES: simplified job view ──────────────────────────────────────── --}}
View Plan Documents
@include('jobs.partials._processor_drawings_tab')
Job Details
Job Number {{ $job->job_number }}
Status {{ ucwords(str_replace('_',' ',$job->status)) }}
Project Type {{ $job->project_type ? implode(', ', array_map('ucfirst', (array)$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)
@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.
Assign Trade
@if($job->tradeUsers->count())
@foreach($job->tradeUsers as $tu)
{{ $tu->initials }}
{{ $tu->name }}
@endforeach
@else
No trades workers assigned yet.
@endif
@endif
@if($canSeeOverview)
Overview
Task
@endif
@if($canSeeWorksOrder)
Works Order
@endif
@if($canSeePayments)
@endif
@if($canSeeVariants)
Variations
@endif
@if($canSeeInvoices)
Invoices
@endif
@if($canSeeDocuments)
Documents
@endif
@if(auth()->user()->role->name == 'processor')
Processor Drawings
@endif
@if(auth()->user()->role->name == 'factory_employee')
Processor Drawings
@endif
@if($canSeeOverview)
Job Details
Project Type {{ $job->project_type ? implode(', ', array_map('ucfirst', (array)$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)
@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)
@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)
@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
@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')
@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)
@php $job->loadMissing(['variants.items.materialType', 'variants.respondedBy', 'variants.quote']); @endphp
Job Variation
@if(in_array(auth()->user()->role?->name, ['office_admin','project_manager','sales_consultant','accounts']))
Add Variation
@endif
@if(isset($variantRevenue) && $job->variants->where('status','accepted')->count())
@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) }}
incl. GST
@endif
@if($variant->description)
{{ $variant->description }}
@endif
{{-- Material items table --}}
@if($variant->items->count())
Description
Code
Unit
Qty
Retail
Total
@foreach($variant->items as $item)
{{ $item->description }}
{{ $item->item_code ?? '—' }}
{{ $item->unit ?? 'Each' }}
{{ number_format((float)$item->qty, 2) }}
${{ number_format((float)$item->retail_price, 2) }}
${{ number_format($item->retailTotal(), 2) }}
@endforeach
Subtotal (ex. GST)
${{ number_format($variant->totalRetail(), 2) }}
GST (10%)
${{ number_format($variant->totalRetail() * 0.10, 2) }}
Total (inc. GST)
${{ number_format($variant->totalRetail() * 1.10, 2) }}
@endif
@if($variant->stripe_payment_status)
Payment: {{ ucfirst(str_replace('_',' ',$variant->stripe_payment_status)) }}
@endif
@if($variant->status === 'pending' && in_array(auth()->user()->role?->name, ['office_admin','project_manager','sales_consultant','accounts']))
@elseif($variant->status === 'rejected')
Rejected{{ $variant->responded_at ? ' on '.$variant->responded_at->format('d M Y') : '' }}
@elseif($variant->status === 'accepted')
Accepted{{ $variant->responded_at ? ' on '.$variant->responded_at->format('d M Y') : '' }}
@endif
@empty
No Variations yet for this job.
@endforelse
{{-- Add Variation Modal with Material Picker --}}
@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']))
@endif
@empty
No invoices recorded yet.
@endforelse
@if(in_array(auth()->user()->role?->name, ['office_admin','project_manager','accounts']))
@endif
@endif
@if($canSeeDocuments)
@endif
@include('jobs.partials._processor_drawings_tab')
@endif {{-- end non-trades / processor view --}}
@endsection
@push('scripts')
@endpush