@php $secret = $this->secret; $package = $this->package; $live = $this->live; $stats = $this->stats; $billing = $this->billing; $dueDate = $billing?->auto_disable_date ? \Carbon\Carbon::parse($billing->auto_disable_date) : null; $label = $customer->customer_name ?: ($secret?->username ?: $customer->customer_unique_id); $initials = strtoupper(mb_substr(preg_replace('/[^A-Za-z0-9]/', '', $label) ?: '?', 0, 2)); $hue = crc32($customer->customer_unique_id) % 360; $counts = [ 'bills' => $this->bills->count(), 'sms' => $this->smsLog->count(), 'tickets' => $this->tickets->count(), 'notes' => $this->notes->count(), ]; @endphp
{{-- ── Header ─────────────────────────────────────────────────── --}}
{{ __('Subscribers') }} — #{{ $customer->id }}
{{ $initials }}
@{{ $secret?->username ?: __('no login') }} {{-- Three states, not two. A router we cannot reach is not the same as a customer who is offline, and saying "offline" would send an operator chasing a subscriber whose line is probably fine. --}} @if ($live === null) {{ __('Router unreachable') }} @elseif ($live['online']) {{ __('Online') }} @if ($live['uptime']) · {{ $live['uptime'] }} @endif @else {{ __('Offline') }} @endif @if ($customer->status !== 'active') {{ __('Suspended') }} @endif @if ($secret?->router_name) {{ $secret->router_name }} @endif {{ __('PPPoE') }} @if ($package) {{ $package->package }} @if ($package->mikrotik_rate_limit) {{ $package->mikrotik_rate_limit }} @endif @endif
@if ($customer->mobile) {{ $customer->mobile }} @endif @if ($customer->email) {{ $customer->email }} @endif {{ $customer->customer_unique_id }} {{ __('Member since') }} {{ optional($customer->created_at)->format('M j, Y') }}
{{-- A fixed line has no session to extend; what it has is the day an unpaid subscriber gets cut off. That is the equivalent control, so it carries the equivalent name. --}}
@if ($flash)
{{ $flash }}
@endif {{-- ── Summary ────────────────────────────────────────────────── --}}
{{ __('Monthly') }} {{ __('Ksh') }} {{ number_format((float) ($package->price ?? 0)) }} {{ $package?->package ?: __('no package') }}
{{ __('Billed') }} {{ __('Ksh') }} {{ number_format($stats['billed']) }} {{ trans_choice('{0}no bills yet|{1}:count bill|[2,*]:count bills', $stats['bills'], ['count' => $stats['bills']]) }}
{{ __('Cut-off') }} $dueDate && $dueDate->isPast()])> {{ $dueDate ? $dueDate->format('j M Y') : '—' }} @if (! $billing) {{ __('no billing record') }} @elseif (! $billing->auto_disable) {{ __('auto cut-off is off') }} @elseif ($dueDate && $dueDate->isPast()) {{ __('overdue') }} @elseif ($dueDate) {{ __('in :days days', ['days' => (int) now()->diffInDays($dueDate)]) }} @endif
{{ __('Outstanding') }} $stats['due'] > 0])> {{ __('Ksh') }} {{ number_format($stats['due']) }} {{ $stats['due'] > 0 ? __('owed now') : __('nothing owed') }}
@unless ($billing) {{-- Loud, because it is silent everywhere else: the monthly job selects on the billing row, so this subscriber is never billed, never reminded, and never cut off. --}}
{{ __('No billing record — this subscriber will never be billed, reminded or cut off.') }}
@endunless {{-- ── Tabs ───────────────────────────────────────────────────── --}}
@foreach ([ 'overview' => [__('Overview'), null], 'connection' => [__('Connection'), null], 'bills' => [__('Bills'), $counts['bills']], 'sms' => [__('SMS'), $counts['sms']], 'tickets' => [__('Tickets'), $counts['tickets']], 'notes' => [__('Notes'), $counts['notes']], ] as $key => [$name, $count]) @endforeach
{{-- ---------- Overview ---------- --}} @if ($tab === 'overview')
{{ __('Name') }}
{{ $customer->customer_name ?: '—' }}
{{ __('Account number') }}
{{ $customer->customer_unique_id }}
{{ __('Phone') }}
{{ $customer->mobile ?: '—' }}
{{ __('Email') }}
{{ $customer->email ?: '—' }}
{{ __('Address') }}
{{ $customer->address ?: '—' }}
{{ __('Status') }}
{{ ucfirst($customer->status) }}
{{ __('Connected since') }}
{{ optional($customer->connection_date)->format('j M Y') ?: '—' }}
{{ __('Package') }}
{{ $package?->package ?: '—' }}
{{ __('Speed') }}
{{ $package?->mikrotik_rate_limit ?: '—' }}
{{-- ---------- Connection ---------- --}} @elseif ($tab === 'connection') @if (! $secret) {{-- Says what is wrong and what it costs, because a customer with no secret cannot connect at all however healthy the rest of the record looks. --}}

