@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
{{ $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.') }}
{{ __('Revenue → direct costs → gross profit → absorbed overhead → net profit.') }}
{{ __('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)]) }}
{{ __('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
{{ $message }}
@enderror{{ $message }}
@enderror{{ $message }}
@enderror{{ $line->product?->name ?? $line->lineItem?->name ?? __('Line item') }}
{{ __('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') }}
{{ __(':across across, :orient orientation', ['across' => $pv['pieces_across'], 'orient' => $pv['orientation']]) }}
@endif{{ __('These items were flagged as bought-per-job estimates on the product recipe. Confirm the real amount actually paid.') }}
{{ $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
| {{ __('Date') }} | {{ __('Item') }} | {{ __('Type') }} | {{ __('Supplier / Partner') }} | {{ __('Qty') }} | @if ($canManageCosts){{ __('Unit') }} | {{ __('Total') }} | @endif @if ($canManage){{ __('Actions') }} | @endif
|---|---|---|---|---|---|---|---|
| {{ optional($cost->incurred_on)->format('Y-m-d') }} |
{{ $cost->description }}
@if ($awaitingCost($cost))
|
|
@if ($cost->partnerModel)
|
{{ number_format((float) $cost->qty, 2) }} | @if ($canManageCosts){{ number_format((float) $cost->unit_cost, 2) }} {{ $cost->currency_code }} | {{ number_format((float) $cost->total_cost, 2) }} {{ $cost->currency_code }} | @endif @if ($canManage)
@if ($cost->stock_movement_id && $cost->job_production_id)
{{ __('Via production') }}
@elseif ($cost->stock_movement_id)
@elseif ($canManageCosts)
|
@endif
| {{ $row['date'] }} | {{ __('Production overheads') }} {{ __('Labour, machine time, ink & overhead from the product recipe') }} |
|
— | — | @if ($canManageCosts)— | {{ number_format($row['total'], 2) }} {{ $row['currency'] }} | @endif @if ($canManage){{ __('From recipe') }} | @endif
| {{ __('Total (base)') }} | {{ $baseCurrency }} {{ number_format($totalBase, 2) }} | @if ($canManage)@endif | |||||
{{ __('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.') }}
{{ __('Using something that is in stock? Close this and pick “Use stock item” instead so inventory is deducted.') }}
@endunless{{ __('Tag it and this cost lands on that product’s profit exactly. Left shared, it is split across the job’s products by revenue.') }}
{{ __('Left shared, it is split across the pieces by quantity.') }}
{{ __('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{{ __('No partners yet.') }} {{ __('Add one') }}.
@else{{ __('Select if this cost is a payment to an outsourcing partner.') }}
@endif{{ __('Materials supplier, if any.') }}