@extends('layouts.app') @section('title', __('lang_v1.expiry_analytics')) @section('content')

@lang('lang_v1.expiry_analytics') @lang('lang_v1.expiry_analytics_desc')

@include('layouts.partials.error') {{-- Scope. Every figure and chart below obeys these three, so the board can be read for the whole chain, one state, one tier, or one site. --}}
{!! Form::open(['route' => 'expiry-analytics.index', 'method' => 'get', 'class' => 'form-inline']) !!}
{!! Form::label('tier', __('lang_v1.scope') . ':') !!} {!! Form::select('tier', ['' => __('lang_v1.entire_chain'), 'store' => __('lang_v1.all_stores'), 'warehouse' => __('lang_v1.all_warehouses')], $filters['tier'] ?? null, ['class' => 'form-control']) !!}
{!! Form::label('state', __('business.state') . ':') !!} {!! Form::select('state', ['' => __('lang_v1.all_states')] + $states->mapWithKeys(fn($s) => [$s => $s])->all(), $filters['state'] ?? null, ['class' => 'form-control']) !!}
{!! Form::label('business_id', __('lang_v1.site') . ':') !!} {!! Form::select('business_id', ['' => __('lang_v1.all_sites')] + $businesses->all(), $filters['business_id'] ?? null, ['class' => 'form-control select2', 'style' => 'width:220px;']) !!}
@lang('lang_v1.reset') {!! Form::close() !!}
{{-- Sunk loss vs recoverable exposure vs already destroyed. Kept as three separate numbers on purpose: adding them together would be meaningless. --}}
@lang('lang_v1.expired_value_at_cost') @format_currency($totals['value_at_cost']) {{ @num_format($totals['units']) }} @lang('lang_v1.units') · {{ $totals['batches'] }} @lang('lang_v1.batches') · {{ $totals['sites'] }} @lang('lang_v1.sites')
@lang('lang_v1.at_risk_90_days') @format_currency($upcoming[90]['value_at_cost']) {{ $upcoming[90]['batches'] }} @lang('lang_v1.batches') — @lang('lang_v1.still_recoverable')
@lang('lang_v1.destroyed_to_date') @format_currency($disposed['value']) {{ $disposed['records'] }} @lang('lang_v1.disposal_records_short') · {{ @num_format($disposed['units']) }} @lang('lang_v1.units')
@lang('lang_v1.in_the_pipeline') {{ $in_transit + $awaiting_disposal }} {{ $in_transit }} @lang('lang_v1.in_transit') · {{ $awaiting_disposal }} @lang('lang_v1.awaiting_destruction')
{{-- What to do about it, in words. A wall of charts still leaves the reader to work out the action; these are generated only where the data supports them. --}} @if(!empty($insights)) @component('components.widget', ['class' => 'box-solid', 'title' => __('lang_v1.what_this_means')]) @foreach($insights as $i) @php $cls = ['high' => 'alert-danger', 'medium' => 'alert-warning', 'info' => 'alert-info'][$i['severity']] ?? 'alert-info'; $icon = ['high' => 'fa-exclamation-circle', 'medium' => 'fa-exclamation-triangle', 'info' => 'fa-info-circle'][$i['severity']] ?? 'fa-info-circle'; @endphp
{{ $i['text'] }}
@endforeach @endcomponent @endif
@if($chart_has_data['ageing']){!! $charts['ageing']->container() !!}@else

@lang('lang_v1.chart_no_data')

@endif
@if($chart_has_data['pipeline']){!! $charts['pipeline']->container() !!}@else

@lang('lang_v1.chart_no_data')

@endif
@if($chart_has_data['trend']){!! $charts['trend']->container() !!}@else

@lang('lang_v1.chart_no_data')

@endif @unless($trend['sufficient']) {{-- Never let a two-point line imply a trend. --}}

@lang('lang_v1.insufficient_trend_note', ['months' => $trend['months_of_data']])

@endunless
@if($chart_has_data['seasonality']){!! $charts['seasonality']->container() !!}@else

@lang('lang_v1.chart_no_data')

@endif

@lang('lang_v1.seasonality_note') @unless($seasonality['sufficient']) @lang('lang_v1.seasonality_insufficient', ['years' => $seasonality['years_of_data']]) @endunless

@if(!empty($seasonality['top_products'])) @component('components.widget', ['class' => 'box-solid', 'title' => __('lang_v1.worst_product_per_month')])
@foreach($seasonality['top_products'] as $tp) @endforeach
@lang('lang_v1.month') @lang('lang_v1.product_with_most_expiry') @lang('lang_v1.value_at_cost')
{{ $tp['label'] }} {{ $tp['product_name'] }} @format_currency($tp['value'])

