@extends('layouts.enterprise') @section('title', 'Vista previa') @section('content')

Vista previa

Arma una vista previa desde artículos de solicitudes. Según la configuración del cliente, la compatibilidad puede validarse con reglas RC, con el RC cliente capturado por artículo o con recibos inbound ligados al RC solicitud.

@if(session('ok'))
{{ session('ok') }}
@endif @unless(($hasSatCatalog ?? false) && ($hasSatItemColumns ?? false))
La columna SAT se activara en cuanto corras las migraciones del catalogo SAT.
@endunless @if($errors->any())
@endif @php $pageRoute = request()->routeIs('accountant.*') ? route('accountant.incomes.generate_invoice') : route('admin.incomes.generate_invoice'); $storeRoute = request()->routeIs('accountant.*') ? route('accountant.incomes.generate_invoice.store') : route('admin.incomes.generate_invoice.store'); $printRouteName = request()->routeIs('accountant.*') ? 'accountant.incomes.generate_invoice.print' : 'admin.incomes.generate_invoice.print'; $issueRouteName = request()->routeIs('accountant.*') ? 'accountant.incomes.generate_invoice.issue' : 'admin.incomes.generate_invoice.issue'; $destroyRouteName = request()->routeIs('accountant.*') ? 'accountant.incomes.generate_invoice.destroy' : 'admin.incomes.generate_invoice.destroy'; $historyRoute = request()->routeIs('accountant.*') ? route('accountant.incomes.generated_invoices') : route('admin.incomes.generated_invoices'); $selectedClient = collect($clients)->firstWhere('id', $selectedClientId); $hasSatCatalogFeature = (bool) (($hasSatCatalog ?? false) && ($hasSatItemColumns ?? false)); $hasOldItemSelection = session()->hasOldInput('item_ids'); $oldSelectedItemIds = collect(old('item_ids', []))->map(fn ($value) => (int) $value)->values()->all(); $oldItemRcs = old('item_rcs', []); $oldSelectedSatCatalogItemIds = collect(old('sat_catalog_item_ids', [])) ->mapWithKeys(fn ($value, $key) => [(int) $key => (int) $value]) ->all(); $defaultAdditionalRequestIds = collect(old('additional_request_ids', ($selectedAdditionalRequestIds ?? collect())->all())) ->map(fn ($value) => (int) $value) ->values(); $defaultRequestOfficeIds = collect(old('request_office_ids', $selectedRequestOfficeIds ?? [])) ->mapWithKeys(fn ($value, $key) => [(int) $key => (int) $value]) ->filter(fn ($value, $key) => $key > 0 && (int) $value > 0) ->all(); $selectedRequestIdsSummary = collect([$selectedRequest?->id])->filter()->merge($defaultAdditionalRequestIds)->unique()->values(); $savedSelectedItemIds = collect($selectedItems ?? collect()) ->pluck('id') ->map(fn ($value) => (int) $value) ->filter(fn ($value) => $value > 0) ->values() ->all(); $savedItemRcs = collect($selectedItems ?? collect()) ->filter(fn ($item) => filled($item['item_rc'] ?? null)) ->mapWithKeys(fn ($item) => [(int) ($item['id'] ?? 0) => (string) ($item['item_rc'] ?? '')]) ->all(); $savedInboundMatches = collect($selectedItems ?? collect()) ->filter(fn ($item) => filled($item['matched_inbound'] ?? null)) ->mapWithKeys(fn ($item) => [(int) ($item['id'] ?? 0) => $item['matched_inbound']]) ->all(); $savedSatCatalogItemIds = collect($selectedItems ?? collect()) ->filter(fn ($item) => filled($item['sat_catalog_item_id'] ?? null)) ->mapWithKeys(fn ($item) => [(int) ($item['id'] ?? 0) => (int) ($item['sat_catalog_item_id'] ?? 0)]) ->all(); $defaultSatCatalogItemId = collect($satCatalogItems ?? collect())->firstWhere('is_default', true)?->id ?: collect($satCatalogItems ?? collect())->firstWhere('is_active', true)?->id; $draftIssueDate = $currentDraftInvoice?->issue_date ? $currentDraftInvoice->issue_date->format('Y-m-d') : now()->toDateString(); $draftTaxRate = ($currentDraftInvoice && (float) $currentDraftInvoice->subtotal > 0) ? round(((float) $currentDraftInvoice->tax / (float) $currentDraftInvoice->subtotal) * 100, 2) : 16; $selectedClientUsesInboundGrouping = $selectedClient ? \App\Support\ClientRequestGrouping::usesInboundReceiptEngine($selectedClient) : false; $selectedClientRulesSummary = $selectedClient ? \App\Support\ClientRequestGrouping::configurationSummary($selectedClient) : null; $itemColumnCount = $hasSatCatalogFeature ? 11 : 10; @endphp
Ver vistas previas finalizadas Los borradores siguen apareciendo aquí para continuar capturando información.
1
Agregar solicitudes Cliente, oficina y solicitudes una a una
2
Captura fiscal Clave SAT, RC y artículos incluidos
3
Guardar borrador Notas, fecha e IVA
4
Finalizar vista previa Generar e imprimir PDF
5
Crear factura Timbrado en Facturama
@if(!$selectedRequest)
Agregar solicitudes a la agrupación
Si seleccionas cliente, también se mostrarán solicitudes sin cliente asignado para amarrarlas aquí.
Selecciona cliente para filtrar oficinas disponibles.
Escribe parte del RC solicitud (Pipefy), del JN o del ID para filtrar la lista.
@endif @if($selectedRequest) @if($selectedRequestHasGeneratedInvoice ?? false)

