@php $quoteBadge = [ 'DRAFT' => 'slate', 'SENT' => 'sky', 'ACCEPTED' => 'emerald', 'REJECTED' => 'rose', 'EXPIRED' => 'amber', ]; $kpiAccent = [ 'indigo' => '#6366f1', 'amber' => '#f59e0b', 'emerald' => '#10b981', 'sky' => '#0ea5e9', 'rose' => '#f43f5e', ]; $avatarColors = [ 'bg-indigo-100 text-indigo-700', 'bg-emerald-100 text-emerald-700', 'bg-amber-100 text-amber-700', 'bg-sky-100 text-sky-700', 'bg-rose-100 text-rose-700', 'bg-violet-100 text-violet-700', ]; $initials = function (?string $name): string { $parts = collect(preg_split('/\s+/', trim((string) $name)))->filter(); if ($parts->isEmpty()) { return '—'; } return $parts->take(2)->map(fn ($w) => mb_strtoupper(mb_substr($w, 0, 1)))->implode(''); }; $avatarColor = fn (?string $name): string => $avatarColors[abs(crc32((string) $name)) % count($avatarColors)]; @endphp
@if ($canManage) {{ __('New Quote') }} @endif
@foreach ($kpis as $kpi) @php $accent = $kpiAccent[$kpi['color']] ?? $kpiAccent['indigo']; @endphp

{{ $kpi['label'] }}

{{ $kpi['value'] }}

{{ $kpi['sub'] }}
@endforeach
–
@if ($showFilters)
@endif @if ($quotes->isEmpty())
@if ($canManage && ! $this->hasActiveFilters) {{ __('New Quote') }} @endif
@else @php // Row actions live in the floating selection bar, so every // row carries a tick box instead of a strip of icons. The // header box selects / clears this page. $pageIds = $quotes->getCollection()->modelKeys(); $pageAllTicked = $pageIds !== [] && array_diff($pageIds, $selected) === []; @endphp
@foreach ($quotes as $quote) @php $vu = $quote->valid_until; $daysLeft = $vu ? (int) round(\Illuminate\Support\Carbon::today()->diffInDays($vu, false)) : null; @endphp @php $ticked = in_array($quote->id, $selected, true); @endphp
{{ $initials($quote->customer?->name) }}
{{ $quote->quote_number }}
@if ($quote->converted_to_invoice_id) {{ __('Invoiced') }} @endif

{{ $quote->customer?->name ?: '—' }}

{{ $quote->status }}

{{ $quote->currency_code }} {{ number_format((float) $quote->total, 2) }}

{{ $quote->created_at?->format('Y-m-d') }} @if ($vu) @if ($daysLeft < 0) · {{ __('Expired') }} @elseif ($daysLeft === 0) · {{ __('Expires today') }} @else · {{ trans_choice('{1} :count day to expiry|[2,*] :count days to expiry', $daysLeft, ['count' => $daysLeft]) }} @endif @endif

