{{-- New-Unity ERP | resources/views/dashboard.blade.php | v2.4 | 27/07/2026 --}} {{-- v2.4 — Título limpio: "Dashboard" + breadcrumb "Unity ERP / Dashboard". --}} {{-- v2.3 — Sección 1 (saludo) eliminada: saludo vive ahora en app-header.blade.php. --}} {{-- Botón Actualizar + timestamp movidos junto al page-title. --}} {{-- v2.2 — Header simplificado: removidos fecha y empresa (info redundante con app-header). --}} {{-- v2.1 — Fix dona: canvas en wrapper cuadrado 185×185 + responsive:true/maintainAspectRatio --}} {{-- :false. Leyenda acotada con overflow-y:auto. Card-body h-260 sin desbordamiento. --}} {{-- v2.0 — KPI cards rediseñados: icono izq FA, número+label der, colores suaves por valor. --}} {{-- Fix gráficas: @push → @section (layout usa @yield), guard typeof Chart, --}} {{-- wrapper window.addEventListener('load'). Icono Stock Crítico → link correcto. --}} {{-- v1.0 — Dashboard inteligente: KPIs reales, gráficas Chart.js, tablas operativas por rol. --}} @extends('layouts.vertical', ['pageTitle' => __('dashboard.title')]) @section('page-title') @include('layouts.partials/app-pagetitle', [ 'pageTitle' => __('dashboard.title'), 'pageSubTitle1' => 'Unity ERP', ]) @endsection @section('content') {{-- ══ SECCIÓN 1 — KPI Cards ═══════════════════════════════════════════════════ --}} {{-- Toolbar: timestamp + refresh alineados a la derecha antes de los cards --}}
{{ __('dashboard.last-update') }}: {{ $now->format('H:i') }}
{{-- ══ KPI Cards ════════════════════════════════════════════════════════════════ --}} {{-- Estilos calculados en PHP: bg suave, borde, color de icono/número/label --}} @php $kpiStyle = function (bool $active, string $bg, string $bd, string $iconC, string $numC, string $lblC): array { return [ 'bg' => $active ? $bg : '#f8f9fa', 'bd' => $active ? $bd : 'rgba(0,0,0,.07)', 'icon' => $active ? $iconC : '#adb5bd', 'num' => $active ? $numC : '#495057', 'lbl' => $active ? $lblC : '#6c757d', ]; }; $kpiVentas = $kpiStyle(($ventasHoy ?? 0) > 0, 'rgba(25,135,84,.10)', 'rgba(25,135,84,.25)', '#198754', '#0f5132', '#1a7a47'); $kpiOvs = $kpiStyle(($ovsPendientes ?? 0) > 0, 'rgba(255,193,7,.15)', 'rgba(255,193,7,.40)', '#cc9700', '#664d03', '#7a5a03'); $kpiEnt = $kpiStyle(($entregasPendientes ?? 0) > 0, 'rgba(13,110,253,.10)', 'rgba(13,110,253,.25)', '#0d6efd', '#084298', '#084298'); $kpiStock = $kpiStyle(($stockCritico ?? 0) > 0, 'rgba(220,53,69,.10)', 'rgba(220,53,69,.25)', '#dc3545', '#842029', '#842029'); $kpiMrp = $kpiStyle(($mrpPendientes ?? 0) > 0, 'rgba(253,126,20,.10)', 'rgba(253,126,20,.25)', '#fd7e14', '#7c3200', '#7c3200'); $kpiCxc = $kpiStyle(($cxcVencida ?? 0) > 0, 'rgba(220,53,69,.10)', 'rgba(220,53,69,.25)', '#dc3545', '#842029', '#842029'); @endphp
@can('sales.access') {{-- Ventas Hoy --}}
${{ number_format($ventasHoy ?? 0, 0) }}
{{ __('dashboard.sales-today') }}
{{-- OVs Pendientes --}}
{{ $ovsPendientes ?? 0 }}
{{ __('dashboard.pending-orders') }}
@endcan @can('warehouse.picking') {{-- Entregas Pendientes --}}
{{ $entregasPendientes ?? 0 }}
{{ __('dashboard.pending-deliveries') }}
@endcan @can('warehouse.access') {{-- Stock Crítico --}}
{{ $stockCritico ?? 0 }}
{{ __('dashboard.critical-stock') }}
@endcan @can('purchases.access') {{-- MRP Pendientes --}}
{{ $mrpPendientes ?? 0 }}
{{ __('dashboard.pending-mrp') }}
@endcan @can('finance.access') {{-- CxC Vencida --}}
${{ number_format($cxcVencida ?? 0, 0) }}
{{ __('dashboard.overdue-cxc') }}
@endcan
{{-- ══ SECCIÓN 3 — Gráficas ════════════════════════════════════════════════════ --}} @can('sales.access')
{{-- Gráfica de barras: Ventas 30 días --}}
{{ __('dashboard.sales-last-30-days') }}
@php $allZero = empty(array_filter($chartData, fn($v) => $v > 0)); @endphp @if($allZero)

