@extends('layouts.app') @section('title', 'Solicitação ' . $solicitacao->numero_solicitacao . ' — Operador') @section('page_title', 'Solicitação ' . $solicitacao->numero_solicitacao) @section('content') @php $sc = $solicitacao->statusColor(); $colorMap = ['gray'=>'bg-gray-100 text-gray-700','blue'=>'bg-blue-100 text-blue-700','yellow'=>'bg-yellow-100 text-yellow-700','green'=>'bg-green-100 text-green-800','indigo'=>'bg-indigo-100 text-indigo-800','teal'=>'bg-teal-100 text-teal-800','red'=>'bg-red-100 text-red-700']; $badgeClass = $colorMap[$sc] ?? 'bg-gray-100 text-gray-700'; @endphp
{{-- Cabeçalho --}}

{{ $solicitacao->numero_solicitacao }}

{{ $solicitacao->statusLabel() }}
@if($solicitacao->assunto)

{{ $solicitacao->assunto }}

@endif
Cliente: {{ $solicitacao->cliente?->nome_fantasia ?? $solicitacao->cliente?->razao_social ?? '—' }} Solicitante: {{ $solicitacao->solicitante_nome }} {{ $solicitacao->solicitante_email ? '(' . $solicitacao->solicitante_email . ')' : '' }} Criada: {{ $solicitacao->created_at->format('d/m/Y H:i') }} @if($solicitacao->operador) Operador: {{ $solicitacao->operador->name }} @endif
{{-- Ações do operador --}}
@if((in_array($solicitacao->status, ['enviada','em_analise','aprovada']) || ($solicitacao->status === 'rascunho' && $solicitacao->operador_id)) && $ordens->isEmpty()) ✎ Editar @endif @if($solicitacao->status === 'rascunho' && $solicitacao->operador_id)
@csrf @method('PATCH')
@endif @if($solicitacao->status === 'enviada' && !$solicitacao->operador_id)
@csrf @method('PATCH')
@endif @if($solicitacao->status === 'em_analise')
@csrf @method('PATCH')
{{-- Rejeitar (modal inline) --}}

Rejeitar Solicitação

@csrf @method('PATCH')
@endif {{-- Gerar OSes: apenas uma vez, quando a solicitação estiver pronta --}} @if($solicitacao->status === 'aprovada' && $ordens->isEmpty())
@csrf
@elseif($ordens->isNotEmpty()) 📋 Ver {{ $ordens->count() }} OS @endif ← Voltar
@if($solicitacao->justificativa_rejeicao)
Motivo da rejeição: {{ $solicitacao->justificativa_rejeicao }}
@endif @if($solicitacao->pedido_cliente)
Pedido / OS do Cliente: {{ $solicitacao->pedido_cliente }}
@endif @if($solicitacao->observacoes)
Observações: {{ $solicitacao->observacoes }}
@endif
{{-- Regras do fluxo operacional --}}

Fluxo Solicitação → OS

A solicitação só entra em execução quando as OS forem efetivamente geradas.

@if($ordens->isNotEmpty()) {{ $ordens->count() }} OS gerada(s) @endif
@foreach([ ['enviada','1. Enviada'], ['em_analise','2. Em análise'], ['aprovada','3. Aprovada'], ['em_execucao','4. Em execução'], ['concluida','5. Concluída'] ] as [$statusFluxo,$labelFluxo]) @php $ordemFluxo = ['enviada'=>1,'em_analise'=>2,'aprovada'=>3,'em_execucao'=>4,'concluida'=>5]; $atualFluxo = $ordemFluxo[$solicitacao->status] ?? 0; $passoFluxo = $ordemFluxo[$statusFluxo]; @endphp
{{ $labelFluxo }}
@endforeach
@if($solicitacao->status === 'aprovada' && !empty($problemasGeracaoOs))

Antes de gerar as OS:

    @foreach($problemasGeracaoOs as $problema)
  • {{ $problema }}
  • @endforeach
@endif @if($ordens->isNotEmpty())

Após a geração, motorista, veículo, data/hora e status operacional devem ser ajustados diretamente nas respectivas OS. A regeneração automática é bloqueada para preservar rastreabilidade.

@endif
@php $itensComCoincidencia = collect($disponibilidadeItens)->filter(fn($ctx) => !empty($ctx['coincidencias_horario'] ?? [])); $totalCoincidencias = $itensComCoincidencia->sum(fn($ctx) => count($ctx['coincidencias_horario'] ?? [])); @endphp @if($totalCoincidencias > 0)

Conflito / coincidência de agenda identificado

Há {{ $totalCoincidencias }} ocorrência(s) no mesmo dia e horário em Solicitações, OS ou na base importada. Confira os detalhes abaixo antes de aprovar a alocação.

@endif {{-- Itens + alocação --}}

Itens de Transporte & Alocação

{{ $solicitacao->itens->count() }} item(ns)
@forelse($solicitacao->itens as $item) @php $isc = $item->statusColor(); $ibadge = $colorMap[$isc] ?? 'bg-gray-100 text-gray-700'; $dispItem = $disponibilidadeItens[$item->id] ?? [ 'motoristas_criticos'=>[], 'motoristas_atencao'=>[], 'veiculos_criticos'=>[], 'veiculos_atencao'=>[], 'carretas_criticas'=>[], 'carretas_atencao'=>[], 'coincidencias_horario'=>[], ]; @endphp {{-- Formulário de alocação inline --}} @csrf @method('PATCH') @if(!empty($dispItem['coincidencias_horario'])) @endif @empty @endforelse
# Origem Destino Sonda Data Hora Qtd Peso Cavalo Carroceria Motorista Status Salvar
{{ $loop->iteration }} {{ $item->origemLabel() }} {{ $item->destinoLabel() }} {{ $item->sondaLabel() }} {{ $item->data_coleta?->format('d/m/Y') }} {{ $item->hora_coleta ?? '—' }} {{ $item->quantidade }} {{ $item->carga_peso_ton !== null ? number_format((float)$item->carga_peso_ton, 3, ',', '.') . ' t' : '—' }}
@if(in_array($solicitacao->status, ['em_analise', 'aprovada'], true) && $ordens->isEmpty()) @else @endif

