@php // Provenance / type badge per row. Stock-backed material reads "From stock"; // everything else shows its category (material bought for the job => "Bought-in"). $typeBadge = [ 'material' => ['label' => __('Bought-in'), 'color' => 'bg-indigo-50 text-indigo-700 ring-indigo-200', 'icon' => 'archive-box'], 'finishing' => ['label' => __('Finishing'), 'color' => 'bg-violet-50 text-violet-700 ring-violet-200', 'icon' => 'sparkles'], 'outsourcing' => ['label' => __('Outsourced'), 'color' => 'bg-fuchsia-50 text-fuchsia-700 ring-fuchsia-200','icon' => 'building-office'], 'installation' => ['label' => __('Installation'), 'color' => 'bg-amber-50 text-amber-700 ring-amber-200', 'icon' => 'wrench-screwdriver'], 'transport' => ['label' => __('Transport'), 'color' => 'bg-sky-50 text-sky-700 ring-sky-200', 'icon' => 'truck'], 'labour' => ['label' => __('Labour'), 'color' => 'bg-emerald-50 text-emerald-700 ring-emerald-200','icon' => 'users'], 'consumable' => ['label' => __('Consumable'), 'color' => 'bg-cyan-50 text-cyan-700 ring-cyan-200', 'icon' => 'inbox'], 'equipment' => ['label' => __('Equipment'), 'color' => 'bg-orange-50 text-orange-700 ring-orange-200', 'icon' => 'cog-6-tooth'], 'other' => ['label' => __('Other'), 'color' => 'bg-slate-100 text-slate-600 ring-slate-200', 'icon' => 'tag'], ]; $fromStock = ['label' => __('From stock'), 'color' => 'bg-emerald-50 text-emerald-700 ring-emerald-200', 'icon' => 'cube']; $badgeFor = function ($cost) use ($typeBadge, $fromStock) { if ($cost->type === 'material' && $cost->stock_movement_id) { return $fromStock; } return $typeBadge[$cost->type] ?? ['label' => ucfirst(str_replace('_', ' ', $cost->type)), 'color' => 'bg-slate-100 text-slate-600 ring-slate-200', 'icon' => 'tag']; }; // Variance flag presentation for the sized-production draft preview. $flagMeta = [ 'size_changed' => ['label' => __('Size changed'), 'color' => 'bg-amber-50 text-amber-700 ring-amber-200', 'icon' => 'adjustments-horizontal'], 'qty_changed' => ['label' => __('Qty changed'), 'color' => 'bg-sky-50 text-sky-700 ring-sky-200', 'icon' => 'queue-list'], 'over_consumed' => ['label' => __('Over-consumed'), 'color' => 'bg-rose-50 text-rose-700 ring-rose-200', 'icon' => 'exclamation-triangle'], ]; $n = fn ($v, int $dp = 2): string => rtrim(rtrim(number_format((float) $v, $dp), '0'), '.'); // Material logged from the floor, still waiting for someone to price it. $awaitingCost = fn ($cost): bool => in_array($cost->id, $awaitingCostIds, true); $canEditMaterial = fn ($cost): bool => in_array($cost->id, $editableMaterialIds, true); $estVsAct = $estimatedMaterial > 0 ? round(($actualMaterial / $estimatedMaterial) * 100) : null; $varTone = $materialVariance > 0 ? 'text-rose-600' : ($materialVariance < 0 ? 'text-emerald-600' : 'text-slate-600'); @endphp
{{-- ============ HEADER + UNIFIED TOOLBAR ============ --}}

{{ $canManageCosts ? __('Production Costs') : __('Materials Used') }}

{{ $canManageCosts ? __('Every material and cost on this job in one ledger, from stock, bought-in, outsourced and more.') : __('Log everything you used on this job, off the shelf or by hand. Pricing is handled by management.') }}

@if ($canManage)
{{-- Record production ▾ --}}
@if (! $draft) @else

{{ __('A production draft is open below.') }}

@endif
{{-- Add cost (money) is management-only; the floor logs materials. --}} @if ($canManageCosts) @else @endif
@endif
{{-- ============ JOB P&L: GROSS → NET AFTER OVERHEAD (G9, FRS §3) ============ Same ladder and same numbers as /reports/profitability, both from JobAbsorptionService, so the job screen and the report can never disagree about what this job made. --}} @if ($pnl)

{{ __('Job Profit & Loss') }}

{{ __('Revenue → direct costs → gross profit → absorbed overhead → net profit.') }}

{{ \Illuminate\Support\Carbon::parse($pnl['period_start'])->translatedFormat('F Y') }} @if ($pnl['provisional']) {{ __('Provisional') }} @endif

{{ __('Revenue') }}

{{ $baseCurrency }} {{ number_format($pnl['revenue'], 2) }}

{{ __('Direct Costs') }}

{{ $baseCurrency }} {{ number_format($pnl['direct_cost'], 2) }}

{{ __('materials :m · labour :l', ['m' => number_format($pnl['materials'], 2), 'l' => number_format($pnl['labour'], 2)]) }}