@endforeach
{{ __('Rows per page') }}
{{ $quotes->onEachSide(1)->links() }}
@endif
{{-- Floating action bar. Tick one row and it offers everything that used to sit in the row's icon strip, now with labels; tick several and it narrows to the actions that are safe to run across a batch. --}} @if ($selectedQuote) @php $q = $selectedQuote; $convertible = $canConvert && ! in_array($q->status, ['REJECTED', 'EXPIRED'], true) && ! $q->converted_to_invoice_id; @endphp {{ __('View') }} @if ($convertible) {{ __('Convert to invoice') }} @elseif ($canManage) {{ __('Send') }} @endif {{ __('PDF') }} @if ($canManage) {{ __('Edit') }} @endif {{-- The rest, behind one more click so the bar stays readable. It opens upward (`bottom-full`) because the bar is pinned to the bottom of the viewport. --}} @if ($canManage && $convertible) @endif @if ($canManage) @endif @if ($canDelete)
@endif
@else @if ($canManage) {{ __('Email to customers') }} @endif @if ($canDelete) {{ __('Delete') }} @endif @endif
{{ $editingId ? __('Edit Quote') : __('New Quote') }}
@if ($opportunityOptions->isNotEmpty() || $opportunity_id) {{-- The CRM opportunity this quote answers. Accepting it online shows the opportunity as "Accepted, awaiting confirmation". --}}
@endif
@foreach ($lines as $i => $line) @php $lineMode = $this->linePricingMode($line); $lineDimensional = $lineMode !== 'fixed'; @endphp
{{ __('Product') }}
{{ __('Name') }}
{{ __('Qty') }}
{{ $lineDimensional ? ($lineMode === 'per_sqm' ? __('Price / m²') : __('Price / m')) : __('Unit Price') }}
{{ __('Discount') }}
{{-- Dimensional inputs: only for products priced per m² / linear m. --}} @if ($lineDimensional) @php $factor = $this->lineAreaFactor($line); $bothDims = (float) ($line['width_m'] ?? 0) > 0 && ($lineMode === 'per_linear_m' || (float) ($line['height_m'] ?? 0) > 0); @endphp
{{ __('Width (m)') }}
{{ __('Height (m)') }}

@if ($lineMode === 'per_sqm') {{ $bothDims ? __(':factor m² × qty × price/m²', ['factor' => rtrim(rtrim(number_format($factor, 4), '0'), '.')]) : __('Enter width × height to price by area.') }} @else {{ $bothDims ? __(':factor m × qty × price/m', ['factor' => rtrim(rtrim(number_format($factor, 4), '0'), '.')]) : __('Enter the length to price per linear metre.') }} @endif

@endif {{-- Garment details: colour + size breakdown flow through to the invoice, job and delivery note. --}}
{{ __('Colour') }}
{{ __('Size breakdown') }}
{{ number_format($this->lineSubtotal($line), 2) }}
{{-- Cost-plus price builder (custom / one-off items) --}} @php $hasPricing = ! empty($line['pricing']['costs'] ?? []) || (float) ($line['pricing']['profit_pct'] ?? 0) > 0 || ! empty($line['pricing']['additions'] ?? []); @endphp
@if ($hasPricing) @php $hint = $this->computePricing($line['pricing']); @endphp {{ __('Cost') }} {{ $currency_code }} {{ number_format($hint['cost_subtotal'], 2) }} @if (! is_null($hint['margin'])) · {{ __('margin') }} {{ number_format($hint['margin'], 1) }}% @endif @endif
@if ($pricingLineIndex === $i && isset($line['pricing'])) @php $pr = $this->computePricing($line['pricing']); @endphp

{{ __('Cost-plus price builder') }}

{{-- Cost rows --}}

{{ __('Associated costs') }}

@foreach ($line['pricing']['costs'] ?? [] as $ci => $cost)
@endforeach
{{-- ===== Material yield calculator ===== --}} @php $mc = $this->materialCalc; @endphp

{{ __('Material calculator') }}

{{ __('auto m² · offcut · cost') }}
@if ($mc)

{{ __('Consumed') }}

{{ $this->trimNum($mc['consumed_qty']) }} {{ $mc['consumed_unit'] }}

{{ __('Offcut') }}

{{ $this->trimNum($mc['offcut_area']) }} m² ({{ number_format($mc['offcut_pct'], 0) }}%)

{{ __('Material cost') }}

{{ $currency_code }} {{ number_format($mc['material_cost'], 2) }}

{{ __('Weight') }}

{{ $mc['weight_kg'] !== null ? $mc['weight_kg'].' kg' : '—' }}

@if (! $mc['fits'])

{{ $mc['note'] }}

@endif {{-- Offcut decision, asked every time there is offcut --}} @if ((float) $mc['offcut_cost'] > 0)

{{ __('Offcut costs :cur :amt, what do you want to do?', ['cur' => $currency_code, 'amt' => number_format($mc['offcut_cost'], 2)]) }}

@if ($mc['remnant_reusable'])

{{ __('This offcut is a reusable remnant, consider absorbing it.') }}

@endif
@if ($calcOffcut === 'partial')
%
@endif
@endif
@if ($mc['charged'] !== null) {{ __('Adds :cur :amt to costs', ['cur' => $currency_code, 'amt' => number_format($mc['charged'], 2)]) }} @if (($mc['absorbed'] ?? 0) > 0) · {{ __('absorbing :cur :amt', ['cur' => $currency_code, 'amt' => number_format($mc['absorbed'], 2)]) }} @endif @if ($mc['sell_rate'] !== null) · {{ __('sells @ :cur :rate/m²', ['cur' => $currency_code, 'rate' => number_format($mc['sell_rate'], 2)]) }} @endif @else {{ __('Choose what to do with the offcut ↑') }} @endif
@elseif ($calcVariantId)

{{ __('Enter a size and quantity to calculate…') }}

@endif
{{-- Profit % --}}
%
= {{ $currency_code }} {{ number_format($pr['profit'], 2) }}
{{-- Additions --}}

{{ __('Other additions') }}

@foreach ($line['pricing']['additions'] ?? [] as $ai => $addition)
@endforeach
{{-- Summary --}}
{{ __('Cost subtotal') }}{{ $currency_code }} {{ number_format($pr['cost_subtotal'], 2) }}
{{ __('Profit') }}+ {{ $currency_code }} {{ number_format($pr['profit'], 2) }}
{{ __('Additions') }}+ {{ $currency_code }} {{ number_format($pr['additions'], 2) }}
{{ __('Selling price') }} {{ $currency_code }} {{ number_format($pr['price'], 2) }}
@if (! is_null($pr['margin']))
{{ __('Gross margin') }}{{ number_format($pr['margin'], 1) }}%
@endif
{{ __('Costs are for one unit.') }} {{ __('Apply to unit price') }}
@endif
@endforeach

{{ __('Methods carrying a charge add it to the total.') }} {{ __('Set rates') }}

{{-- A quote gets the same treatment as an invoice: clients pay off quotes as though they were pro-formas, so an account number on one priced for cash invites a transfer we never charged for. --}} @php $bankingMethod = $paymentMethods->firstWhere('id', (int) $payment_method_id); @endphp

{{ $bankingMethod?->isBankTransfer() ? __('Your bank details will print on this quote.') : __('No bank details will print on this quote.') }}

{{ __('Subtotal') }} {{ number_format($totals['subtotal'], 2) }}
{{ __('Discount') }} - {{ number_format($totals['discount'], 2) }}
{{ __('VAT') }} {{ number_format($totals['vat'], 2) }}
@if ($totals['surcharge_label'])
{{ $totals['surcharge_label'] }} + {{ number_format($totals['surcharge'], 2) }}
@endif
{{ __('Total') }} {{ $currency_code }} {{ number_format($totals['total'], 2) }}
{{ __('Cancel') }} {{ __('Save') }}