Solicitud ya con vista previa

La solicitud #{{ $selectedRequest->id }} ({{ $selectedRequest->project_name ?: 'Sin PROJECT NAME' }}) ya cuenta con una vista previa guardada.

@if($selectedRequestLatestGeneratedInvoice)
Folio: {{ $selectedRequestLatestGeneratedInvoice->folio }} Fecha: {{ optional($selectedRequestLatestGeneratedInvoice->issue_date)->format('Y-m-d') ?: '-' }} Total: ${{ number_format((float) $selectedRequestLatestGeneratedInvoice->total, 2) }} @if($selectedRequestLatestGeneratedInvoice->facturama_cfdi_id) Factura creada @endif @if(($hasFacturamaPaymentComplementColumns ?? false) && $selectedRequestLatestGeneratedInvoice->facturama_payment_complement_cfdi_id) Complemento creado @endif @if($selectedRequestLatestGeneratedInvoice->id) Abrir vista previa @if(($hasFacturamaColumns ?? false) && !$selectedRequestLatestGeneratedInvoice->facturama_cfdi_id)
@csrf
@elseif(($hasFacturamaColumns ?? false) && $selectedRequestLatestGeneratedInvoice->facturama_cfdi_id) @if($selectedRequestLatestGeneratedInvoice->facturama_pdf_path) PDF Facturama @endif @if(($hasFacturamaPaymentComplementColumns ?? false) && !$selectedRequestLatestGeneratedInvoice->facturama_payment_complement_cfdi_id) Registrar pago @elseif(($hasFacturamaPaymentComplementColumns ?? false) && $selectedRequestLatestGeneratedInvoice->facturama_payment_complement_pdf_path) PDF complemento @endif @endif @else PDF no disponible @endif
@endif
@else

Vista previa en 5 pasos

Solicitud inicial #{{ $selectedRequest->id }} | {{ $selectedRequest->project_name ?: 'Sin PROJECT NAME' }} | JN {{ $selectedRequest->title ?: '-' }} | RC solicitud (Pipefy): {{ $selectedRequest->rc_list ?: '-' }}

@csrf @if($currentDraftInvoice) @endif @if($currentDraftInvoice)
Borrador activo cargado. Si vas a sumar o quitar solicitudes, hazlo primero aquí arriba; después revisa abajo RC cliente, SAT y los conceptos finales.
@endif

Paso 1. Agrega solicitudes una a una

Selecciona cliente, oficina y luego agrega cada solicitud que deba entrar en la vista previa. Este paso se repite tantas veces como solicitudes necesites incluir.