{{ __('dashboard.no-data-available') }}

@else @endif
{{-- Gráfica de dona: Top 5 productos --}}
{{ __('dashboard.top-products') }}
@if($topProductos->isEmpty())

{{ __('dashboard.no-data-available') }}

@else {{-- Wrapper cuadrado centrado: Chart.js lo llena con responsive:true --}}
{{-- Leyenda acotada: ocupa el espacio restante sin desbordarse --}}
@endif
@endcan {{-- ══ SECCIÓN 4 — Tablas Operativas ══════════════════════════════════════════ --}}
{{-- Tabla 1: OVs Recientes --}} @can('sales.access')
{{ __('dashboard.recent-orders') }}
{{ __('dashboard.view-all') }}
@if($ovsRecientes->isEmpty())

{{ __('dashboard.no-data-available') }}

@else
@foreach($ovsRecientes as $ov) @endforeach
{{ __('dashboard.order-number') }} {{ __('dashboard.customer') }} {{ __('dashboard.total') }} {{ __('dashboard.status') }} {{ __('dashboard.date') }}
{{ $ov->folDisplay() }} {{ $ov->customer_name }} ${{ number_format($ov->total, 2) }} {{ $ov->statusLabel() }} {{ $ov->created_at->format('d/m/y') }}
@endif
@endcan {{-- Tabla 2: CxC Vencida --}} @can('finance.access') @can('finance.view')
{{ __('dashboard.overdue-invoices') }}
{{ __('dashboard.view-all') }}
@if($facturasVencidas->isEmpty())

Sin facturas vencidas

@else
@foreach($facturasVencidas as $inv) @php $diasVencida = now()->startOfDay()->diffInDays(\Carbon\Carbon::parse($inv->expiration_date)->startOfDay()); @endphp @endforeach
{{ __('dashboard.invoice') }} {{ __('dashboard.customer') }} {{ __('dashboard.balance') }} {{ __('dashboard.overdue-days') }}
#{{ $inv->id }} {{ $inv->customer->commercial_name ?? '—' }} ${{ number_format($inv->cxc_balance, 2) }} {{ $diasVencida }}d
@endif
@endcan @endcan {{-- Tabla 3: MRP Pendientes --}} @can('purchases.access')
{{ __('dashboard.pending-mrp-list') }}
{{ __('dashboard.view-all') }}
@if($mrpLista->isEmpty())

Sin MRP pendientes

@else
@foreach($mrpLista as $prop) @endforeach
Pre-Orden {{ __('dashboard.product') }} {{ __('dashboard.qty') }} {{ __('dashboard.so-origin') }}
{{ $prop->proposal_number }} Pendiente {{ $prop->product->product_name ?? '—' }} {{ number_format($prop->quantity_needed, 0) }} /{{ number_format($prop->quantity_available, 0) }} {{ $prop->sales_order_number ?? '—' }}
@endif
@endcan {{-- Tabla 4: Recepciones Pendientes --}} @can('warehouse.receive')
{{ __('dashboard.pending-receptions') }}
{{ __('dashboard.view-all') }}
@if($recepcionesPendientes->isEmpty())

Sin recepciones pendientes

@else
@foreach($recepcionesPendientes as $rec) @endforeach
{{ __('dashboard.reception') }} OC Origen {{ __('dashboard.status') }} {{ __('dashboard.date') }}
{{ $rec->reception_number }} {{ $rec->purchase_order_number ?? '—' }} {{ $rec->status_label }} {{ $rec->created_at->format('d/m/y') }}
@endif
@endcan
@endsection {{-- ══ SCRIPTS — Chart.js ═══════════════════════════════════════════════════════════════ --}} {{-- NOTA: el layout usa @yield('scripts') (no @stack), por eso se usa @section aquí. --}} @section('scripts') @endsection