{{ __('This subscriber has no PPPoE login on file, so they cannot connect. Edit them to create one.') }}

@else
{{ __('Username') }}
{{ $secret->username }}
{{ __('Password') }}
{{ $secret->password ?: '—' }}
{{ __('Service') }}
{{ $secret->service ?: '—' }}
{{ __('Profile') }}
{{ $secret->profile ?: '—' }}
{{ __('Router') }}
{{ $secret->router_name ?: '—' }}
{{ __('Assigned IP') }}
{{ $live['address'] ?? ($secret->ppp_remote_ip ?: '—') }}
{{ __('Session uptime') }}
{{ $live['uptime'] ?? '—' }}
{{ __('Caller ID') }}
{{ $live['caller'] ?? ($secret->last_caller_id ?: '—') }}
{{ __('Last logged out') }}
{{ optional($secret->last_logged_out)->diffForHumans() ?: '—' }}
{{ __('Last disconnect reason') }}
{{ $secret->last_disconnect_reason ?: '—' }}
@if ($live === null)

{{ __('The router could not be reached, so the live figures above may be out of date.') }}

@endif @endif {{-- ---------- Bills ---------- --}} @elseif ($tab === 'bills')
@if ($billing) {{ __('Monthly') }} {{ __('Ksh') }} {{ number_format((float) $billing->monthly_rent) }} · {{ __('owing') }} {{ __('Ksh') }} {{ number_format((float) $billing->due_amount) }} @endif
@if ($this->bills->isEmpty())

{{ __('No bills have been raised for this subscriber yet. The first one is created at the end of the month.') }}

@else
@foreach ($this->bills as $bill) @endforeach
{{ __('Raised') }} {{ __('Paid on') }} {{ __('Total') }} {{ __('Paid') }} {{ __('Due') }}
{{ optional($bill->created_at)->format('M j, Y') ?: '—' }} {{ optional($bill->paid_date)->format('M j, Y') ?: __('unpaid') }} {{ number_format((float) $bill->total_amount) }} {{ number_format((float) $bill->paid_amount) }} (float) $bill->due_amount > 0])> {{ number_format((float) $bill->due_amount) }}
@endif {{-- ---------- SMS ---------- --}} @elseif ($tab === 'sms') @if ($this->smsLog->isEmpty())

{{ __('No messages sent to this subscriber yet.') }}

@else
@foreach ($this->smsLog as $sms) @endforeach
{{ __('Sent') }} {{ __('Message') }} {{ __('Kind') }} {{ __('Status') }}
{{ $sms->created_at?->format('M j, Y, H:i') }} {{ Str::limit($sms->body, 80) }} {{ $sms->kind }} $sms->status !== 'sent'])>{{ $sms->status }}
@endif {{-- ---------- Tickets ---------- --}} @elseif ($tab === 'tickets') @if ($this->tickets->isEmpty())

{{ __('No support tickets from this subscriber.') }}

@else
@foreach ($this->tickets as $ticket) @endforeach
{{ __('Raised') }} {{ __('Ref') }} {{ __('Subject') }} {{ __('Priority') }} {{ __('Status') }}
{{ $ticket->created_at?->format('M j, Y') }} #{{ $ticket->ticket_no }} {{ $ticket->subject }} {{ ucfirst((string) $ticket->priority) }} {{ ucfirst((string) $ticket->status) }}
@endif {{-- ---------- Notes ---------- --}} @elseif ($tab === 'notes') @if ($this->notes->isEmpty())

{{ __('Nothing noted about this subscriber.') }}

@else
@foreach ($this->notes as $note) @endforeach
{{ __('When') }} {{ __('Note') }}
{{ $note->created_at?->format('M j, Y, H:i') }} {{ $note->body }}
@endif @endif
{{-- ── Edit ───────────────────────────────────────────────────── --}} @if ($showEdit)
{{ __('Edit :name', ['name' => $label]) }}
{{ __('Changing the plan updates the speed on the router and the monthly charge.') }}
@endif {{-- ── Change cut-off ─────────────────────────────────────────── --}} @if ($showDue)
{{ __('Change cut-off date') }}

{{ __('After this date an unpaid line is disabled by the nightly sweep.') }}

@endif {{-- ── Record payment ─────────────────────────────────────────── --}} @if ($showPayment)
{{ __('Record a payment') }}

{{ __('For cash, or an M-Pesa message you matched by hand.') }} @if ($billing) {{ __('Currently owing') }} {{ __('Ksh') }} {{ number_format((float) $billing->due_amount) }}. @endif

{{ __('Ksh') }}
@endif {{-- ── SMS composer ───────────────────────────────────────────── --}} @if ($showSms)
{{ __('Message :name', ['name' => $label]) }}

{{ $customer->mobile }}

@endif