Mesmo dia e horário já constam em outra ocorrência

@foreach($dispItem['coincidencias_horario'] as $coincidencia)
{{ $coincidencia['numero'] }} {{ $coincidencia['fonte'] === 'importacao' ? 'Importado' : ($coincidencia['fonte'] === 'os' ? 'OS' : 'Solicitação') }} {{ $coincidencia['cliente'] }} {{ $coincidencia['origem'] }} → {{ $coincidencia['destino'] }} @if(!empty($coincidencia['motorista'])) Motorista: {{ $coincidencia['motorista'] }} @endif @if(!empty($coincidencia['veiculo'])) Cavalo: {{ $coincidencia['veiculo'] }} @endif Status: {{ $coincidencia['status'] }}
@if($coincidencia['fonte'] === 'os') Abrir OS @elseif($coincidencia['fonte'] === 'solicitacao') Abrir solicitação @elseif(auth()->user()?->hasRole('superadmin')) Auditar importado @else Registro importado @endif
@endforeach
Nenhum item.
Legenda: ⛔ conflito de recurso bloqueia a opção; ⚠ coincidência de agenda exige conferência. ⚠ Ocupado no dia: recurso permitido, mas já aparece em outra operação do mesmo dia.
@if(!empty($itensExpirados))

Há item(ns) com data/horário de coleta vencido

O sistema não gera sugestões nem permite nova alocação para esses itens. A solicitação deve ser corrigida antes de prosseguir.

    @foreach($solicitacao->itens as $item) @if(isset($itensExpirados[$item->id]))
  • {{ $item->origemLabel() }} → {{ $item->destinoLabel() }} · {{ $item->data_coleta?->format('d/m/Y') }} {{ $item->hora_coleta ? substr((string)$item->hora_coleta,0,5) : '' }} — {{ $itensExpirados[$item->id] }}
  • @endif @endforeach
@endif {{-- ── Sugestões do Sugestor ─────────────────────────────────── --}} @if(!empty($sugestoes) && collect($sugestoes)->flatten(1)->isNotEmpty())

Sugestões de Alocação

Histórico importado + sistema · disponibilidade atual · desempate por experiência, ranking, carga e rodízio
@foreach($solicitacao->itens as $item) @if(isset($sugestoes[$item->id]) && $sugestoes[$item->id]->isNotEmpty())
{{-- Cabeçalho do item --}}

Item {{ $loop->iteration }} — {{ $item->origemLabel() }} → {{ $item->destinoLabel() }} @if($item->data_coleta) · {{ $item->data_coleta->format('d/m/Y') }} @endif @if($item->hora_coleta) · {{ substr((string)$item->hora_coleta, 0, 5) }} @endif

@if(!$item->origem_id || !$item->destino_id)

⚠ Score de rota desconsiderado porque origem e/ou destino ainda não possuem vínculo cadastral.

@endif
@foreach($sugestoes[$item->id] as $i => $sug)
{{-- Posição + Score --}}
{{ $i + 1 }} Score: {{ number_format($sug->score * 100, 1) }}%
{{-- Motorista --}}

{{ $sug->motorista->nome }}

{{ $sug->motorista->rankLabel() }} @if($sug->motorista->empresa) · {{ $sug->motorista->empresa }} @endif

{{-- Veículo sugerido --}}
🚛 Cavalo: {{ $sug->veiculo->placa }} 🛻 Carroceria: {{ $sug->carreta->placa }} ({{ $sug->carreta->subtipo }} · {{ $sug->carreta->capacidade_ton !== null ? number_format((float)$sug->carreta->capacidade_ton, 1, ',', '.') . ' t' : 'cap. n/i' }}) Disponível no horário
{{-- Mini barra de scores --}}
@foreach([ ['Rota', $sug->score_rota], ['Cliente', $sug->score_cliente], ['Rank', $sug->score_rank], ['Disp.', $sug->score_disponibilidade], ['Prox.', $sug->score_proximidade], ['Exp.', $sug->score_experiencia], ] as [$label, $val])
{{ $label }}
{{ number_format($val * 100, 0) }}%
@endforeach
{{-- Evidências / explicação --}}

Por que foi sugerido

    @foreach($sug->motivos as $motivo)
  • {{ $motivo }}
  • @endforeach

Base histórica usada: {{ number_format($sug->historico_total, 0, ',', '.') }} operação(ões) · Importados: {{ number_format($sug->historico_importado, 0, ',', '.') }} · Sistema: {{ number_format($sug->historico_sistema, 0, ',', '.') }} @if(($sug->historico_aproximado ?? 0) > 0) · Alias/nome curto: {{ number_format($sug->historico_aproximado, 0, ',', '.') }} @endif · Rota: {{ $sug->viagens_rota }} · Cliente: {{ $sug->viagens_cliente }}

Desempate: {{ $sug->criterio_desempate }}
@if(!empty($sug->alertas))

Atenção operacional

@foreach($sug->alertas as $alerta)

• {{ $alerta }}

@endforeach
@endif {{-- Botão Usar --}} @if(in_array($solicitacao->status, ['em_analise', 'aprovada'], true) && $ordens->isEmpty())
@csrf @method('PATCH') @if($sug->veiculo) @endif @if($sug->carreta) @endif
@endif
@endforeach
@endif @endforeach
@endif
@endsection