@if($groupingContext) {{ $groupingContext['label'] }} @endif
La vista previa agrupada solo puede mezclar solicitudes del mismo cliente.
Selecciona una oficina para la solicitud que vas a agregar.
Agregar solicitud
@if($selectedClient)
@if($selectedClientUsesInboundGrouping) Este cliente agrupa con recibos inbound. El sistema revisa el RC solicitud contra el email recibido y solo permite juntar solicitudes del mismo tipo detectado y la misma moneda. @elseif($selectedClient->validation_rc) La agrupación se valida con el RC cliente que capturas por artículo. El RC solicitud (Pipefy) solo se muestra como referencia y no entra en la lógica final. @else Este cliente agrupa usando el RC solicitud (Pipefy) de cada solicitud. @endif @if($selectedClientRulesSummary && !in_array($selectedClientRulesSummary, ['Sin reglas', 'Sin agrupación'], true)) Configuración activa: {{ $selectedClientRulesSummary }}. @endif
@endif @if($groupingMessage)
{{ $groupingMessage }}
@endif @if($selectedClientUsesInboundGrouping) Solo se listan solicitudes libres del mismo cliente cuyo recibo inbound cae en el mismo tipo y moneda que la solicitud inicial. @elseif($selectedClient?->validation_rc) Solo se listan solicitudes libres del mismo cliente. La compatibilidad final se valida al guardar usando el RC cliente capturado por artículo. @else Solo se listan solicitudes libres, del mismo cliente y del mismo tipo de RC solicitud (Pipefy). @endif
Cada solicitud incluida debe tener su propia oficina. Esa oficina se usará después para formar el concepto final de la vista previa.

Paso 2. Captura código fiscal, RC y artículos

Aquí seleccionas la clave SAT, capturas el RC cliente y activas los artículos que sí van a entrar en la vista previa final. Si existe match inbound por descripción, oficina y monto, el sistema lo amarra automáticamente.

Solicitudes incluidas: {{ max(1, $selectedRequestIdsSummary->count()) }} La solicitud inicial siempre debe ir incluida. Los artículos con remanente parcial mostrarán un badge de factura parcial. @if($hasSatCatalogFeature && $defaultSatCatalogItemId) SAT predeterminado: {{ collect($satCatalogItems)->firstWhere('id', $defaultSatCatalogItemId)?->display_label }} @endif Subtotal seleccionado: $0.00
@if($hasSatCatalogFeature) @endif
Sel. Solicitud # COD Descripción limpia Cant. InboundClave SATUnit sale Total sale
Cargando artículos...

Paso 3. Guarda la información

Este paso genera el borrador. Úsalo cuando todavía no vas a emitir la vista previa final pero quieres dejar toda la captura guardada.

El borrador conservará cliente, solicitudes, oficina por solicitud, RC cliente y SAT por artículo. Una solicitud solo puede existir en una vista previa. Los movimientos de todas las solicitudes seleccionadas se asignarán al cliente elegido.

Paso 4. Finaliza la vista previa e imprime

Cuando el borrador ya tenga todas las solicitudes correctas y sus artículos completos, genera el PDF final de la vista previa. El paso 5 se hace desde esa misma vista.

@if(!$currentDraftInvoice) Debes guardar primero el borrador del paso 3. @endif
@if($currentDraftInvoice) @endif
@endif @endif @if(($hasStatusColumn ?? false) && isset($draftInvoices) && $draftInvoices->isNotEmpty())

Borradores activos

Estos borradores ya tienen guardada la información capturada por artículo. Puedes retomarlos para revisar la selección de solicitudes, ajustar RC/SAT y solo al final imprimir la vista previa.

@foreach($draftInvoices as $draftInvoice) @php $draftRequests = ($hasGroupingPivot ?? false) ? ($draftInvoice->pipefyRequests ?? collect()) : collect(); if ($draftRequests->isEmpty() && $draftInvoice->pipefyRequest) { $draftRequests = collect([$draftInvoice->pipefyRequest]); } @endphp @endforeach
Borrador Actualizado Cliente Solicitudes Notas internas Subtotal Total Acción
Borrador #{{ $draftInvoice->id }} {{ optional($draftInvoice->updated_at)->format('Y-m-d H:i') ?: '-' }} {{ $draftInvoice->client?->name ?: '-' }}
{{ $draftRequests->count() }} solicitud(es)
@foreach($draftRequests->take(3) as $draftRequest)
#{{ $draftRequest->id }} | {{ $draftRequest->title ?: '-' }} | RC solicitud (Pipefy): {{ $draftRequest->rc_list ?: '-' }}
@endforeach @if($draftRequests->count() > 3)
+{{ $draftRequests->count() - 3 }} más
@endif
@if(filled($draftInvoice->notes))
{{ $draftInvoice->notes }}
@else Sin notas @endif
${{ number_format((float) $draftInvoice->subtotal, 2) }} ${{ number_format((float) $draftInvoice->total, 2) }}
Continuar borrador
@csrf @method('DELETE')
@endif
@endsection @push('styles') @endpush @push('scripts') @endpush