{{ __('Gross Profit') }}

{{ $baseCurrency }} {{ number_format($pnl['gross_profit'], 2) }}

{{ number_format($pnl['gross_margin'], 1) }}% {{ __('margin') }}

{{ __('Net Profit') }}

{{ $baseCurrency }} {{ number_format($pnl['net_profit'], 2) }}

{{ __('after :amount overhead', ['amount' => $baseCurrency.' '.number_format($pnl['absorbed_overhead'], 2)]) }}

{{-- Never let an allocated figure be read as cash. --}}

{{ __('Net profit here is a management allocation, not a cash fact.') }} {{ __('The :amount of overhead is this job\'s share of the whole month\'s nut (rent, salaries, depreciation) on a :basis basis — not money this job spent.', [ 'amount' => $baseCurrency.' '.number_format($pnl['absorbed_overhead'], 2), 'basis' => \Illuminate\Support\Str::lower($pnl['basis_label']), ]) }} @if ($pnl['imputed']) {{ __('No time was logged on this job, so its hours were estimated from its revenue — log time to make the share accurate.') }} @endif

@endif {{-- ============ MATERIAL ESTIMATED VS ACTUAL (slim strip) ============ --}} @if ($hasProductSource && $canManageCosts)
{{ __('Material est. vs actual') }}
{{ __('Estimated') }} {{ $baseCurrency }} {{ number_format($estimatedMaterial, 2) }}
{{ __('Actual') }} {{ $baseCurrency }} {{ number_format($actualMaterial, 2) }}
{{ __('Variance') }} {{ $materialVariance > 0 ? '+' : '' }}{{ number_format($materialVariance, 2) }} @if (! is_null($estVsAct)) ({{ __(':n% of est.', ['n' => $estVsAct]) }}) @endif
@endif {{-- ============ USE-STOCK QUICK PICKER (revealed from the menu) ============ --}} @if ($canManage)

{{ __('Use stock item') }}

@error('useVariantId')

{{ $message }}

@enderror
@error('useQty')

{{ $message }}

@enderror
{{-- Which product it went on. Only asked when the job has more than one; otherwise there is only one possible answer. --}} @if ($jobLineItems->count() > 1)
@error('useLineItemId')

{{ $message }}

@enderror
@endif
@endif {{-- ============ SIZED PRODUCTION DRAFT EDITOR ============ --}} @if ($draft)
{{ __('Draft production') }} {{ __('Started :when', ['when' => optional($draft->produced_at)->format('Y-m-d H:i')]) }}
@if ($canManage) @endif
@foreach ($draftLines as $row) @php /** @var \App\Models\JobProductionLine $line */ $line = $row['line']; $pv = $row['preview']; $variant = $line->materialVariant; $material = $variant?->material; $unit = $pv['base_unit']; @endphp

{{ $line->product?->name ?? $line->lineItem?->name ?? __('Line item') }}

@if ($material) {{ $material->name }}@if ($variant?->label) · {{ $variant->label }}@endif @if ($material->isRoll()) {{ __('Roll :w m', ['w' => $n($material->roll_width, 4)]) }} @elseif ($material->isSheet()) {{ __('Sheet') }} @endif @else {{ __('No stock material mapped') }} @endif

{{ __('Ordered') }}

@if ($line->ordered_width || $line->ordered_height) {{ $n($line->ordered_width, 4) }} × {{ $n($line->ordered_height, 4) }} m · @endif {{ $n($line->ordered_qty, 2) }} {{ __('pcs') }}

@if (! $pv['fits'])
{{ __('Piece is wider than the roll in both orientations, fix the size or the material before confirming. Falling back to area/per-item costing.') }}
@endif
@if ($pv['mode'] === 'roll')
{{ __('Media off roll') }}
{{ $n($pv['linear_m'], 3) }} {{ __('m') }}
@else
{{ __('Consumed') }}
{{ $n($pv['consumed'], 3) }} {{ $unit }}
@endif
{{ __('Billed area') }}
{{ $n($pv['billed_area'], 3) }} {{ __('m²') }}
{{ __('Consumed area') }}
{{ $n($pv['consumed_area'], 3) }} {{ __('m²') }}
{{ __('Offcut') }}
{{ $n($pv['offcut_area'], 3) }} {{ __('m²') }}
@if ($pv['mode'] === 'roll' && $pv['fits'])

{{ __(':across across, :orient orientation', ['across' => $pv['pieces_across'], 'orient' => $pv['orientation']]) }}

@endif
@endforeach
@if ($canManage)
@endif
@endif {{-- ============ VARIABLE COSTS TO CONFIRM (estimate reminders) ============ --}} @if (! empty($estimateReminders))

{{ __('Variable costs to confirm') }}

{{ __('These items were flagged as bought-per-job estimates on the product recipe. Confirm the real amount actually paid.') }}

@foreach ($estimateReminders as $i => $r)

{{ $r['label'] }}