@lang('lang_v1.worst_product_per_month_help')

@endcomponent @endif
@if($chart_has_data['state']){!! $charts['state']->container() !!}@else

@lang('lang_v1.chart_no_data')

@endif
@if($chart_has_data['product']){!! $charts['product']->container() !!}@else

@lang('lang_v1.chart_no_data')

@endif
{{-- EXPIRY RATIO: the diagnostic figure. Absolute loss just ranks the big sellers; a ratio says which products are being bought wrongly. --}} @component('components.widget', ['class' => 'box-primary', 'title' => __('lang_v1.expiry_ratio_by_product')])

@lang('lang_v1.expiry_ratio_help')

@foreach($ratios as $r) @endforeach
@lang('business.product') @lang('lang_v1.schedule') @lang('lang_v1.units_received') @lang('lang_v1.units_wasted') @lang('lang_v1.expiry_ratio') @lang('lang_v1.value_at_cost') @lang('messages.action')
{{ $r->product_name }} {{ $r->drug_schedule ?: '--' }} {{ @num_format($r->received_units) }} {{ @num_format($r->total_wasted_units) }} {{ $r->ratio }}% @format_currency($r->total_wasted_value) @lang('lang_v1.batches')
@endcomponent {{-- ROOT CAUSE: nothing else fixes waste on a product bought far faster than it sells, so this sits next to the ratio table. --}} @component('components.widget', ['class' => 'box-warning', 'title' => __('lang_v1.over_ordering_signals')])

@lang('lang_v1.over_ordering_help')

@foreach($over_ordering as $o) @endforeach
@lang('business.product') @lang('lang_v1.units_received') @lang('lang_v1.units_sold') @lang('lang_v1.sell_through') @lang('lang_v1.unsold_units') @lang('lang_v1.days_of_cover')
{{ $o->product_name }} {{ @num_format($o->received_units) }} {{ @num_format($o->sold_units) }} {{ $o->sell_through }}% {{ @num_format($o->unsold_units) }} {{ $o->days_of_cover === null ? __('lang_v1.no_sales_yet') : $o->days_of_cover }}
@endcomponent
@component('components.widget', ['class' => 'box-solid', 'title' => __('lang_v1.site_comparison')])

@lang('lang_v1.chain_average_ratio'): {{ $site_comparison['chain_ratio'] }}%

@foreach($site_comparison['sites'] as $s) @endforeach
@lang('lang_v1.site') @lang('business.state') @lang('lang_v1.expiry_ratio') @lang('lang_v1.vs_chain') @lang('lang_v1.value_at_cost')
{{ $s->business_name }} @if($s->is_supplier_warehouse) @lang('lang_v1.warehouse') @endif {{ $s->state }} {{ $s->ratio }}% {{ $s->vs_chain > 0 ? '+' : '' }}{{ $s->vs_chain }} @format_currency($s->expired_value)
@endcomponent
@component('components.widget', ['class' => 'box-solid', 'title' => __('lang_v1.expired_by_manufacturer')])

@lang('lang_v1.by_manufacturer_help')

@foreach($by_manufacturer as $m) @endforeach
@lang('lang_v1.manufacturer') @lang('lang_v1.batches') @lang('lang_v1.units') @lang('lang_v1.value_at_cost')
{{ $m->manufacturer }} {{ $m->batches }} {{ @num_format($m->units) }} @format_currency($m->value_at_cost)
@endcomponent
@component('components.widget', ['class' => 'box-solid', 'title' => __('lang_v1.expired_by_site')])
@foreach($by_business as $b) @endforeach
@lang('lang_v1.site') @lang('lang_v1.type') @lang('lang_v1.batches') @lang('lang_v1.units') @lang('lang_v1.value_at_cost') @lang('messages.action')
{{ $b->business_name }} {{ $b->is_supplier_warehouse ? __('lang_v1.warehouse') : __('lang_v1.store') }} {{ $b->batches }} {{ @num_format($b->units) }} @format_currency($b->value_at_cost) @lang('lang_v1.batches')
@lang('lang_v1.view_all_expired_batches') @lang('lang_v1.chain_disposal_register') @endcomponent
@endsection @section('javascript') @if($chart_has_data['ageing']){!! $charts['ageing']->script() !!}@endif @if($chart_has_data['pipeline']){!! $charts['pipeline']->script() !!}@endif @if($chart_has_data['trend']){!! $charts['trend']->script() !!}@endif @if($chart_has_data['seasonality']){!! $charts['seasonality']->script() !!}@endif @if($chart_has_data['state']){!! $charts['state']->script() !!}@endif @if($chart_has_data['product']){!! $charts['product']->script() !!}@endif @endsection