@extends('layouts.enterprise') @section('title', 'Solicitudes de pago') @section('content')

Solicitudes de pago

Módulo de seguimiento por petición para egresos.

@if(session('ok'))
{{ session('ok') }}
@endif

Estatus por petición (Solicitud)

Seguimiento de avance por proveedores y por monto esperado.

@if($errors->any())
@endif @php $paymentRequestsRouteName = request()->routeIs('admin.*') ? 'admin.expenses.payment_requests' : 'accountant.expenses.payment_requests'; $hasActiveFilters = (($filters['q'] ?? '') !== '') || (($filters['completion'] ?? 'all') !== 'all') || (($filters['partial_status'] ?? 'all') !== 'all') || !empty($filters['date_from'] ?? null) || !empty($filters['date_to'] ?? null) || (($filters['progress_min'] ?? null) !== null && $filters['progress_min'] !== '') || (($filters['progress_max'] ?? null) !== null && $filters['progress_max'] !== '') || (($filters['amount_progress_min'] ?? null) !== null && $filters['amount_progress_min'] !== '') || (($filters['amount_progress_max'] ?? null) !== null && $filters['amount_progress_max'] !== ''); $partialToggleRouteName = request()->routeIs('admin.*') ? 'admin.expenses.payment_requests.partial' : 'accountant.expenses.payment_requests.partial'; @endphp
Filtros @if($hasActiveFilters) Activos @endif
Limpiar Resultados: {{ $requests->count() }}
@forelse($requests as $req) @php $summary = $requestSummaries[$req->id] ?? [ 'providers_total' => 0, 'expected_invoices' => 0, 'providers_with_invoice' => 0, 'providers_partial' => 0, 'providers_without_invoice' => 0, 'completion_percent' => 0, 'is_complete' => false, 'has_expected_amount' => false, 'amount_expected' => null, 'amount_invoiced' => 0, 'amount_pending' => null, 'amount_completion_percent' => 0, 'amount_completion_percent_for_bar' => 0, 'is_amount_complete' => false, 'pending_provider_names' => [], ]; $providersPartialEnabled = $req->providers->filter(fn ($provider) => (bool) ($provider->allows_partial_invoicing ?? false))->count(); $requestSubtotal = $req->subtotal_cost !== null ? (float) $req->subtotal_cost : (($summary['has_expected_amount'] ?? false) && isset($summary['amount_expected']) ? round(((float) $summary['amount_expected']) / 1.16, 2) : null); $requestSubtotalIva = $requestSubtotal !== null ? round($requestSubtotal * 1.16, 2) : null; @endphp
{{ $req->project_name ?: 'Sin PROJECT NAME' }}
Job Number: {{ $req->title ?: '-' }}
RC(s): {{ $req->rc_list ?: '-' }}
Ejecutivo: {{ $req->executive_display ?: '-' }}
Cliente: {{ $req->client_display ?: '-' }}
Subtotal solicitud: {{ $requestSubtotal !== null ? '$'.number_format($requestSubtotal, 2) : 'Sin subtotal' }} @if($requestSubtotalIva !== null) Con IVA: ${{ number_format($requestSubtotalIva, 2) }} @endif
@if($requestSubtotal !== null) Subtotal: ${{ number_format($requestSubtotal, 2) }} Subtotal + IVA: ${{ number_format($requestSubtotalIva, 2) }} @endif Prov: {{ $summary['providers_total'] }} Esperadas: {{ $summary['expected_invoices'] }} Con factura: {{ $summary['providers_with_invoice'] }} Parciales: {{ $summary['providers_partial'] ?? 0 }} Parcial habilitado: {{ $providersPartialEnabled }} Pendientes: {{ $summary['providers_without_invoice'] }} Proveedores: {{ $summary['completion_percent'] }}% Monto: {{ $summary['amount_completion_percent'] }}%
@if($requestSubtotal !== null)
Subtotal de la solicitud (referencia principal): ${{ number_format($requestSubtotal, 2) }} Subtotal + IVA (16%): ${{ number_format($requestSubtotalIva, 2) }}
@endif
Estado de solicitud: {{ $summary['completion_percent'] }}% ({{ $summary['providers_with_invoice'] }}/{{ $summary['expected_invoices'] }})
Avance por monto: @if($summary['has_expected_amount'] && $summary['amount_expected'] !== null) {{ $summary['amount_completion_percent'] }}% ({{ number_format($summary['amount_invoiced'], 2) }}/{{ number_format($summary['amount_expected'], 2) }}) @else Sin monto esperado @endif
@if($summary['has_expected_amount'] && $summary['amount_pending'] !== null)
Saldo pendiente: {{ number_format($summary['amount_pending'], 2) }}
@endif
PENDIENTES: {{ count($summary['pending_provider_names']) ? implode(', ', $summary['pending_provider_names']) : 'Todos enviaron.' }}
@forelse($req->providers as $provider) @php $totals = $providerTotals[$provider->id] ?? null; $invoicePdf = $providerInvoicePdfLinks[$provider->id] ?? null; $invoicesCount = (int) ($totals?->invoices_count ?? 0); $invoiced = $totals?->total_invoiced ? (float) $totals->total_invoiced : 0.0; $providerItems = $provider->items ->sortBy('product_index') ->values(); $expectedBase = $provider->total_cost; if ($expectedBase === null) { $itemCostTotal = (float) $providerItems->sum(function ($it) { return (float) ($it->total_cost ?? 0); }); if ($itemCostTotal > 0) { $expectedBase = $itemCostTotal; } } if ($expectedBase === null) { $expectedBase = $provider->total_sale; } if ($expectedBase === null) { $itemSaleTotal = (float) $providerItems->sum(function ($it) { return (float) ($it->total_sale ?? 0); }); if ($itemSaleTotal > 0) { $expectedBase = $itemSaleTotal; } } $expected = $expectedBase !== null ? ((float) $expectedBase * 1.16) : null; $pending = $expected !== null ? max($expected - $invoiced, 0) : null; $providerItemsTotal = (int) ($providerItemsTotals[$provider->id] ?? 0); $providerMatchedCount = (int) ($providerMatchedItems[$provider->id] ?? 0); $pendingApprovalCount = (int) ($providerPendingApprovalCounts[$provider->id] ?? 0); $hasLegacyApprovedInvoices = $invoicesCount > 0 && $providerMatchedCount === 0 && $providerItemsTotal > 0; $partialEnabled = (bool) ($provider->allows_partial_invoicing ?? false); $providerRequestedQuantity = (float) $providerItems->sum(function ($it) { return \App\Support\ProviderPartialBilling::requestedQuantity($it); }); $providerUploadedQuantity = (float) $providerItems->sum(function ($it) use ($providerUploadedQuantities) { $requested = \App\Support\ProviderPartialBilling::requestedQuantity($it); $uploaded = (float) ($providerUploadedQuantities[(int) $it->id] ?? 0); return min($requested, max(0, $uploaded)); }); if ($partialEnabled) { $providerStatus = $providerUploadedQuantity <= 0.0001 ? 'none' : ($providerUploadedQuantity + 0.0001 < $providerRequestedQuantity ? 'partial' : 'complete'); } elseif ($providerItemsTotal > 0 && !$hasLegacyApprovedInvoices) { $providerStatus = $providerMatchedCount <= 0 ? 'none' : ($providerMatchedCount < $providerItemsTotal ? 'partial' : 'complete'); } else { $providerStatus = $invoicesCount > 0 ? 'complete' : 'none'; } @endphp @empty @endforelse
Proveedor Parcial Facturas Monto esperado Monto sin IVA Monto facturado Saldo pendiente Productos Estatus
{{ $provider->provider_name }}
@csrf @method('PATCH') Parcial
El proveedor puede subir por piezas y la vista previa solo tomará el remanente cargado.
{{ $invoicesCount }} {{ $expected !== null ? number_format($expected, 2) : '-' }} {{ $expectedBase !== null ? number_format((float) $expectedBase, 2) : '-' }} {{ number_format($invoiced, 2) }} {{ $pending !== null ? number_format($pending, 2) : '-' }} @if($providerItems->isEmpty()) Sin productos @else
Ver productos ({{ $providerItems->count() }}) @if($partialEnabled) @endif @foreach($providerItems as $item) @php $displayCode = $item->concept_code ?: \App\Support\ConceptCodeExtractor::extract( (string) ($item->description ?? ''), (string) ($item->product_name ?? '') ); $requestedQuantity = \App\Support\ProviderPartialBilling::requestedQuantity($item); $uploadedQuantity = min($requestedQuantity, max(0, (float) ($providerUploadedQuantities[(int) $item->id] ?? 0))); $pendingQuantity = max($requestedQuantity - $uploadedQuantity, 0); @endphp @if($partialEnabled) @endif @endforeach
# COD Producto Cant.Cargado Pendiente
{{ $item->product_index ?: '-' }} {{ $displayCode ?: '-' }} {{ $item->description ?: ($item->product_name ?: '-') }} {{ $item->quantity ?: '-' }}{{ number_format($uploadedQuantity, 2) }} {{ number_format($pendingQuantity, 2) }}
@endif
Parcial activado
@if($providerStatus === 'none') @if($pendingApprovalCount > 0) {{ $pendingApprovalCount === 1 ? 'Factura pendiente por aprobar' : 'Facturas pendientes por aprobar' }} ({{ $pendingApprovalCount }}) @else Sin factura @endif @elseif($providerStatus === 'partial') @if($partialEnabled) Parcial ({{ number_format($providerUploadedQuantity, 2) }}/{{ number_format(max($providerRequestedQuantity, 0), 2) }} piezas) @else Parcial ({{ $providerMatchedCount }}/{{ max(1, $providerItemsTotal) }}) @endif @if($invoicePdf) Ver factura @endif @elseif($invoicePdf) Con factura @else Con factura @endif
Sin proveedores asociados.
@empty
No hay solicitudes para mostrar.
@endforelse
@endsection @push('styles') @endpush @push('scripts') @endpush