{{ $r['product'] }} · {{ __('est.') }} {{ $baseCurrency }} {{ number_format($r['estimated_total'], 2) }} @if ($r['qty'] != 1) ({{ rtrim(rtrim(number_format($r['qty'], 2), '0'), '.') }} × {{ number_format($r['estimated_unit'], 2) }}) @endif

@if ($r['done']) {{ __('Recorded') }} @elseif ($canManage) @endif
@endforeach
@endif {{-- ============ SINGLE FLAT COST LEDGER ============ --}} @if ($costs->isEmpty() && empty($overheadRows)) @else
@if ($canManageCosts) @endif @if ($canManage) @endif @foreach ($costs as $cost) @php $badge = $badgeFor($cost); @endphp @if ($canManageCosts) @endif @if ($canManage) @endif @endforeach {{-- The product recipe's labour / machine / ink / overhead rows, folded into one figure. Only a director sees them itemised. --}} @foreach ($overheadRows as $row) @if ($canManageCosts) @endif @if ($canManage) @endif @endforeach @if ($canManageCosts) @if ($canManage)@endif @endif
{{ __('Date') }} {{ __('Item') }} {{ __('Type') }} {{ __('Supplier / Partner') }} {{ __('Qty') }}{{ __('Unit') }} {{ __('Total') }}{{ __('Actions') }}
{{ optional($cost->incurred_on)->format('Y-m-d') }} {{ $cost->description }} @if ($awaitingCost($cost)) {{ __('Cost to confirm') }} @endif @if ($jobLineItems->count() > 1) {{-- Which product carries this cost. "Shared" is a real answer, not a gap: it gets split by revenue. --}} @if ($cost->lineItem) {{ $cost->lineItem->name }} @else {{ __('Shared') }} @endif @endif @if ($cost->fundAccount) {{ __('Paid from :account', ['account' => $cost->fundAccount->name]) }} @endif {{ $badge['label'] }} @if ($cost->partnerModel) {{ $cost->partnerModel->name }} @elseif ($cost->supplierModel) {{ $cost->supplierModel->name }} {{ $cost->supplierModel->type === 'international' ? __('Intl') : __('Local') }} @else {{ $cost->supplier ?: '—' }} @endif {{ number_format((float) $cost->qty, 2) }}{{ number_format((float) $cost->unit_cost, 2) }} {{ $cost->currency_code }} {{ number_format((float) $cost->total_cost, 2) }} {{ $cost->currency_code }} @if ($cost->stock_movement_id && $cost->job_production_id) {{ __('Via production') }} @elseif ($cost->stock_movement_id) @elseif ($canManageCosts)
@elseif ($canEditMaterial($cost))
@else — @endif
{{ $row['date'] }} {{ __('Production overheads') }} {{ __('Labour, machine time, ink & overhead from the product recipe') }} {{ __('Overheads') }} — —— {{ number_format($row['total'], 2) }} {{ $row['currency'] }}{{ __('From recipe') }}
{{ __('Total (base)') }} {{ $baseCurrency }} {{ number_format($totalBase, 2) }}
@endif
{{ $editingMaterialId ? __('Edit Material Used') : __('Add Material Used') }}

{{ __('Anything not taken off the shelf, an offcut, a board bought for the job, a consumable. Record what and how much; management fills in the cost.') }}

@if ($jobLineItems->count() > 1)
@endif
@unless ($editingMaterialId)

{{ __('Using something that is in stock? Close this and pick “Use stock item” instead so inventory is deducted.') }}

@endunless
{{ __('Cancel') }} {{ $editingMaterialId ? __('Save Changes') : __('Add Material') }}
@if ($canManageCosts) {{ $editingId ? __('Edit Cost') : __('Add Cost') }}
@if ($jobLineItems->count() > 1)

{{ __('Tag it and this cost lands on that product’s profit exactly. Left shared, it is split across the job’s products by revenue.') }}

@endif {{-- A product split into pieces goes one level further: the reprint of design B is design B's cost, and charging it to the whole line would hide which design lost money. --}} @php $pieces = $line_item_id ? ($jobProductParts->get((int) $line_item_id) ?? collect()) : collect(); @endphp @if ($pieces->count() > 1)

{{ __('Left shared, it is split across the pieces by quantity.') }}

@endif
@if ($fundAccounts->isEmpty())

{{ __('No fund accounts yet.') }} {{ __('Create one') }}.

@else

{{ __('Pick the account this money comes out of to deduct it from your treasury. Must match the currency above. Leave as “None” for costs already paid elsewhere.') }}

@endif
@if ($partners->isEmpty())

{{ __('No partners yet.') }} {{ __('Add one') }}.

@else

{{ __('Select if this cost is a payment to an outsourcing partner.') }}

@endif

{{ __('Materials supplier, if any.') }}

{{ __('Line total') }} {{ number_format($this->lineTotal, 2) }} {{ $currency_code }}
{{ __('Cancel') }} {{ $editingId ? __('Save Changes') : __('Add Cost') }}
@endif